KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > sql > depend > DependencyManager


1 /*
2
3    Derby - Class org.apache.derby.iapi.sql.depend.DependencyManager
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.iapi.sql.depend;
23
24 import org.apache.derby.iapi.services.context.ContextManager;
25
26 import org.apache.derby.iapi.error.StandardException;
27
28 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
29
30 import org.apache.derby.iapi.store.access.TransactionController;
31
32 /**
33     Dependency Manager Interface
34     <p>
35     The dependency manager tracks needs that dependents have of providers. This
36     is a general purpose interface which is associated with a
37     DataDictinary object; infact the dependencymanager is really the
38     datadictionary keeping track of dependcies between objects that it handles
39     (descriptors) as well as prepared statements.
40     <p>
41     The primary example of this is a prepared statement's needs of
42     schema objects such as tables.
43     <p>
44     Dependencies are used so that we can determine when we
45     need to recompile a statement; compiled statements depend
46     on schema objects like tables and constraints, and may
47     no longer be executable when those tables or constraints are
48     altered. For example, consider an insert statement.
49     <p>
50     An insert statement is likely to have dependencies on the table it
51     inserts into, any tables it selects from (including
52     subqueries), the authorities it uses to do this,
53     and any constraints or triggers it needs to check.
54     <p>
55     A prepared insert statement has a dependency on the target table
56     of the insert. When it is compiled, that dependency is registered
57     from the prepared statement on the data dictionary entry for the
58     table. This dependency is added to the prepared statement's dependency
59     list, which is also accessible from an overall dependency pool.
60     <p>
61     A DDL statement will mark invalid any prepared statement that
62     depends on the schema object the DDL statement is altering or
63     dropping. We tend to want to track at the table level rather than
64     the column or constraint level, so that we are not overburdened
65     with dependencies. This does mean that we may invalidate when in
66     fact we do not need to; for example, adding a column to a table may
67     not actually cause an insert statement compiled for that table
68     to stop working; but our level of granularity may force us to
69     invalidate the insert because it has to invalidate all statements
70     that depend on the table due to some of them actually no longer
71     being valid.
72
73     It is up to the user of the dependency system at what granularity
74     to track dependencies, where to hang them, and how to identify when
75     objects become invalid. The dependency system is basically supplying
76     the ability to find out who is interested in knowing about
77     other, distinct operations. The primary user is the language system,
78     and its primary use is for invalidating prepared statements when
79     DDL occurs.
80     <p>
81     The insert will recompile itself when its next execution
82     is requested (not when it is invalidated). We don't want it to
83     recompile when the DDL is issued, as that would increase the time
84     of execution of the DDL command unacceptably. Note that the DDL
85     command is also allowed to proceed even if it would make the
86     statement no longer compilable. It can be useful to have a way
87     to recompile invalid statements during idle time in the system,
88     but our first implementation will simply recompile at the next
89     execution.
90     <p>
91     The start of a recompile will release the connection to
92     all dependencies when it releases the activation class and
93     generates a new one.
94     <p>
95     The Dependency Manager is capable of storing dependencies to
96     ensure that other D.M.s can see them and invalidate them
97     appropriately. The dependencies in memory only the current
98     D.M. can see; the stored dependencies are visible to other D.M.s
99     once the transaction in which they were stored is committed.
100     <p>
101     REVISIT: Given that statements are compiled in a separate top-transaction
102     from their execution, we may need/want some intermediate memory
103     storage that makes the dependencies visible to all D.M.s in the
104     system, without requiring that they be stored.
105     <p>
106     To ensure that dependencies are cleaned up when a statement is undone,
107     the compiler context needs to keep track of what dependent it was
108     creating dependencies for, and if it is informed of a statement
109     exception that causes it to throw out the statement it was compiling,
110     it should also call the dependency manager to have the
111     dependencies removed.
112     <p>
113     Several expansions of the basic interface may be desirable:
114     <ul>
115     <li> to note a type of dependency, and to invalidate or perform
116       an invalidation action based on dependency type
117     <li> to note a type of invalidation, so the revalidation could
118       actually take some action other than recompilation, such as
119       simply ensuring the provider objects still existed.
120     <li> to control the order of invalidation, so that if (for example)
121       the invalidation action actually includes the revalidation attempt,
122       revalidation is not attempted until all invalidations have occurred.
123     <li> to get a list of dependencies that a Dependent or
124       a Provider has (this is included in the above, although the
125       basic system does not need to expose the list).
126     <li> to find out which of the dependencies for a dependent were marked
127       invalid.
128     </ul>
129     <p>
130     To provide a simple interface that satisfies the basic need,
131     and yet supply more advanced functionality as well, we will present
132     the simple functionality as defaults and provide ways to specify the
133     more advanced functionality.
134
135     <pre>
136     interface Dependent {
137         boolean isValid();
138         InvalidType getInvalidType(); // returns what it sees
139                         // as the "most important"
140                         // of its invalid types.
141         void makeInvalid( );
142         void makeInvalid( DependencyType dt, InvalidType it );
143         void makeValid();
144     }
145
146     interface Provider() {
147     }
148
149     interface Dependency() {
150         Provider getProvider();
151         Dependent getDependent();
152         DependencyType getDependencyType();
153         boolean isValid();
154         InvalidType getInvalidType(); // returns what it sees
155                         // as the "most important"
156                         // of its invalid types.
157     }
158
159     interface DependencyManager() {
160         void addDependency(Dependent d, Provider p, ContextManager cm);
161         void invalidateFor(Provider p);
162         void invalidateFor(Provider p, DependencyType dt, InvalidType it);
163         void clearDependencies(Dependent d);
164         void clearDependencies(Dependent d, DependencyType dt);
165         Enumeration getProviders (Dependent d);
166         Enumeration getProviders (Dependent d, DependencyType dt);
167         Enumeration getInvalidDependencies (Dependent d,
168             DependencyType dt, InvalidType it);
169         Enumeration getDependents (Provider p);
170         Enumeration getDependents (Provider p, DependencyType dt);
171         Enumeration getInvalidDependencies (Provider p,
172             DependencyType dt, InvalidType it);
173     }
174     </pre>
175     <p>
176     The simplest things for DependencyType and InvalidType to be are
177     integer id's or strings, rather than complex objects.
178     <p>
179     In terms of ensuring that no makeInvalid calls are made until we have
180     identified all objects that could be, so that the calls will be made
181     from "leaf" invalid objects (those not in turn relied on by other
182     dependents) to dependent objects upon which others depend, the
183     dependency manager will need to maintain an internal queue of
184     dependencies and make the calls once it has completes its analysis
185     of the dependencies of which it is aware. Since it is much simpler
186     and potentially faster for makeInvalid calls to be made as soon
187     as the dependents are identified, separate implementations may be
188     called for, or separate interfaces to trigger the different
189     styles of invalidation.
190     <p>
191     In terms of separate interfaces, the DependencyManager might have
192     two methods,
193     <pre>
194         void makeInvalidImmediate();
195         void makeInvalidOrdered();
196     </pre>
197     or a flag on the makeInvalid method to choose the style to use.
198     <p>
199     In terms of separate implementations, the ImmediateInvalidate
200     manager might have simpler internal structures for
201     tracking dependencies than the OrderedInvalidate manager.
202     <p>
203     The language system doesn't tend to suffer from this ordering problem,
204     as it tends to handle the impact of invalidation by simply deferring
205     recompilation until the next execution. So, a prepared statement
206     might be invalidated several times by a transaction that contains
207     several DDL operations, and only recompiled once, at its next
208     execution. This is sufficient for the common use of a system, where
209     DDL changes tend to be infrequent and clustered.
210     <p>
211     There could be ways to push this "ordering problem" out of the
212     dependency system, but since it knows when it starts and when it
213     finished finding all of the invalidating actions, it is likely
214     the best home for this.
215     <p>
216     One other problem that could arise is multiple invalidations occurring
217     one after another. The above design of the dependency system can
218     really only react to each invalidation request as a unit, not
219     to multiple invalidation requests.
220     <p>
221     Another extension that might be desired is for the dependency manager
222     to provide for cascading invalidations -- that is, if it finds
223     and marks one Dependent object as invalid, if that object can also
224     be a provider, to look for its dependent objects and cascade the
225     dependency on to them. This can be a way to address the
226     multiple-invalidation request need, if it should arise. The simplest
227     way to do this is to always cascade the same invalidation type;
228     otherwise, dependents need to be able to say what a certain type
229     of invalidation type gets changed to when it is handed on.
230     <p>
231     The basic language system does not need support for cascaded
232     dependencies -- statements do not depend on other statements
233     in a way that involves the dependency system.
234     <p>
235     I do not know if it would be worthwhile to consider using the
236     dependency manager to aid in the implementation of the SQL DROP
237     statements or not. Past implementations
238     of database systems have not used the dependency system to implement
239     this functionality, but have instead hard-coded the lookups like so:
240
241     <pre>
242         in DropTable:
243             scan the TableAuthority table looking for authorities on
244         this table; drop any that are found.
245             scan the ColumnAuthority table looking for authorities on
246         this table; drop any that are found.
247             scan the View table looking for views on
248         this table; drop any that are found.
249             scan the Column table looking for rows for columns of
250         this table; drop any that are found.
251             scan the Constraint table looking for rows for constraints of
252         this table; drop any that are found.
253             scan the Index table looking for rows for indexes of
254         this table; drop the indexes, and any rows that are found.
255         drop the table's conglomerate
256         drop the table's row in the Table table.
257         </pre>
258     <p>
259     The direct approach such as that outlined in the example will
260     probably be quicker and is definitely "known technology" over
261     the use of a dependency system in this area.
262  */

