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 public static final int DROP_COLUMN_RESTRICT = 46; 328 329 // Revoke action when a granted role is dropped/revoked. A revoke statement 330 // causes the dependents to drop. 331 public static final int REVOKE_ROLE = 47; 332 333 // Action when the current role is changed in a session. Used to force 334 // rechecking of privileges for prepared statements that depend on the 335 // current role for privileges by recreating the activation. 336 public static final int RECHECK_PRIVILEGES = 48; 337 338 /** 339 * Extensions to this interface may use action codes > MAX_ACTION_CODE without fear of 340 * clashing with action codes in this base interface. 341 */ 342 public static final int MAX_ACTION_CODE = 0XFFFF; 343 344 /** 345 adds a dependency from the dependent on the provider. 346 This will be considered to be the default type of 347 dependency, when dependency types show up. 348 <p> 349 Implementations of addDependency should be fast -- 350 performing alot of extra actions to add a dependency would 351 be a detriment. 352 353 @param d the dependent 354 @param p the provider 355 @param cm Current ContextManager 356 357 @exception StandardException thrown if something goes wrong 358 */ 359 void addDependency(Dependent d, Provider p, ContextManager cm) throws StandardException; 360 361 /** 362 mark all dependencies on the named provider as invalid. 363 When invalidation types show up, this will use the default 364 invalidation type. The dependencies will still exist once 365 they are marked invalid; clearDependencies should be used 366 to remove dependencies that a dependent has or provider gives. 367 <p> 368 Implementations of this can take a little time, but are not 369 really expected to recompile things against any changes 370 made to the provider that caused the invalidation. The 371 dependency system makes no guarantees about the state of 372 the provider -- implementations can call this before or 373 after actually changing the provider to its new state. 374 <p> 375 Implementations should throw DependencyStatementException 376 if the invalidation should be disallowed. 377 378 @param p the provider 379 @param action The action causing the invalidate 380 @param lcc The LanguageConnectionContext 381 382 @exception StandardException thrown if unable to make it invalid 383 */ 384 void invalidateFor(Provider p, int action, LanguageConnectionContext lcc) 385 throws StandardException; 386 387 388 389 /** 390 Erases all of the dependencies the dependent has, be they 391 valid or invalid, of any dependency type. This action is 392 usually performed as the first step in revalidating a 393 dependent; it first erases all the old dependencies, then 394 revalidates itself generating a list of new dependencies, 395 and then marks itself valid if all its new dependencies are 396 valid. 397 <p> 398 There might be a future want to clear all dependencies for 399 a particular provider, e.g. when destroying the provider. 400 However, at present, they are assumed to stick around and 401 it is the responsibility of the dependent to erase them when 402 revalidating against the new version of the provider. 403 <p> 404 clearDependencies will delete dependencies if they are 405 stored; the delete is finalized at the next commit. 406 407 @param lcc Compiler state 408 @param d the dependent 409 * 410 * @exception StandardException Thrown on failure 411 */ 412 void clearDependencies(LanguageConnectionContext lcc, Dependent d) throws StandardException; 413 414 /** 415 * Clear the specified in memory dependency. 416 * This is useful for clean-up when an exception occurs. 417 * (We clear all in-memory dependencies added in the current 418 * StatementContext.) 419 This method will handle Dependency's that have already been 420 removed from the DependencyManager. 421 */ 422 public void clearInMemoryDependency(Dependency dy); 423 424 /** 425 * Get a new array of ProviderInfos representing all the persistent 426 * providers for the given dependent. 427 * 428 * @exception StandardException Thrown on error. 429 */ 430 public ProviderInfo[] getPersistentProviderInfos(Dependent dependent) 431 throws StandardException; 432 433 /** 434 * Get a new array of ProviderInfos representing all the persistent 435 * providers from the given list of providers. 436 * 437 * @exception StandardException Thrown on error. 438 */ 439 public ProviderInfo[] getPersistentProviderInfos(ProviderList pl) 440 throws StandardException; 441 442 /** 443 * Clear the in memory column bit map information in any table descriptor 444 * provider in a provider list. This function needs to be called before 445 * the table descriptor is reused as provider in column dependency. For 446 * example, this happens in "create publication" statement with target-only 447 * DDL where more than one views are defined and they all reference one 448 * table. 449 * 450 * @exception StandardException Thrown on error. 451 */ 452 public void clearColumnInfoInProviders(ProviderList pl) 453 throws StandardException; 454 455 456 /** 457 * Copy dependencies from one dependent to another. 458 * 459 * @param copy_From the dependent to copy from 460 * @param copyTo the dependent to copy to 461 * @param persistentOnly only copy persistent dependencies 462 * @param cm Current ContextManager 463 * 464 * @exception StandardException Thrown on error. 465 */ 466 public void copyDependencies( 467 Dependent copy_From, 468 Dependent copyTo, 469 boolean persistentOnly, 470 ContextManager cm) 471 throws StandardException; 472 473 /** 474 * Returns a string representation of the SQL action, hence no 475 * need to internationalize, which is causing the invokation 476 * of the Dependency Manager. 477 * 478 * @param action The action 479 * 480 * @return String The String representation 481 */ 482 String getActionString(int action); 483 484 /** 485 * Count the number of active dependencies, both stored and in memory, 486 * in the system. 487 * 488 * @return int The number of active dependencies in the system. 489 490 @exception StandardException thrown if something goes wrong 491 */ 492 public int countDependencies() throws StandardException; 493 494 /** 495 * Dump out debugging info on all of the dependencies currently 496 * within the system. 497 * 498 * @return String Debugging info on the dependencies. 499 * (null if SanityManger.DEBUG is false) 500 501 @exception StandardException thrown if something goes wrong 502 @exception java.sql.SQLException thrown if something goes wrong 503 */ 504 public String dumpDependencies() throws StandardException, java.sql.SQLException; 505 506 /** 507 Erases all of the dependencies the dependent has, be they 508 valid or invalid, of any dependency type. This action is 509 usually performed as the first step in revalidating a 510 dependent; it first erases all the old dependencies, then 511 revalidates itself generating a list of new dependencies, 512 and then marks itself valid if all its new dependencies are 513 valid. 514 <p> 515 There might be a future want to clear all dependencies for 516 a particular provider, e.g. when destroying the provider. 517 However, at present, they are assumed to stick around and 518 it is the responsibility of the dependent to erase them when 519 revalidating against the new version of the provider. 520 <p> 521 clearDependencies will delete dependencies if they are 522 stored; the delete is finalized at the next commit. 523 524 @param lcc Compiler state 525 @param d the dependent 526 @param tc transaction controller 527 528 @exception StandardException Thrown on failure 529 */ 530 public void clearDependencies(LanguageConnectionContext lcc, 531 Dependent d, 532 TransactionController tc) 533 throws StandardException; 534 535 536 /** 537 * Copy dependencies from one dependent to another. 538 * 539 * @param copy_From the dependent to copy from 540 * @param copyTo the dependent to copy to 541 * @param persistentOnly only copy persistent dependencies 542 * @param cm Current ContextManager 543 * @param tc Transaction Controller 544 * 545 * @exception StandardException Thrown on error. 546 */ 547 public void copyDependencies( 548 Dependent copy_From, 549 Dependent copyTo, 550 boolean persistentOnly, 551 ContextManager cm, 552 TransactionController tc) 553 throws StandardException; 554 555 }