001: /*
002:
003: Derby - Class org.apache.derby.iapi.sql.depend.DependencyManager
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.iapi.sql.depend;
023:
024: import org.apache.derby.iapi.services.context.ContextManager;
025:
026: import org.apache.derby.iapi.error.StandardException;
027:
028: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
029:
030: import org.apache.derby.iapi.store.access.TransactionController;
031:
032: /**
033: Dependency Manager Interface
034: <p>
035: The dependency manager tracks needs that dependents have of providers. This
036: is a general purpose interface which is associated with a
037: DataDictinary object; infact the dependencymanager is really the
038: datadictionary keeping track of dependcies between objects that it handles
039: (descriptors) as well as prepared statements.
040: <p>
041: The primary example of this is a prepared statement's needs of
042: schema objects such as tables.
043: <p>
044: Dependencies are used so that we can determine when we
045: need to recompile a statement; compiled statements depend
046: on schema objects like tables and constraints, and may
047: no longer be executable when those tables or constraints are
048: altered. For example, consider an insert statement.
049: <p>
050: An insert statement is likely to have dependencies on the table it
051: inserts into, any tables it selects from (including
052: subqueries), the authorities it uses to do this,
053: and any constraints or triggers it needs to check.
054: <p>
055: A prepared insert statement has a dependency on the target table
056: of the insert. When it is compiled, that dependency is registered
057: from the prepared statement on the data dictionary entry for the
058: table. This dependency is added to the prepared statement's dependency
059: list, which is also accessible from an overall dependency pool.
060: <p>
061: A DDL statement will mark invalid any prepared statement that
062: depends on the schema object the DDL statement is altering or
063: dropping. We tend to want to track at the table level rather than
064: the column or constraint level, so that we are not overburdened
065: with dependencies. This does mean that we may invalidate when in
066: fact we do not need to; for example, adding a column to a table may
067: not actually cause an insert statement compiled for that table
068: to stop working; but our level of granularity may force us to
069: invalidate the insert because it has to invalidate all statements
070: that depend on the table due to some of them actually no longer
071: being valid.
072:
073: It is up to the user of the dependency system at what granularity
074: to track dependencies, where to hang them, and how to identify when
075: objects become invalid. The dependency system is basically supplying
076: the ability to find out who is interested in knowing about
077: other, distinct operations. The primary user is the language system,
078: and its primary use is for invalidating prepared statements when
079: DDL occurs.
080: <p>
081: The insert will recompile itself when its next execution
082: is requested (not when it is invalidated). We don't want it to
083: recompile when the DDL is issued, as that would increase the time
084: of execution of the DDL command unacceptably. Note that the DDL
085: command is also allowed to proceed even if it would make the
086: statement no longer compilable. It can be useful to have a way
087: to recompile invalid statements during idle time in the system,
088: but our first implementation will simply recompile at the next
089: execution.
090: <p>
091: The start of a recompile will release the connection to
092: all dependencies when it releases the activation class and
093: generates a new one.
094: <p>
095: The Dependency Manager is capable of storing dependencies to
096: ensure that other D.M.s can see them and invalidate them
097: appropriately. The dependencies in memory only the current
098: D.M. can see; the stored dependencies are visible to other D.M.s
099: 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)
350: throws StandardException;
351:
352: /**
353: mark all dependencies on the named provider as invalid.
354: When invalidation types show up, this will use the default
355: invalidation type. The dependencies will still exist once
356: they are marked invalid; clearDependencies should be used
357: to remove dependencies that a dependent has or provider gives.
358: <p>
359: Implementations of this can take a little time, but are not
360: really expected to recompile things against any changes
361: made to the provider that caused the invalidation. The
362: dependency system makes no guarantees about the state of
363: the provider -- implementations can call this before or
364: after actually changing the provider to its new state.
365: <p>
366: Implementations should throw DependencyStatementException
367: if the invalidation should be disallowed.
368:
369: @param p the provider
370: @param action The action causing the invalidate
371: @param lcc The LanguageConnectionContext
372:
373: @exception StandardException thrown if unable to make it invalid
374: */
375: void invalidateFor(Provider p, int action,
376: LanguageConnectionContext lcc) throws StandardException;
377:
378: /**
379: Erases all of the dependencies the dependent has, be they
380: valid or invalid, of any dependency type. This action is
381: usually performed as the first step in revalidating a
382: dependent; it first erases all the old dependencies, then
383: revalidates itself generating a list of new dependencies,
384: and then marks itself valid if all its new dependencies are
385: valid.
386: <p>
387: There might be a future want to clear all dependencies for
388: a particular provider, e.g. when destroying the provider.
389: However, at present, they are assumed to stick around and
390: it is the responsibility of the dependent to erase them when
391: revalidating against the new version of the provider.
392: <p>
393: clearDependencies will delete dependencies if they are
394: stored; the delete is finalized at the next commit.
395:
396: @param lcc Compiler state
397: @param d the dependent
398: *
399: * @exception StandardException Thrown on failure
400: */
401: void clearDependencies(LanguageConnectionContext lcc, Dependent d)
402: 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: * Copy dependencies from one dependent to another.
447: *
448: * @param copy_From the dependent to copy from
449: * @param copyTo the dependent to copy to
450: * @param persistentOnly only copy persistent dependencies
451: * @param cm Current ContextManager
452: *
453: * @exception StandardException Thrown on error.
454: */
455: public void copyDependencies(Dependent copy_From, Dependent copyTo,
456: boolean persistentOnly, ContextManager cm)
457: throws StandardException;
458:
459: /**
460: * Returns a string representation of the SQL action, hence no
461: * need to internationalize, which is causing the invokation
462: * of the Dependency Manager.
463: *
464: * @param action The action
465: *
466: * @return String The String representation
467: */
468: String getActionString(int action);
469:
470: /**
471: * Count the number of active dependencies, both stored and in memory,
472: * in the system.
473: *
474: * @return int The number of active dependencies in the system.
475:
476: @exception StandardException thrown if something goes wrong
477: */
478: public int countDependencies() throws StandardException;
479:
480: /**
481: * Dump out debugging info on all of the dependencies currently
482: * within the system.
483: *
484: * @return String Debugging info on the dependencies.
485: * (null if SanityManger.DEBUG is false)
486:
487: @exception StandardException thrown if something goes wrong
488: @exception java.sql.SQLException thrown if something goes wrong
489: */
490: public String dumpDependencies() throws StandardException,
491: java.sql.SQLException;
492:
493: /**
494: Erases all of the dependencies the dependent has, be they
495: valid or invalid, of any dependency type. This action is
496: usually performed as the first step in revalidating a
497: dependent; it first erases all the old dependencies, then
498: revalidates itself generating a list of new dependencies,
499: and then marks itself valid if all its new dependencies are
500: valid.
501: <p>
502: There might be a future want to clear all dependencies for
503: a particular provider, e.g. when destroying the provider.
504: However, at present, they are assumed to stick around and
505: it is the responsibility of the dependent to erase them when
506: revalidating against the new version of the provider.
507: <p>
508: clearDependencies will delete dependencies if they are
509: stored; the delete is finalized at the next commit.
510:
511: @param lcc Compiler state
512: @param d the dependent
513: @param tc transaction controller
514:
515: @exception StandardException Thrown on failure
516: */
517: public void clearDependencies(LanguageConnectionContext lcc,
518: Dependent d, TransactionController tc)
519: throws StandardException;
520:
521: /**
522: * Copy dependencies from one dependent to another.
523: *
524: * @param copy_From the dependent to copy from
525: * @param copyTo the dependent to copy to
526: * @param persistentOnly only copy persistent dependencies
527: * @param cm Current ContextManager
528: * @param tc Transaction Controller
529: *
530: * @exception StandardException Thrown on error.
531: */
532: public void copyDependencies(Dependent copy_From, Dependent copyTo,
533: boolean persistentOnly, ContextManager cm,
534: TransactionController tc) throws StandardException;
535:
536: }
|