263
264 public interface DependencyManager {
265
266     /* NOTE - every value in this group (actions) must have a matching
267      * String in the implementation of getActionString().
268      */

269     public static final int COMPILE_FAILED = 0;
270     public static final int DROP_TABLE = 1;
271     public static final int DROP_INDEX = 2;
272     public static final int CREATE_INDEX = 3;
273     public static final int ROLLBACK = 4;
274     public static final int CHANGED_CURSOR = 5;
275     public static final int DROP_METHOD_ALIAS = 6;
276     public static final int DROP_VIEW = 9;
277     public static final int CREATE_VIEW = 10;
278     public static final int PREPARED_STATEMENT_RELEASE = 11;
279     public static final int ALTER_TABLE = 12;
280     public static final int DROP_SPS = 13;
281     public static final int USER_RECOMPILE_REQUEST = 14;
282     public static final int BULK_INSERT = 15;
283     public static final int DROP_JAR = 17;
284     public static final int REPLACE_JAR = 18;
285     public static final int DROP_CONSTRAINT = 19;
286     public static final int SET_CONSTRAINTS_ENABLE = 20;
287     public static final int SET_CONSTRAINTS_DISABLE = 21;
288     public static final int CREATE_CONSTRAINT = 22;
289     public static final int INTERNAL_RECOMPILE_REQUEST = 23;
290     public static final int DROP_TRIGGER = 27;
291     public static final int CREATE_TRIGGER = 28;
292     public static final int SET_TRIGGERS_ENABLE = 29;
293     public static final int SET_TRIGGERS_DISABLE = 30;
294     public static final int MODIFY_COLUMN_DEFAULT = 31;
295     public static final int DROP_SCHEMA = 32;
296     public static final int COMPRESS_TABLE = 33;
297     //using same action for rename table/column
298
public static final int RENAME = 34;
299     public static final int DROP_COLUMN = 37;
300     public static final int DROP_STATISTICS = 39;
301     public static final int UPDATE_STATISTICS = 40;
302     //rename index dependency behavior is not as stringent as rename table and column and
303
//hence we need a different action for rename index. Rename index tries to imitate the
304
//drop index behavior for dependency which is not very strict.
305
public static final int RENAME_INDEX = 41;
306
307     public static final int TRUNCATE_TABLE = 42;
308     public static final int DROP_SYNONYM = 43;
309     //A generic revoke action for TRIGGER, REFERENCES, SELECT, INSERT,
310
// UPDATE and DELETE privileges. For all these privilege types,
311
// a revoke statement causes the dependents to drop
312
public static final int REVOKE_PRIVILEGE = 44;
313     
314     //This special revoke action is for when revoke should fail if
315
// there are dependents on the privilege being revoked. When
316
// such an action type is received by any dependents, they
317
// should throw an exception. Such a form of revoke will succeed
318
// only if there are no dependents on the privilege being revoked.
319
//
320
//Currently, this is supported only for execute privilege on a
321
// routine. In Derby, at this point, execute privilege on a
322
// routine can be revoked only if there are no dependents on
323
// that privilege. So, when a revoke execute..,restrict is
324
// issued, this invalidation action will be sent to all
325
// it's dependents.
326
public static final int REVOKE_PRIVILEGE_RESTRICT = 45;
327
328     /**
329      * Extensions to this interface may use action codes > MAX_ACTION_CODE without fear of
330      * clashing with action codes in this base interface.
331      */

332     public static final int MAX_ACTION_CODE = 0XFFFF;
333
334     /**
335         adds a dependency from the dependent on the provider.
336         This will be considered to be the default type of
337         dependency, when dependency types show up.
338         <p>
339         Implementations of addDependency should be fast --
340         performing alot of extra actions to add a dependency would
341         be a detriment.
342
343         @param d the dependent
344         @param p the provider
345         @param cm Current ContextManager
346
347         @exception StandardException thrown if something goes wrong
348      */

349     void addDependency(Dependent d, Provider p, ContextManager cm) throws StandardException;
350
351     /**
352         mark all dependencies on the named provider as invalid.
353         When invalidation types show up, this will use the default
354         invalidation type. The dependencies will still exist once
355         they are marked invalid; clearDependencies should be used
356         to remove dependencies that a dependent has or provider gives.
357         <p>
358         Implementations of this can take a little time, but are not
359         really expected to recompile things against any changes
360         made to the provider that caused the invalidation. The
361         dependency system makes no guarantees about the state of
362         the provider -- implementations can call this before or
363         after actually changing the provider to its new state.
364         <p>
365         Implementations should throw DependencyStatementException
366         if the invalidation should be disallowed.
367
368         @param p the provider
369         @param action The action causing the invalidate
370         @param lcc The LanguageConnectionContext
371
372         @exception StandardException thrown if unable to make it invalid
373      */

374     void invalidateFor(Provider p, int action, LanguageConnectionContext lcc)
375         throws StandardException;
376
377
378
379     /**
380         Erases all of the dependencies the dependent has, be they
381         valid or invalid, of any dependency type. This action is
382         usually performed as the first step in revalidating a
383         dependent; it first erases all the old dependencies, then
384         revalidates itself generating a list of new dependencies,
385         and then marks itself valid if all its new dependencies are
386         valid.
387         <p>
388         There might be a future want to clear all dependencies for
389         a particular provider, e.g. when destroying the provider.
390         However, at present, they are assumed to stick around and
391         it is the responsibility of the dependent to erase them when
392         revalidating against the new version of the provider.
393         <p>
394         clearDependencies will delete dependencies if they are
395         stored; the delete is finalized at the next commit.
396
397         @param lcc Compiler state
398         @param d the dependent
399      *
400      * @exception StandardException Thrown on failure
401      */

402     void clearDependencies(LanguageConnectionContext lcc, Dependent d) throws StandardException;
403
404     /**
405      * Clear the specified in memory dependency.
406      * This is useful for clean-up when an exception occurs.
407      * (We clear all in-memory dependencies added in the current
408      * StatementContext.)
409        This method will handle Dependency's that have already been
410        removed from the DependencyManager.
411      */

412     public void clearInMemoryDependency(Dependency dy);
413
414     /**
415      * Get a new array of ProviderInfos representing all the persistent
416      * providers for the given dependent.
417      *
418      * @exception StandardException Thrown on error.
419      */

420     public ProviderInfo[] getPersistentProviderInfos(Dependent dependent)
421             throws StandardException;
422
423     /**
424      * Get a new array of ProviderInfos representing all the persistent
425      * providers from the given list of providers.
426      *
427      * @exception StandardException Thrown on error.
428      */

429     public ProviderInfo[] getPersistentProviderInfos(ProviderList pl)
430             throws StandardException;
431
432     /**
433      * Clear the in memory column bit map information in any table descriptor
434      * provider in a provider list. This function needs to be called before
435      * the table descriptor is reused as provider in column dependency. For
436      * example, this happens in "create publication" statement with target-only
437      * DDL where more than one views are defined and they all reference one
438      * table.
439      *
440      * @exception StandardException Thrown on error.
441      */

442     public void clearColumnInfoInProviders(ProviderList pl)
443             throws StandardException;
444
445
446     /**
447      * Copy dependencies from one dependent to another.
448      *
449      * @param copy_From the dependent to copy from
450      * @param copyTo the dependent to copy to
451      * @param persistentOnly only copy persistent dependencies
452      * @param cm Current ContextManager
453      *
454      * @exception StandardException Thrown on error.
455      */

456     public void copyDependencies(
457                                     Dependent copy_From,
458                                     Dependent copyTo,
459                                     boolean persistentOnly,
460                                     ContextManager cm)
461             throws StandardException;
462     
463     /**
464      * Returns a string representation of the SQL action, hence no
465      * need to internationalize, which is causing the invokation
466      * of the Dependency Manager.
467      *
468      * @param action The action
469      *
470      * @return String The String representation
471      */

472     String JavaDoc getActionString(int action);
473
474     /**
475      * Count the number of active dependencies, both stored and in memory,
476      * in the system.
477      *
478      * @return int The number of active dependencies in the system.
479
480         @exception StandardException thrown if something goes wrong
481      */

482     public int countDependencies() throws StandardException;
483
484     /**
485      * Dump out debugging info on all of the dependencies currently
486      * within the system.
487      *
488      * @return String Debugging info on the dependencies.
489      * (null if SanityManger.DEBUG is false)
490
491         @exception StandardException thrown if something goes wrong
492         @exception java.sql.SQLException thrown if something goes wrong
493      */

494     public String JavaDoc dumpDependencies() throws StandardException, java.sql.SQLException JavaDoc;
495     
496     /**
497         Erases all of the dependencies the dependent has, be they
498         valid or invalid, of any dependency type. This action is
499         usually performed as the first step in revalidating a
500         dependent; it first erases all the old dependencies, then
501         revalidates itself generating a list of new dependencies,
502         and then marks itself valid if all its new dependencies are
503         valid.
504         <p>
505         There might be a future want to clear all dependencies for
506         a particular provider, e.g. when destroying the provider.
507         However, at present, they are assumed to stick around and
508         it is the responsibility of the dependent to erase them when
509         revalidating against the new version of the provider.
510         <p>
511         clearDependencies will delete dependencies if they are
512         stored; the delete is finalized at the next commit.
513
514         @param lcc Compiler state
515         @param d the dependent
516         @param tc transaction controller
517     
518         @exception StandardException Thrown on failure
519     */

520     public void clearDependencies(LanguageConnectionContext lcc,
521                                     Dependent d,
522                                     TransactionController tc)
523         throws StandardException;
524
525
526     /**
527      * Copy dependencies from one dependent to another.
528      *
529      * @param copy_From the dependent to copy from
530      * @param copyTo the dependent to copy to
531      * @param persistentOnly only copy persistent dependencies
532      * @param cm Current ContextManager
533      * @param tc Transaction Controller
534      *
535      * @exception StandardException Thrown on error.
536      */

537     public void copyDependencies(
538                                     Dependent copy_From,
539                                     Dependent copyTo,
540                                     boolean persistentOnly,
541                                     ContextManager cm,
542                                     TransactionController tc)
543             throws StandardException;
544     
545 }
546
Popular Tags