1 | /* |
2 | |
3 | Derby - Class org.apache.derby.iapi.sql.dictionary.SPSDescriptor |
4 | |
5 | Copyright 1998, 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.iapi.sql.dictionary; |
22 | |
23 | import org.apache.derby.iapi.services.io.StoredFormatIds; |
24 | |
25 | import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; |
26 | import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory; |
27 | import org.apache.derby.iapi.sql.conn.StatementContext; |
28 | |
29 | import org.apache.derby.iapi.store.access.TransactionController; |
30 | |
31 | import org.apache.derby.iapi.sql.dictionary.DataDictionary; |
32 | import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; |
33 | import org.apache.derby.iapi.sql.dictionary.TableDescriptor; |
34 | |
35 | import org.apache.derby.iapi.sql.execute.ConstantAction; |
36 | import org.apache.derby.iapi.sql.execute.ExecutionContext; |
37 | |
38 | import org.apache.derby.iapi.sql.compile.CompilerContext; |
39 | |
40 | import org.apache.derby.iapi.types.DataTypeDescriptor; |
41 | import org.apache.derby.iapi.sql.Statement; |
42 | import org.apache.derby.iapi.sql.StorablePreparedStatement; |
43 | |
44 | import org.apache.derby.iapi.error.StandardException; |
45 | import org.apache.derby.iapi.reference.SQLState; |
46 | |
47 | import org.apache.derby.iapi.services.context.ContextManager; |
48 | import org.apache.derby.iapi.services.loader.ClassFactory; |
49 | import org.apache.derby.iapi.services.context.ContextService; |
50 | import org.apache.derby.iapi.services.monitor.Monitor; |
51 | |
52 | import org.apache.derby.iapi.sql.depend.DependencyManager; |
53 | import org.apache.derby.iapi.sql.depend.Dependent; |
54 | import org.apache.derby.iapi.sql.depend.Dependency; |
55 | import org.apache.derby.iapi.sql.depend.Provider; |
56 | import org.apache.derby.iapi.sql.depend.ProviderInfo; |
57 | |
58 | import org.apache.derby.iapi.types.DataValueFactory; |
59 | |
60 | import org.apache.derby.iapi.sql.execute.ExecPreparedStatement; |
61 | |
62 | import org.apache.derby.iapi.services.sanity.SanityManager; |
63 | import org.apache.derby.iapi.services.loader.GeneratedClass; |
64 | |
65 | import org.apache.derby.catalog.UUID; |
66 | import org.apache.derby.catalog.Dependable; |
67 | import org.apache.derby.catalog.DependableFinder; |
68 | import org.apache.derby.iapi.services.uuid.UUIDFactory; |
69 | |
70 | import java.util.Enumeration; |
71 | import java.util.Vector; |
72 | import java.sql.Timestamp; |
73 | |
74 | /** |
75 | * A SPSDescriptor describes a Stored Prepared Statement. |
76 | * It correlates to a row in SYS.SYSSTATEMENTS. |
77 | * |
78 | * <B>SYNCHRONIZATION</B>: Stored prepared statements |
79 | * may be cached. Thus they may be shared by multiple |
80 | * threads. It is very hard for two threads to try |
81 | * to muck with an sps simultaeously because all ddl |
82 | * (including sps recompilation) clears out the sps |
83 | * cache and invalidates whatever statement held a |
84 | * cached sps. But it is possible for two statements |
85 | * to do a prepare execute statment <x> at the exact |
86 | * same time, so both try to do an sps.prepare() at the |
87 | * same time during code generation, so we synchronize |
88 | * most everything except getters on immutable objects |
89 | * just to be on the safe side. |
90 | * |
91 | * |
92 | * @author jamie |
93 | */ |
94 | public class SPSDescriptor extends TupleDescriptor |
95 | implements UniqueSQLObjectDescriptor, Dependent, Provider |
96 | { |
97 | /** |
98 | * Statement types. |
99 | * <UL> |
100 | * <LI> SPS_TYPE_TRIGGER - trigger (<B>NOT IMPLEMENTED</B>) </LI> |
101 | * <LI> SPS_TYPE_EXPLAIN - explain (<B>NOT IMPLEMENTED</B>) </LI> |
102 | * <LI> SPS_TYPE_REGULAR - catchall</LI> |
103 | * </UL> |
104 | */ |
105 | public static final char SPS_TYPE_TRIGGER = 'T'; |
106 | public static final char SPS_TYPE_REGULAR = 'S'; |
107 | public static final char SPS_TYPE_EXPLAIN = 'X'; |
108 | |
109 | /** |
110 | interface to this class is: |
111 | <ol> |
112 | <li>public void prepare() throws StandardException; |
113 | <li>public void prepareAndRelease(LanguageConnectionContext lcc) |
114 | throws StandardException; |
115 | <li>public void prepareAndRelease(...); |
116 | <li>public String getQualifiedName(); |
117 | <li>public char getType(); |
118 | <li>public String getTypeAsString(); |
119 | <li>public boolean isValid(); |
120 | <li>public boolean initiallyCompilable(); |
121 | <li>public java.sql.Timestamp getCompileTime(); |
122 | <li>public void setCompileTime(); |
123 | <li>public String getText(); |
124 | <li>public String getUsingText(); |
125 | <li>public void setUsingText(String usingText); |
126 | <li>public void setUUID(UUID uuid); |
127 | <li>public DataTypeDescriptor[] getParams() throws StandardException; |
128 | <li>public void setParams(DataTypeDescriptor[] params); |
129 | <li>Object[] getParameterDefaults() throws StandardException; |
130 | <li>void setParameterDefaults(Object[] values); |
131 | <li>public UUID getCompSchemaId(); |
132 | <li>public ExecPreparedStatement getPreparedStatement() |
133 | throws StandardException; |
134 | <li>public ExecPreparedStatement getPreparedStatement(boolean recompIfInvalid) |
135 | throws StandardException; |
136 | <li>public void revalidate(LanguageConnectionContext lcc) |
137 | throws StandardException; |
138 | </ol> |
139 | */ |
140 | |
141 | private static final int RECOMPILE = 1; |
142 | private static final int INVALIDATE = 0; |
143 | |
144 | |
145 | // Class contents |
146 | private SchemaDescriptor sd; |
147 | private String name; |
148 | private UUID uuid; |
149 | private UUID compSchemaId; |
150 | private char type; |
151 | private boolean valid; |
152 | private String text; |
153 | private String usingText; |
154 | private ExecPreparedStatement preparedStatement; |
155 | private DataTypeDescriptor params[]; |
156 | private Timestamp compileTime; |
157 | private Object paramDefaults[]; |
158 | private boolean initiallyCompilable; |
159 | private boolean lookedUpParams; |
160 | |
161 | private UUIDFactory uuidFactory; |
162 | |
163 | |
164 | // constructors |
165 | /** |
166 | * Constructor for a SPS Descriptor |
167 | * |
168 | * @param dataDictionary The data dictionary that this descriptor lives in |
169 | * @param name the SPS name |
170 | * @param uuid the UUID |
171 | * @param suuid the schema UUID |
172 | * @param compSchemaUUID the schema UUID at compilation time |
173 | * @param type type |
174 | * @param valid is the sps valid |
175 | * @param text the text for this statement |
176 | * @param usingText the text for the USING clause supplied to |
177 | * CREATE or ALTER STATEMENT |
178 | * @param paramDefaults default values for the parameters (if |
179 | * any) in this statement. Generated by a USING |
180 | * clause, for use by the optimizer. |
181 | * @param initiallyCompilable is the statement initially compilable? |
182 | * |
183 | * @exception StandardException on error |
184 | */ |
185 | public SPSDescriptor |
186 | (DataDictionary dataDictionary, |
187 | String name, |
188 | UUID uuid, |
189 | UUID suuid, |
190 | UUID compSchemaUUID, |
191 | char type, |
192 | boolean valid, |
193 | String text, |
194 | String usingText, |
195 | Object[] paramDefaults, |
196 | boolean initiallyCompilable ) throws StandardException |
197 | { |
198 | this( dataDictionary, name, uuid, suuid, compSchemaUUID, type, valid, text, usingText, null, null, initiallyCompilable ); |
199 | this.paramDefaults = paramDefaults; |
200 | } |
201 | |
202 | /** |
203 | * Constructor for a SPS Descriptor. Used when |
204 | * constructing an SPS descriptor from a row |
205 | * in SYSSTATEMENTS. |
206 | * |
207 | * @param dataDictionary The data dictionary that this descriptor lives in |
208 | * @param name the SPS name |
209 | * @param uuid the UUID |
210 | * @param suuid the schema UUID |
211 | * @param compSchemaUUID the schema UUID at compilation time |
212 | * @param type type |
213 | * @param valid is the sps valid |
214 | * @param text the text for this statement |
215 | * @param usingText the text for the USING clause supplied to |
216 | * CREATE or ALTER STATEMENT |
217 | * @param compileTime the time this was compiled |
218 | * @param preparedStatement the PreparedStatement |
219 | * @param initiallyCompilable is the statement initially compilable? |
220 | * |
221 | * @exception StandardException on error |
222 | */ |
223 | public SPSDescriptor |
224 | (DataDictionary dataDictionary, |
225 | String name, |
226 | UUID uuid, |
227 | UUID suuid, |
228 | UUID compSchemaUUID, |
229 | char type, |
230 | boolean valid, |
231 | String text, |
232 | String usingText, |
233 | Timestamp compileTime, |
234 | ExecPreparedStatement preparedStatement, |
235 | boolean initiallyCompilable ) throws StandardException |
236 | { |
237 | super( dataDictionary ); |
238 | |
239 | this.name = name; |
240 | this.uuid = uuid; |
241 | this.type = type; |
242 | this.text = text; |
243 | this.usingText = usingText; |
244 | this.valid = valid; |
245 | this.compileTime = compileTime; |
246 | this.sd = dataDictionary.getSchemaDescriptor(suuid, null); |
247 | this.preparedStatement = preparedStatement; |
248 | this.compSchemaId = compSchemaUUID; |
249 | this.initiallyCompilable = initiallyCompilable; |
250 | } |
251 | |
252 | /** |
253 | * FOR TRIGGERS ONLY |
254 | * <p> |
255 | * Generate the class for this SPS and immediately |
256 | * release it. This is useful for cases where we |
257 | * don't want to immediately execute the statement |
258 | * corresponding to this sps (e.g. CREATE STATEMENT). |
259 | * <p> |
260 | * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS |
261 | * with the prepared statement dependency info. |
262 | * |
263 | * @param lcc the language connection context |
264 | * @param triggerTable the table descriptor to bind against. Had |
265 | * better be null if this isn't a trigger sps. |
266 | * |
267 | * @exception StandardException on error |
268 | */ |
269 | public final synchronized void prepareAndRelease |
270 | ( |
271 | LanguageConnectionContext lcc, |
272 | TableDescriptor triggerTable |
273 | ) throws StandardException |
274 | { |
275 | if (SanityManager.DEBUG) |
276 | { |
277 | if (triggerTable != null) |
278 | { |
279 | SanityManager.ASSERT(type == SPS_TYPE_TRIGGER, "only expect a table descriptor when we have a trigger"); |
280 | } |
281 | } |
282 | |
283 | compileStatement(lcc, triggerTable); |
284 | |
285 | preparedStatement.makeInvalid(DependencyManager.PREPARED_STATEMENT_RELEASE, lcc); |
286 | } |
287 | |
288 | /** |
289 | * Generate the class for this SPS and immediately |
290 | * release it. This is useful for cases where we |
291 | * don't want to immediately execute the statement |
292 | * corresponding to this sps (e.g. CREATE STATEMENT). |
293 | * <p> |
294 | * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS |
295 | * with the prepared statement dependency info. |
296 | * |
297 | * @param lcc the language connection context |
298 | * |
299 | * @exception StandardException on error |
300 | */ |
301 | public final synchronized void prepareAndRelease(LanguageConnectionContext lcc) throws StandardException |
302 | { |
303 | prepareAndRelease(lcc, (TableDescriptor)null); |
304 | } |
305 | |
306 | private void compileStatement |
307 | ( |
308 | LanguageConnectionContext lcc, |
309 | TableDescriptor triggerTable |
310 | ) |
311 | throws StandardException |
312 | { |
313 | ContextManager cm = lcc.getContextManager(); |
314 | DependencyManager dm; |
315 | ProviderInfo[] providerInfo; |
316 | |
317 | LanguageConnectionFactory lcf = lcc.getLanguageConnectionFactory(); |
318 | |
319 | DataDictionary dd = getDataDictionary(); |
320 | |
321 | |
322 | /* |
323 | ** If we are a trigger, then we have to go ahead |
324 | ** and locate the trigger's table descriptor and |
325 | ** push it on the lcc. This is expensive, but |
326 | ** pretty atypical since trigger actions aren't |
327 | ** likely to be invalidated too often. Also, when |
328 | ** possible, we already have the triggerTable. |
329 | */ |
330 | if (type == SPS_TYPE_TRIGGER && triggerTable == null) |
331 | { |
332 | String uuidStr = name.substring(49); |
333 | triggerTable = dd.getTableDescriptor(recreateUUID(uuidStr)); |
334 | if (SanityManager.DEBUG) |
335 | { |
336 | if (triggerTable == null) |
337 | { |
338 | SanityManager.THROWASSERT("couldn't find trigger table for trigger sps "+name); |
339 | } |
340 | } |
341 | } |
342 | |
343 | if (triggerTable != null) |
344 | { |
345 | lcc.pushTriggerTable(triggerTable); |
346 | } |
347 | |
348 | // stored statements always stored as unicode. |
349 | Statement stmt = lcf.getStatement(dd.getSchemaDescriptor(compSchemaId, null), text, true); |
350 | |
351 | try |
352 | { |
353 | preparedStatement = (ExecPreparedStatement) stmt.prepareStorable( |
354 | lcc, |
355 | preparedStatement, |
356 | getParameterDefaults(), |
357 | getSchemaDescriptor(), |
358 | type == SPS_TYPE_TRIGGER); |
359 | } |
360 | finally |
361 | { |
362 | if (triggerTable != null) |
363 | { |
364 | lcc.popTriggerTable(triggerTable); |
365 | } |
366 | } |
367 | |
368 | //If this references a SESSION schema table (temporary or permanent), then throw an exception |
369 | //This is if EXECUTE STATEMENT executing a statement that was created with NOCOMPILE. Because |
370 | //of NOCOMPILE, we could not catch SESSION schema table reference by the statement at |
371 | //CREATE STATEMENT time. And hence need to catch such statements at EXECUTE STATEMENT time |
372 | //when the query is getting compiled. |
373 | if (preparedStatement.referencesSessionSchema()) |
374 | throw StandardException.newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES); |
375 | |
376 | setCompileTime(); |
377 | setParams(preparedStatement.getParameterTypes()); |
378 | |
379 | if (!((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) dd).readOnlyUpgrade) { |
380 | |
381 | /* |
382 | ** Indicate that we are going to write the data |
383 | ** dictionary. We have probably already done this |
384 | ** but it is ok to call startWriting more than once. |
385 | */ |
386 | dd.startWriting(lcc); |
387 | |
388 | dm = dd.getDependencyManager(); |
389 | /* |
390 | ** Clear out all the dependencies that exist |
391 | ** before we recreate them so we don't grow |
392 | ** SYS.SYSDEPENDS forever. |
393 | */ |
394 | dm.clearDependencies(lcc, this); |
395 | |
396 | /* |
397 | ** Copy over all the dependencies to me |
398 | */ |
399 | dm.copyDependencies(preparedStatement, // from |
400 | this, // to |
401 | false, // persistent only |
402 | cm); |
403 | } |
404 | |
405 | // mark it as valid |
406 | valid = true; |
407 | } |
408 | |
409 | /** |
410 | * Gets the name of the sps. |
411 | * |
412 | * @return A String containing the name of the statement. |
413 | */ |
414 | public final String getName() |
415 | { |
416 | return name; |
417 | } |
418 | |
419 | /** |
420 | * Gets the full, qualified name of the statement. |
421 | * |
422 | * @return A String containing the name of the statement. |
423 | */ |
424 | public final String getQualifiedName() |
425 | { |
426 | return sd.getSchemaName() + "." + name; |
427 | } |
428 | |
429 | /** |
430 | * Gets the SchemaDescriptor for this SPS Descriptor. |
431 | * |
432 | * @return SchemaDescriptor The SchemaDescriptor. |
433 | */ |
434 | public final SchemaDescriptor getSchemaDescriptor() |
435 | { |
436 | return sd; |
437 | } |
438 | |
439 | /** |
440 | * Gets an identifier telling what type of table this is. |
441 | * Types match final ints in this interface. Currently |
442 | * returns SPS_TYPE_REGULAR or SPS_TYPE_TRIGGER. |
443 | * |
444 | * @return An identifier telling what type of statement |
445 | * we are. |
446 | */ |
447 | public final char getType() |
448 | { |
449 | return type; |
450 | } |
451 | |
452 | /** |
453 | * Simple little helper function to convert your type |
454 | * to a string, which is easier to use. |
455 | * |
456 | * @return type as a string |
457 | */ |
458 | public final String getTypeAsString() |
459 | { |
460 | char[] charArray = new char[1]; |
461 | charArray[0] = type; |
462 | return new String(charArray); |
463 | } |
464 | |
465 | /** |
466 | * Is the statement initially compilable? |
467 | * |
468 | * @return false if statement was created with the NOCOMPILE flag |
469 | * true otherwise |
470 | */ |
471 | public boolean initiallyCompilable() { return initiallyCompilable; } |
472 | |
473 | /** |
474 | * Validate the type. <B>NOTE</B>: Only SPS_TYPE_REGULAR |
475 | * and SPS_TYPE_TRIGGER are currently valid. |
476 | * |
477 | * @param type the type |
478 | * |
479 | * @return true/false |
480 | */ |
481 | public final static boolean validType(char type) |
482 | { |
483 | return (type == SPSDescriptor.SPS_TYPE_REGULAR) || |
484 | (type == SPSDescriptor.SPS_TYPE_TRIGGER); |
485 | } |
486 | |
487 | /** |
488 | * The time this prepared statement was compiled |
489 | * |
490 | * @return the time this class was last compiled |
491 | */ |
492 | public final synchronized Timestamp getCompileTime() |
493 | { |
494 | return compileTime; |
495 | } |
496 | |
497 | /** |
498 | * Set the compile time to now |
499 | * |
500 | */ |
501 | public final synchronized void setCompileTime() |
502 | { |
503 | compileTime = new Timestamp(System.currentTimeMillis()); |
504 | } |
505 | |
506 | /** |
507 | * Get the text used to create this statement. |
508 | * Returns original text in a cleartext string. |
509 | * |
510 | * @return The text |
511 | */ |
512 | public final String getText() |
513 | { |
514 | return text; |
515 | } |
516 | |
517 | /** |
518 | * Get the text of the USING clause used on CREATE |
519 | * or ALTER statement. |
520 | * |
521 | * @return The text |
522 | */ |
523 | public final synchronized String getUsingText() |
524 | { |
525 | return usingText; |
526 | } |
527 | |
528 | /** |
529 | * Set the text of the USING clause. Used by |
530 | * ALTER statement. |
531 | * |
532 | * @param usingText the new value for the USING text |
533 | */ |
534 | public final synchronized void setUsingText(String usingText) |
535 | { |
536 | this.usingText = usingText; |
537 | } |
538 | |
539 | /** |
540 | * Sets the UUID of the SPS. |
541 | * |
542 | * @param uuid The UUID of the SPS to be set in the descriptor |
543 | */ |
544 | public final synchronized void setUUID(UUID uuid) |
545 | { |
546 | this.uuid = uuid; |
547 | } |
548 | |
549 | /** |
550 | * Gets the UUID of the SPS. |
551 | * |
552 | * @return the uuid |
553 | */ |
554 | public final UUID getUUID() |
555 | { |
556 | return uuid; |
557 | } |
558 | |
559 | /** |
560 | * Get the array of date type descriptors for |
561 | * this statement. Currently, we do a lookup |
562 | * if we don't already have the parameters saved. |
563 | * When SPSes are cached, the parameters should |
564 | * be set up when the sps is constructed. |
565 | * |
566 | * @return the array of data type descriptors |
567 | * |
568 | * @exception StandardException on error |
569 | */ |
570 | public final synchronized DataTypeDescriptor[] getParams() |
571 | throws StandardException |
572 | { |
573 | if (params == null && !lookedUpParams) |
574 | { |
575 | Vector v = new Vector(); |
576 | params = getDataDictionary().getSPSParams(this, v); |
577 | paramDefaults = new Object[v.size()]; |
578 | Enumeration iterator = v.elements(); |
579 | for (int i = 0; iterator.hasMoreElements(); i++) |
580 | { |
581 | paramDefaults[i] = iterator.nextElement(); |
582 | } |
583 | |
584 | lookedUpParams = true; |
585 | } |
586 | |
587 | return params; |
588 | } |
589 | |
590 | /** |
591 | * Set the list of parameters for this statement |
592 | * |
593 | * @param params the parameter list |
594 | */ |
595 | public final synchronized void setParams(DataTypeDescriptor params[]) |
596 | { |
597 | this.params = params; |
598 | } |
599 | |
600 | /** |
601 | * Get the default parameter values for this |
602 | * statement. Default parameter values are |
603 | * supplied by a USING clause on either a |
604 | * CREATE or ALTER STATEMENT statement. |
605 | * |
606 | * @return the default parameter values |
607 | * |
608 | * @exception StandardException on error |
609 | */ |
610 | public final synchronized Object[] getParameterDefaults() |
611 | throws StandardException |
612 | { |
613 | if (paramDefaults == null) |
614 | getParams(); |
615 | |
616 | return paramDefaults; |
617 | } |
618 | |
619 | /** |
620 | * Set the parameter defaults for this statement. |
621 | * |
622 | * @param values the parameter defaults |
623 | */ |
624 | public final synchronized void setParameterDefaults(Object[] values) |
625 | { |
626 | this.paramDefaults = values; |
627 | } |
628 | |
629 | /** |
630 | * Get the constant action for this statement |
631 | * |
632 | * @return the constant action |
633 | */ |
634 | //public final synchronized ConstantAction getConstantAction() |
635 | //{ |
636 | // return preparedStatement.getConstantAction(); |
637 | //} |
638 | |
639 | /** |
640 | * Get the preparedStatement for this statement. |
641 | * If stmt is invalid or hasn't been compiled yet, |
642 | * it will be recompiled. |
643 | * |
644 | * @return the preparedStatement |
645 | * |
646 | * @exception StandardException on error |
647 | */ |
648 | public final ExecPreparedStatement getPreparedStatement() |
649 | throws StandardException |
650 | { |
651 | return getPreparedStatement(true); |
652 | } |
653 | |
654 | /** |
655 | * Get the preparedStatement for this statement. |
656 | * Expects the prepared statement to have already |
657 | * been added to SYS.SYSSTATEMENTS. |
658 | * <p> |
659 | * Side Effects: will update SYS.SYSSTATEMENTS with |
660 | * the new plan if it needs to be recompiled. |
661 | * |
662 | * @param recompIfInvalid if false, never recompile even |
663 | * if statement is invalid |
664 | * |
665 | * @return the preparedStatement |
666 | * |
667 | * @exception StandardException on error |
668 | */ |
669 | public final synchronized ExecPreparedStatement getPreparedStatement(boolean recompIfInvalid) |
670 | throws StandardException |
671 | { |
672 | //System.out.println("preparedStatement = " + preparedStatement); |
673 | /* |
674 | ** Recompile if we are invalid, we don't have |
675 | ** a prepared statement, or the statements activation |
676 | ** has been cleared and cannot be reconstituted. |
677 | */ |
678 | if (recompIfInvalid && |
679 | (!valid || |
680 | (preparedStatement == null))) |
681 | { |
682 | ContextManager cm = ContextService.getFactory().getCurrentContextManager(); |
683 | |
684 | /* |
685 | ** Find the language connection context. Get |
686 | ** it each time in case a connection is dropped. |
687 | */ |
688 | LanguageConnectionContext lcc = (LanguageConnectionContext) |
689 | cm.getContext(LanguageConnectionContext.CONTEXT_ID); |
690 | prepareAndRelease(lcc); |
691 | |
692 | |
693 | if (!((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) (lcc.getDataDictionary())).readOnlyUpgrade) { |
694 | |
695 | //bug 4821 - First try compiling on a nested transaction so we can release |
696 | //the locks after the compilation. But if we get lock time out on the |
697 | //nested transaction, then go ahead and do the compilation on the user |
698 | //transaction. When doing the compilation on user transaction, the locks |
699 | //acquired for recompilation will be released at the end of the user transaction. |
700 | TransactionController nestedTC; |
701 | try |
702 | { |
703 | nestedTC = lcc.getTransactionCompile().startNestedUserTransaction(false); |
704 | } |
705 | catch (StandardException se) |
706 | { |
707 | // If I cannot start a Nested User Transaction use the parent |
708 | // transaction to do all the work. |
709 | nestedTC = null; |
710 | } |
711 | |
712 | try |
713 | { |
714 | updateSYSSTATEMENTS(lcc, RECOMPILE, nestedTC); |
715 | } |
716 | catch (StandardException se) |
717 | { |
718 | if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT)) |
719 | { |
720 | if (nestedTC != null) |
721 | { |
722 | nestedTC.commit(); |
723 | nestedTC.destroy(); |
724 | nestedTC = null; |
725 | } |
726 | // if we couldn't do this with a nested xaction, retry with |
727 | // parent-- we need to wait this time! |
728 | updateSYSSTATEMENTS(lcc, RECOMPILE, null); |
729 | } |
730 | else throw se; |
731 | } |
732 | finally |
733 | { |
734 | // no matter what, commit the nested transaction; if something |
735 | // bad happened in the child xaction lets not abort the parent |
736 | // here. |
737 | if (nestedTC != null) |
738 | { |
739 | nestedTC.commit(); |
740 | nestedTC.destroy(); |
741 | } |
742 | } |
743 | } |
744 | } |
745 | |
746 | return preparedStatement; |
747 | } |
748 | |
749 | /** |
750 | * Get the compilation type schema id when this view |
751 | * was first bound. |
752 | * |
753 | * @return the schema UUID |
754 | */ |
755 | public final UUID getCompSchemaId() |
756 | { |
757 | return compSchemaId; |
758 | } |
759 | |
760 | /** |
761 | * Prints the contents of the TableDescriptor |
762 | * |
763 | * @return The contents as a String |
764 | */ |
765 | public final String toString() |
766 | { |
767 | if (SanityManager.DEBUG) |
768 | { |
769 | return "SPSDescriptor:\n"+ |
770 | "\tname: "+sd.getSchemaName()+"."+name+"\n"+ |
771 | "\tuuid: "+uuid+"\n"+ |
772 | "\ttext: "+text+"\n"+ |
773 | "\tvalid: "+((valid) ? "TRUE" : "FALSE")+"\n" + |
774 | "\tpreparedStatement: "+preparedStatement+"\n"; |
775 | } |
776 | else |
777 | { |
778 | return ""; |
779 | } |
780 | } |
781 | |
782 | ////////////////////////////////////////////////////// |
783 | // |
784 | // PROVIDER INTERFACE |
785 | // |
786 | ////////////////////////////////////////////////////// |
787 | |
788 | /** |
789 | * Return the stored form of this provider |
790 | * |
791 | * @see Dependable#getDependableFinder |
792 | */ |
793 | public final DependableFinder getDependableFinder() |
794 | { |
795 | return getDependableFinder(StoredFormatIds.SPS_DESCRIPTOR_FINDER_V01_ID); |
796 | } |
797 | |
798 | /** |
799 | * Return the name of this Provider. (Useful for errors.) |
800 | * |
801 | * @return String The name of this provider. |
802 | */ |
803 | public final String getObjectName() |
804 | { |
805 | return name; |
806 | } |
807 | |
808 | /** |
809 | * Get the provider's UUID |
810 | * |
811 | * @return String The provider's UUID |
812 | */ |
813 | public final UUID getObjectID() |
814 | { |
815 | return uuid; |
816 | } |
817 | |
818 | /** |
819 | * Get the provider's type. |
820 | * |
821 | * @return String The provider's type. |
822 | */ |
823 | public final String getClassType() |
824 | { |
825 | return Dependable.STORED_PREPARED_STATEMENT; |
826 | } |
827 | |
828 | ////////////////////////////////////////////////////// |
829 | // |
830 | // DEPENDENT INTERFACE |
831 | // |
832 | ////////////////////////////////////////////////////// |
833 | /** |
834 | * Check that all of the dependent's dependencies are valid. |
835 | * |
836 | * @return true if the dependent is currently valid |
837 | */ |
838 | public final synchronized boolean isValid() |
839 | { |
840 | return valid; |
841 | } |
842 | |
843 | /** |
844 | * Prepare to mark the dependent as invalid (due to at least one of |
845 | * its dependencies being invalid). |
846 | * |
847 | * @param action The action causing the invalidation |
848 | * @param p the provider |
849 | * |
850 | * @exception StandardException thrown if unable to make it invalid |
851 | */ |
852 | public final synchronized void prepareToInvalidate( |
853 | Provider p, int action, |
854 | LanguageConnectionContext lcc) |
855 | throws StandardException |
856 | { |
857 | switch (action) |
858 | { |
859 | /* |
860 | ** Things that don't affect us |
861 | */ |
862 | case DependencyManager.CREATE_VIEW: |
863 | |
864 | /* |
865 | ** Things that force a recompile, but are |
866 | ** allowed. |
867 | */ |
868 | case DependencyManager.CREATE_INDEX: |
869 | case DependencyManager.CREATE_CONSTRAINT: |
870 | case DependencyManager.DROP_CONSTRAINT: |
871 | case DependencyManager.DROP_INDEX: |
872 | case DependencyManager.DROP_TABLE: |
873 | case DependencyManager.DROP_VIEW: |
874 | case DependencyManager.DROP_METHOD_ALIAS: |
875 | case DependencyManager.DROP_SYNONYM: |
876 | case DependencyManager.ALTER_TABLE: |
877 | case DependencyManager.RENAME: |
878 | case DependencyManager.RENAME_INDEX: |
879 | case DependencyManager.PREPARED_STATEMENT_RELEASE: |
880 | case DependencyManager.USER_RECOMPILE_REQUEST: |
881 | case DependencyManager.CHANGED_CURSOR: |
882 | case DependencyManager.BULK_INSERT: |
883 | case DependencyManager.COMPRESS_TABLE: |
884 | case DependencyManager.SET_CONSTRAINTS_ENABLE: |
885 | case DependencyManager.SET_CONSTRAINTS_DISABLE: |
886 | case DependencyManager.SET_TRIGGERS_ENABLE: |
887 | case DependencyManager.SET_TRIGGERS_DISABLE: |
888 | case DependencyManager.ROLLBACK: |
889 | case DependencyManager.INTERNAL_RECOMPILE_REQUEST: |
890 | case DependencyManager.CREATE_TRIGGER: |
891 | case DependencyManager.DROP_TRIGGER: |
892 | case DependencyManager.DROP_COLUMN: |
893 | case DependencyManager.UPDATE_STATISTICS: |
894 | case DependencyManager.DROP_STATISTICS: |
895 | case DependencyManager.TRUNCATE_TABLE: |
896 | break; |
897 | |
898 | /* |
899 | ** The rest are errors |
900 | */ |
901 | default: |
902 | |
903 | DependencyManager dm; |
904 | |
905 | dm = getDataDictionary().getDependencyManager(); |
906 | throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_S_P_S, |
907 | dm.getActionString(action), |
908 | p.getObjectName(), name); |
909 | |
910 | } |
911 | } |
912 | |
913 | /** |
914 | * Mark the dependent as invalid (due to at least one of |
915 | * its dependencies being invalid). |
916 | * |
917 | * @param action The action causing the invalidation |
918 | * |
919 | * @exception StandardException thrown if unable to make it invalid |
920 | */ |
921 | public final synchronized void makeInvalid(int action, |
922 | LanguageConnectionContext lcc) |
923 | throws StandardException |
924 | { |
925 | DependencyManager dm; |
926 | |
927 | dm = getDataDictionary().getDependencyManager(); |
928 | |
929 | switch (action) |
930 | { |
931 | /* |
932 | ** Some things that don't affect stored prepared |
933 | ** statements. |
934 | */ |
935 | case DependencyManager.PREPARED_STATEMENT_RELEASE: |
936 | case DependencyManager.CREATE_VIEW: |
937 | break; |
938 | |
939 | /* |
940 | ** Things that can invalidate a stored |
941 | ** prepared statement. |
942 | */ |
943 | case DependencyManager.CREATE_INDEX: |
944 | case DependencyManager.CREATE_CONSTRAINT: |
945 | case DependencyManager.DROP_CONSTRAINT: |
946 | case DependencyManager.DROP_TABLE: |
947 | case DependencyManager.DROP_INDEX: |
948 | case DependencyManager.DROP_VIEW: |
949 | case DependencyManager.DROP_METHOD_ALIAS: |
950 | case DependencyManager.DROP_SYNONYM: |
951 | case DependencyManager.ALTER_TABLE: |
952 | case DependencyManager.RENAME: |
953 | case DependencyManager.RENAME_INDEX: |
954 | case DependencyManager.USER_RECOMPILE_REQUEST: |
955 | case DependencyManager.CHANGED_CURSOR: |
956 | case DependencyManager.BULK_INSERT: |
957 | case DependencyManager.COMPRESS_TABLE: |
958 | case DependencyManager.SET_CONSTRAINTS_ENABLE: |
959 | case DependencyManager.SET_CONSTRAINTS_DISABLE: |
960 | case DependencyManager.SET_TRIGGERS_ENABLE: |
961 | case DependencyManager.SET_TRIGGERS_DISABLE: |
962 | case DependencyManager.ROLLBACK: |
963 | case DependencyManager.INTERNAL_RECOMPILE_REQUEST: |
964 | case DependencyManager.CREATE_TRIGGER: |
965 | case DependencyManager.DROP_TRIGGER: |
966 | case DependencyManager.DROP_COLUMN: |
967 | case DependencyManager.UPDATE_STATISTICS: |
968 | case DependencyManager.DROP_STATISTICS: |
969 | case DependencyManager.TRUNCATE_TABLE: |
970 | /* |
971 | ** If we are already invalid, don't write ourselves |
972 | ** out. Just to be safe, we'll send out an invalidate |
973 | ** to our dependents either way. |
974 | */ |
975 | if (valid == true) |
976 | { |
977 | valid = false; |
978 | updateSYSSTATEMENTS(lcc, INVALIDATE, null); |
979 | } |
980 | dm.invalidateFor(this, dm.USER_RECOMPILE_REQUEST, lcc); |
981 | break; |
982 | case DependencyManager.DROP_SPS: |
983 | //System.out.println("SPSD " + preparedStatement); |
984 | dm.clearDependencies(lcc, this); |
985 | break; |
986 | |
987 | default: |
988 | |
989 | /* |
990 | ** We should never get here, since we can't have dangling references |
991 | */ |
992 | if (SanityManager.DEBUG) |
993 | { |
994 | SanityManager.THROWASSERT("makeInvalid("+ |
995 | dm.getActionString(action)+ |
996 | ") not expected to get called; should have failed in "+ |
997 | "prepareToInvalidate()"); |
998 | } |
999 | break; |
1000 | |
1001 | } |
1002 | |
1003 | } |
1004 | |
1005 | /** |
1006 | * Attempt to revalidate the dependent. For prepared statements, |
1007 | * this could go through its dependencies and check that they |
1008 | * are up to date; if not, it would recompile the statement. |
1009 | * Any failure during this attempt should throw |
1010 | * StandardException.unableToRevalidate(). |
1011 | * |
1012 | * @exception StandardException thrown if unable to make it valid |
1013 | */ |
1014 | public final synchronized void makeValid(LanguageConnectionContext lcc) |
1015 | throws StandardException |
1016 | { |
1017 | if (valid) |
1018 | { |
1019 | return; |
1020 | } |
1021 | prepareAndRelease(lcc); |
1022 | |
1023 | updateSYSSTATEMENTS(lcc, RECOMPILE, null); |
1024 | |
1025 | } |
1026 | |
1027 | /** |
1028 | * Invalidate and revalidate. The functional equivalent |
1029 | * of calling makeInvalid() and makeValid(), except it |
1030 | * is optimized. |
1031 | * |
1032 | * @exception StandardException on error |
1033 | */ |
1034 | public final synchronized void revalidate(LanguageConnectionContext lcc) |
1035 | throws StandardException |
1036 | { |
1037 | /* |
1038 | ** Mark it as invalid first to ensure that |
1039 | ** we don't write SYSSTATEMENTS 2x. |
1040 | */ |
1041 | valid = false; |
1042 | makeInvalid(DependencyManager.USER_RECOMPILE_REQUEST, lcc); |
1043 | prepareAndRelease(lcc); |
1044 | updateSYSSTATEMENTS(lcc, RECOMPILE, null); |
1045 | } |
1046 | |
1047 | /** |
1048 | * Load the underlying generatd class. This is not expected |
1049 | * to be used outside of the datadictionary package. It |
1050 | * is used for optimizing class loading for sps |
1051 | * cacheing. |
1052 | * |
1053 | * @exception StandardException on error |
1054 | */ |
1055 | public void loadGeneratedClass() throws StandardException |
1056 | { |
1057 | /* |
1058 | ** On upgrade, we null out the statement body, |
1059 | ** so handle that here. |
1060 | */ |
1061 | if (preparedStatement != null) |
1062 | { |
1063 | ((StorablePreparedStatement)preparedStatement).loadGeneratedClass(); |
1064 | } |
1065 | } |
1066 | |
1067 | /* |
1068 | ** Update SYSSTATEMENTS with the changed the descriptor. |
1069 | ** Always done in the user XACT. |
1070 | ** <p> |
1071 | ** Ideally, the changes to SYSSTATEMENTS would be made |
1072 | ** in a separate xact as the current user xact, but this |
1073 | ** is painful (you'ld need to get a new ContextManager |
1074 | ** and then push all of the usual langauge contexts |
1075 | ** onto it and THEN call AccessManager.getTransaction()), |
1076 | ** and it wont work, because the xact is in a different |
1077 | ** compatibility space and will self deadlock (e.g. |
1078 | ** in the process of call DependencyManager.makeInvalid() |
1079 | ** we first did a DDdependableFinder.getDependable() |
1080 | ** which called DataDictionaryImpl.getSPSDescriptor() |
1081 | ** so we hold a lock on SYS.SYSSTATEMENTS by the |
1082 | ** time we get a 2nd xact and try to drop the statement). |
1083 | */ |
1084 | private void updateSYSSTATEMENTS(LanguageConnectionContext lcc, int mode, TransactionController tc) |
1085 | throws StandardException |
1086 | { |
1087 | int[] colsToUpdate; |
1088 | boolean updateSYSCOLUMNS, recompile; |
1089 | //bug 4821 - we want to wait for locks if updating sysstatements on parent transaction |
1090 | boolean wait = false; |
1091 | boolean firstCompilation = false; |
1092 | if (mode == RECOMPILE) |
1093 | { |
1094 | recompile = true; |
1095 | updateSYSCOLUMNS = true; |
1096 | if(!initiallyCompilable) |
1097 | { |
1098 | firstCompilation = true; |
1099 | initiallyCompilable = true; |
1100 | } |
1101 | } |
1102 | else |
1103 | { |
1104 | recompile = false; |
1105 | updateSYSCOLUMNS = false; |
1106 | } |
1107 | |
1108 | DataDictionary dd = getDataDictionary(); |
1109 | |
1110 | if (((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) dd).readOnlyUpgrade) |
1111 | return; |
1112 | |
1113 | |
1114 | /* |
1115 | ** Get busy time |
1116 | */ |
1117 | dd.startWriting(lcc); |
1118 | |
1119 | if (tc == null) { //bug 4821 - tc will passed null if we want to use the user transaction |
1120 | tc = lcc.getTransactionExecute(); |
1121 | wait = true; |
1122 | } |
1123 | |
1124 | dd.updateSPS(this, |
1125 | tc, |
1126 | recompile, |
1127 | updateSYSCOLUMNS, |
1128 | wait, |
1129 | firstCompilation); |
1130 | } |
1131 | |
1132 | /** |
1133 | * Get the UUID for the given string |
1134 | * |
1135 | * @param idString the string |
1136 | * |
1137 | * @return the UUID |
1138 | */ |
1139 | private UUID recreateUUID(String idString) |
1140 | { |
1141 | if (uuidFactory == null) |
1142 | { |
1143 | uuidFactory = Monitor.getMonitor().getUUIDFactory(); |
1144 | } |
1145 | return uuidFactory.recreateUUID(idString); |
1146 | } |
1147 | |
1148 | /** @see TupleDescriptor#getDescriptorType */ |
1149 | public String getDescriptorType() { return "Statement"; } |
1150 | |
1151 | /** @see TupleDescriptor#getDescriptorName */ |
1152 | // RESOLVE: some descriptors have getName. some descriptors have |
1153 | // getTableName, getColumnName whatever! try and unify all of this to one |
1154 | // getDescriptorName! |
1155 | public String getDescriptorName() { return name; } |
1156 | |
1157 | } |
1158 | |