Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 }