Source code: org/apache/derby/iapi/sql/depend/DependencyManager.java
1 /*
2
3 Derby - Class org.apache.derby.iapi.sql.depend.DependencyManager
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.iapi.sql.depend;
22
23 import org.apache.derby.iapi.services.context.ContextManager;
24
25 import org.apache.derby.iapi.error.StandardException;
26
27 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
28
29
30 /**
31 Dependency Manager Interface
32 <p>
33 The dependency manager tracks needs that dependents have of providers. This
34 is a general purpose interface interface which is associated with a
35 DataDictinary object; infact the dependencymanager is really the
36 datadictionary keeping track of dependcies between objects that it handles
37 (descriptors) as well as prepared statements.
38 <p>
39 The primary example of this is a prepared statement's needs of
40 schema objects such as tables.
41 <p>
42 Dependencies are used so that we can determine when we
43 need to recompile a statement; compiled statements depend
44 on schema objects like tables and constraints, and may
45 no longer be executable when those tables or constraints are
46 altered. For example, consider an insert statement.
47 <p>
48 An insert statement is likely to have dependencies on the table it
49 inserts into, any tables it selects from (including
50 subqueries), the authorities it uses to do this,
51 and any constraints or triggers it needs to check.
52 <p>
53 A prepared insert statement has a dependency on the target table
54 of the insert. When it is compiled, that dependency is registered
55 from the prepared statement on the data dictionary entry for the
56 table. This dependency is added to the prepared statement's dependency
57 list, which is also accessible from an overall dependency pool.
58 <p>
59 A DDL statement will mark invalid any prepared statement that
60 depends on the schema object the DDL statement is altering or
61 dropping. We tend to want to track at the table level rather than
62 the column or constraint level, so that we are not overburdened
63 with dependencies. This does mean that we may invalidate when in
64 fact we do not need to; for example, adding a column to a table may
65 not actually cause an insert statement compiled for that table
66 to stop working; but our level of granularity may force us to
67 invalidate the insert because it has to invalidate all statements
68 that depend on the table due to some of them actually no longer
69 being valid.
70
71 It is up to the user of the dependency system at what granularity
72 to track dependencies, where to hang them, and how to identify when
73 objects become invalid. The dependency system is basically supplying
74 the ability to find out who is interested in knowing about
75 other, distinct operations. The primary user is the language system,
76 and its primary use is for invalidating prepared statements when
77 DDL occurs.
78 <p>
79 The insert will recompile itself when its next execution
80 is requested (not when it is invalidated). We don't want it to
81 recompile when the DDL is issued, as that would increase the time
82 of execution of the DDL command unacceptably. Note that the DDL
83 command is also allowed to proceed even if it would make the
84 statement no longer compilable. It can be useful to have a way
85 to recompile invalid statements during idle time in the system,
86 but our first implementation will simply recompile at the next
87 execution.
88 <p>
89 The start of a recompile will release the connection to
90 all dependencies when it releases the activation class and
91 generates a new one.
92 <p>
93 The Dependency Manager is capable of storing dependencies to
94 ensure that other D.M.s can see them and invalidate them
95 appropriately. The dependencies in memory only the current
96 D.M. can see; the stored dependencies are visible to other D.M.s
97 once the transaction in which they were stored is committed.
98 <p>
99 REVISIT: Given that statements are compiled in a separate top-transaction
100 from their execution, we may need/want some intermediate memory
101 storage that makes the dependencies visible to all D.M.s in the
102 system, without requiring that they be stored.
103 <p>
104 To ensure that dependencies are cleaned up when a statement is undone,
105 the compiler context needs to keep track of what dependent it was
106 creating dependencies for, and if it is informed of a statement
107 exception that causes it to throw out the statement it was compiling,
108 it should also call the dependency manager to have the
109 dependencies removed.
110 <p>
111 Several expansions of the basic interface may be desirable:
112 <ul>
113 <li> to note a type of dependency, and to invalidate or perform
114 an invalidation action based on dependency type
115 <li> to note a type of invalidation, so the revalidation could
116 actually take some action other than recompilation, such as
117 simply ensuring the provider objects still existed.
118 <li> to control the order of invalidation, so that if (for example)
119 the invalidation action actually includes the revalidation attempt,
120 revalidation is not attempted until all invalidations have occurred.
121 <li> to get a list of dependencies that a Dependent or
122 a Provider has (this is included in the above, although the
123 basic system does not need to expose the list).
124 <li> to find out which of the dependencies for a dependent were marked
125 invalid.
126 </ul>
127 <p>
128 To provide a simple interface that satisfies the basic need,
129 and yet supply more advanced functionality as well, we will present
130 the simple functionality as defaults and provide ways to specify the
131 more advanced functionality.
132
133 <pre>
134 interface Dependent {
135 boolean isValid();
136 InvalidType getInvalidType(); // returns what it sees
137 // as the "most important"
138 // of its invalid types.
139 void makeInvalid( );
140 void makeInvalid( DependencyType dt, InvalidType it );
141 void makeValid();
142 }
143
144 interface Provider() {
145 }
146
147 interface Dependency() {
148 Provider getProvider();
149 Dependent getDependent();
150 DependencyType getDependencyType();
151 boolean isValid();
152 InvalidType getInvalidType(); // returns what it sees
153 // as the "most important"
154 // of its invalid types.
155 }
156
157 interface DependencyManager() {
158 void addDependency(Dependent d, Provider p, ContextManager cm);
159 void invalidateFor(Provider p);
160 void invalidateFor(Provider p, DependencyType dt, InvalidType it);
161 void clearDependencies(Dependent d);
162 void clearDependencies(Dependent d, DependencyType dt);
163 Enumeration getProviders (Dependent d);
164 Enumeration getProviders (Dependent d, DependencyType dt);
165 Enumeration getInvalidDependencies (Dependent d,
166 DependencyType dt, InvalidType it);
167 Enumeration getDependents (Provider p);
168 Enumeration getDependents (Provider p, DependencyType dt);
169 Enumeration getInvalidDependencies (Provider p,
170 DependencyType dt, InvalidType it);
171 }
172 </pre>
173 <p>
174 The simplest things for DependencyType and InvalidType to be are
175 integer id's or strings, rather than complex objects.
176 <p>
177 In terms of ensuring that no makeInvalid calls are made until we have
178 identified all objects that could be, so that the calls will be made
179 from "leaf" invalid objects (those not in turn relied on by other
180 dependents) to dependent objects upon which others depend, the
181 dependency manager will need to maintain an internal queue of
182 dependencies and make the calls once it has completes its analysis
183 of the dependencies of which it is aware. Since it is much simpler
184 and potentially faster for makeInvalid calls to be made as soon
185 as the dependents are identified, separate implementations may be
186 called for, or separate interfaces to trigger the different
187 styles of invalidation.
188 <p>
189 In terms of separate interfaces, the DependencyManager might have
190 two methods,
191 <pre>
192 void makeInvalidImmediate();
193 void makeInvalidOrdered();
194 </pre>
195 or a flag on the makeInvalid method to choose the style to use.
196 <p>
197 In terms of separate implementations, the ImmediateInvalidate
198 manager might have simpler internal structures for
199 tracking dependencies than the OrderedInvalidate manager.
200 <p>
201 The language system doesn't tend to suffer from this ordering problem,
202 as it tends to handle the impact of invalidation by simply deferring
203 recompilation until the next execution. So, a prepared statement
204 might be invalidated several times by a transaction that contains
205 several DDL operations, and only recompiled once, at its next
206 execution. This is sufficient for the common use of a system, where
207 DDL changes tend to be infrequent and clustered.
208 <p>
209 There could be ways to push this "ordering problem" out of the
210 dependency system, but since it knows when it starts and when it
211 finished finding all of the invalidating actions, it is likely
212 the best home for this.
213 <p>
214 One other problem that could arise is multiple invalidations occurring
215 one after another. The above design of the dependency system can
216 really only react to each invalidation request as a unit, not
217 to multiple invalidation requests.
218 <p>
219 Another extension that might be desired is for the dependency manager
220 to provide for cascading invalidations -- that is, if it finds
221 and marks one Dependent object as invalid, if that object can also
222 be a provider, to look for its dependent objects and cascade the
223 dependency on to them. This can be a way to address the
224 multiple-invalidation request need, if it should arise. The simplest
225 way to do this is to always cascade the same invalidation type;
226 otherwise, dependents need to be able to say what a certain type
227 of invalidation type gets changed to when it is handed on.
228 <p>
229 The basic language system does not need support for cascaded
230 dependencies -- statements do not depend on other statements
231 in a way that involves the dependency system.
232 <p>
233 I do not know if it would be worthwhile to consider using the
234 dependency manager to aid in the implementation of the SQL DROP
235 statements or not. SQL DROP statements tend to have CASCADE or
236 RESTRICT actions, where they either also DROP all objects that
237 somehow use or depend on the object being dropped, or refuse
238 to drop the object if any such objects exist. Past implementations
239 of database systems have not used the dependency system to implement
240 this functionality, but have instead hard-coded the lookups like so:
241
242 <pre>
243 in DropTable:
244 scan the TableAuthority table looking for authorities on
245 this table; drop any that are found.
246 scan the ColumnAuthority table looking for authorities on
247 this table; drop any that are found.
248 scan the View table looking for views on
249 this table; drop any that are found.
250 scan the Column table looking for rows for columns of
251 this table; drop any that are found.
252 scan the Constraint table looking for rows for constraints of
253 this table; drop any that are found.
254 scan the Index table looking for rows for indexes of
255 this table; drop the indexes, and any rows that are found.
256 drop the table's conglomerate
257 drop the table's row in the Table table.
258 </pre>
259 <p>
260 The direct approach such as that outlined in the example will
261 probably be quicker and is definitely "known technology" over
262 the use of a dependency system in this area.
263 */
264
265 public interface DependencyManager {
266
267 /* NOTE - every value in this group (actions) must have a matching
268 * String in the implementation of getActionString().
269 */
270 public static final int COMPILE_FAILED = 0;
271 public static final int DROP_TABLE = 1;
272 public static final int DROP_INDEX = 2;
273 public static final int CREATE_INDEX = 3;
274 public static final int ROLLBACK = 4;
275 public static final int CHANGED_CURSOR = 5;
276 public static final int DROP_METHOD_ALIAS = 6;
277 public static final int DROP_VIEW = 9;
278 public static final int CREATE_VIEW = 10;
279 public static final int PREPARED_STATEMENT_RELEASE = 11;
280 public static final int ALTER_TABLE = 12;
281 public static final int DROP_SPS = 13;
282 public static final int USER_RECOMPILE_REQUEST = 14;
283 public static final int BULK_INSERT = 15;
284 public static final int DROP_JAR = 17;
285 public static final int REPLACE_JAR = 18;
286 public static final int DROP_CONSTRAINT = 19;
287 public static final int SET_CONSTRAINTS_ENABLE = 20;
288 public static final int SET_CONSTRAINTS_DISABLE = 21;
289 public static final int CREATE_CONSTRAINT = 22;
290 public static final int INTERNAL_RECOMPILE_REQUEST = 23;
291 public static final int DROP_TRIGGER = 27;
292 public static final int CREATE_TRIGGER = 28;
293 public static final int SET_TRIGGERS_ENABLE = 29;
294 public static final int SET_TRIGGERS_DISABLE = 30;
295 public static final int MODIFY_COLUMN_DEFAULT = 31;
296 public static final int DROP_SCHEMA = 32;
297 public static final int COMPRESS_TABLE = 33;
298 //using same action for rename table/column
299 public static final int RENAME = 34;
300 public static final int DROP_TABLE_CASCADE = 35;
301 public static final int DROP_VIEW_CASCADE = 36;
302 public static final int DROP_COLUMN = 37;
303 public static final int DROP_COLUMN_CASCADE = 38;
304 public static final int DROP_STATISTICS = 39;
305 public static final int UPDATE_STATISTICS = 40;
306 //rename index dependency behavior is not as stringent as rename table and column and
307 //hence we need a different action for rename index. Rename index tries to imitate the
308 //drop index behavior for dependency which is not very strict.
309 public static final int RENAME_INDEX = 41;
310
311 public static final int TRUNCATE_TABLE = 42;
312 public static final int DROP_SYNONYM = 43;
313
314 /**
315 * Extensions to this interface may use action codes > MAX_ACTION_CODE without fear of
316 * clashing with action codes in this base interface.
317 */
318 public static final int MAX_ACTION_CODE = 0XFFFF;
319
320 /**
321 adds a dependency from the dependent on the provider.
322 This will be considered to be the default type of
323 dependency, when dependency types show up.
324 <p>
325 Implementations of addDependency should be fast --
326 performing alot of extra actions to add a dependency would
327 be a detriment.
328
329 @param d the dependent
330 @param p the provider
331 @param cm Current ContextManager
332
333 @exception StandardException thrown if something goes wrong
334 */
335 void addDependency(Dependent d, Provider p, ContextManager cm) throws StandardException;
336
337 /**
338 mark all dependencies on the named provider as invalid.
339 When invalidation types show up, this will use the default
340 invalidation type. The dependencies will still exist once
341 they are marked invalid; clearDependencies should be used
342 to remove dependencies that a dependent has or provider gives.
343 <p>
344 Implementations of this can take a little time, but are not
345 really expected to recompile things against any changes
346 made to the provider that caused the invalidation. The
347 dependency system makes no guarantees about the state of
348 the provider -- implementations can call this before or
349 after actually changing the provider to its new state.
350 <p>
351 Implementations should throw DependencyStatementException
352 if the invalidation should be disallowed.
353
354 @param p the provider
355 @param action The action causing the invalidate
356 @param lcc The LanguageConnectionContext
357
358 @exception StandardException thrown if unable to make it invalid
359 */
360 void invalidateFor(Provider p, int action, LanguageConnectionContext lcc)
361 throws StandardException;
362
363
364
365 /**
366 Erases all of the dependencies the dependent has, be they
367 valid or invalid, of any dependency type. This action is
368 usually performed as the first step in revalidating a
369 dependent; it first erases all the old dependencies, then
370 revalidates itself generating a list of new dependencies,
371 and then marks itself valid if all its new dependencies are
372 valid.
373 <p>
374 There might be a future want to clear all dependencies for
375 a particular provider, e.g. when destroying the provider.
376 However, at present, they are assumed to stick around and
377 it is the responsibility of the dependent to erase them when
378 revalidating against the new version of the provider.
379 <p>
380 clearDependencies will delete dependencies if they are
381 stored; the delete is finalized at the next commit.
382
383 @param d the dependent
384 @param p the provider
385 *
386 * @exception StandardException Thrown on failure
387 */
388 void clearDependencies(LanguageConnectionContext lcc, Dependent d) throws StandardException;
389
390 /**
391 * Clear the specified in memory dependency.
392 * This is useful for clean-up when an exception occurs.
393 * (We clear all in-memory dependencies added in the current
394 * StatementContext.)
395 This method will handle Dependency's that have already been
396 removed from the DependencyManager.
397 */
398 public void clearInMemoryDependency(Dependency dy);
399
400 /**
401 * Get a new array of ProviderInfos representing all the persistent
402 * providers for the given dependent.
403 *
404 * @exception StandardException Thrown on error.
405 */
406 public ProviderInfo[] getPersistentProviderInfos(Dependent dependent)
407 throws StandardException;
408
409 /**
410 * Get a new array of ProviderInfos representing all the persistent
411 * providers from the given list of providers.
412 *
413 * @exception StandardException Thrown on error.
414 */
415 public ProviderInfo[] getPersistentProviderInfos(ProviderList pl)
416 throws StandardException;
417
418 /**
419 * Clear the in memory column bit map information in any table descriptor
420 * provider in a provider list. This function needs to be called before
421 * the table descriptor is reused as provider in column dependency. For
422 * example, this happens in "create publication" statement with target-only
423 * DDL where more than one views are defined and they all reference one
424 * table.
425 *
426 * @exception StandardException Thrown on error.
427 */
428 public void clearColumnInfoInProviders(ProviderList pl)
429 throws StandardException;
430
431
432 /**
433 * Copy dependencies from one dependent to another.
434 *
435 * @param copy_From the dependent to copy from
436 * @param copyTo the dependent to copy to
437 * @param persistentOnly only copy persistent dependencies
438 * @param cm Current ContextManager
439 *
440 * @exception StandardException Thrown on error.
441 */
442 public void copyDependencies(
443 Dependent copy_From,
444 Dependent copyTo,
445 boolean persistentOnly,
446 ContextManager cm)
447 throws StandardException;
448
449 /**
450 * Returns a string representation of the SQL action, hence no
451 * need to internationalize, which is causing the invokation
452 * of the Dependency Manager.
453 *
454 * @param int The action
455 *
456 * @return String The String representation
457 */
458 String getActionString(int action);
459
460 /**
461 * Count the number of active dependencies, both stored and in memory,
462 * in the system.
463 *
464 * @return int The number of active dependencies in the system.
465
466 @exception StandardException thrown if something goes wrong
467 */
468 public int countDependencies() throws StandardException;
469
470 /**
471 * Dump out debugging info on all of the dependencies currently
472 * within the system.
473 *
474 * @return String Debugging info on the dependencies.
475 * (null if SanityManger.DEBUG is false)
476
477 @exception StandardException thrown if something goes wrong
478 @exception java.sql.SQLException thrown if something goes wrong
479 */
480 public String dumpDependencies() throws StandardException, java.sql.SQLException;
481 }