/** * Executes the given scripts and updates the database execution registry appropriately. After * each successful script execution, the script execution is registered in the database and marked * as successful. If a script execution fails, the script execution is registered in the database * and marked as unsuccessful. * * @param scriptUpdates the script updates to be executed */ protected void executeScriptUpdates(SortedSet<ScriptUpdate> scriptUpdates) { scriptRunner.initialize(); try { for (ScriptUpdate scriptUpdate : scriptUpdates) { long startTimeMs = currentTimeMillis(); executeScript(scriptUpdate.getScript()); long durationMs = currentTimeMillis() - startTimeMs; logger.info( "Executed " + scriptUpdatesFormatter.formatScriptUpdate(scriptUpdate) + " (" + durationMs + " ms)"); } } finally { scriptRunner.close(); } }
/** * This operation can be used to bring the database to the latest version. First it checks which * scripts were already applied to the database and executes the new scripts or the updated * repeatable scripts. If an existing incremental script was changed, removed, or if a new * incremental script has been added with a lower index than one that was already executed, an * error is given; unless the <fromScratch> option is enabled: in that case all database objects * at the end. * * @param dryRun if true, no updates have to be performed on the database - we do a simulation of * the database update instead of actually performing the database update. * @return whether updates were performed on the database */ public boolean updateDatabase(boolean dryRun) { try { ScriptUpdates scriptUpdates = getScriptUpdates(); if (!getIncrementalScriptsThatFailedDuringLastUpdate().isEmpty() && !scriptUpdates.hasIrregularScriptUpdates()) { ExecutedScript failedExecutedScriptScript = getIncrementalScriptsThatFailedDuringLastUpdate().first(); throw new DbMaintainException( "During the latest update, the execution of the following incremental script failed: " + failedExecutedScriptScript + ". \nThis problem must be fixed before any other " + "updates can be performed.\n" + getErrorScriptOptionsMessage(failedExecutedScriptScript.getScript())); } if (!getRepeatableScriptsThatFailedDuringLastUpdate().isEmpty() && !scriptUpdates.hasIrregularScriptUpdates()) { ExecutedScript failedScript = getRepeatableScriptsThatFailedDuringLastUpdate().first(); if (!scriptUpdates .getRegularlyAddedOrModifiedScripts() .contains(new ScriptUpdate(REPEATABLE_SCRIPT_UPDATED, failedScript.getScript())) && !scriptUpdates .getRegularlyDeletedRepeatableScripts() .contains(new ScriptUpdate(REPEATABLE_SCRIPT_DELETED, failedScript.getScript()))) { throw new DbMaintainException( "During the latest update, the execution of following repeatable script failed: " + getRepeatableScriptsThatFailedDuringLastUpdate().first() + ". \nThis problem must be fixed " + "before any other updates can be performed."); } } if (scriptUpdates.isEmpty()) { logger.info("The database is up to date"); return false; } boolean recreateFromScratch = false; if (fromScratchEnabled && isInitialDatabaseUpdate()) { logger.info( "The database is updated for the first time. The database is cleared to be sure that we start with a clean database"); recreateFromScratch = true; } if (scriptUpdates.hasIrregularScriptUpdates()) { if (fromScratchEnabled) { // Recreate the database from scratch logger.info( "The database is recreated from scratch, since following irregular script updates were detected:\n" + scriptUpdatesFormatter.formatScriptUpdates( scriptUpdates.getIrregularScriptUpdates())); recreateFromScratch = true; } else { throw new DbMaintainException( "Following irregular script updates were detected:\n" + scriptUpdatesFormatter.formatScriptUpdates( scriptUpdates.getIrregularScriptUpdates()) + "\nBecause of this, dbmaintain can't perform the update. To solve this problem, you can do one of the following:\n" + " 1: Revert the irregular updates and use regular script updates instead\n" + " 2: Enable the fromScratch option so that the database is recreated from scratch (all data will be lost)\n" + " 3: Perform the updates manually on the database and invoke the markDatabaseAsUpToDate operation (error prone)\n"); } } if (recreateFromScratch) { if (baseLineRevision != null) { throw new DbMaintainException( "Unable to recreate the database from scratch: a baseline revision is set.\n" + "After clearing the database only scripts starting from the baseline revision would have been executed. The other scripts would have been ignored resulting in an inconsistent database state.\n" + "Please clear the baseline revision if you want to perform a from scratch update.\n" + "Another option is to explicitly clear the database using the clear task and then performing the update."); } logger.info("The database is cleared, and all database scripts are executed."); if (!dryRun) { dbClearer.clearDatabase(); executedScriptInfoSource.resetCachedState(); executeScripts(scriptRepository.getAllUpdateScripts()); } } else { logger.info( "The database is updated incrementally, since following regular script updates were detected:\n" + scriptUpdatesFormatter.formatScriptUpdates( scriptUpdates.getRegularScriptUpdates())); if (!dryRun) { // If the disable constraints option is enabled, disable all FK and not null constraints if (disableConstraints) { constraintsDisabler.disableConstraints(); } // If cleandb is enabled, remove all data from the database. if (cleanDb) { dbCleaner.cleanDatabase(); } // If there are incremental patch scripts with a lower index and the option // allowOutOfSequenceExecutionOfPatches // is enabled, execute them first executeScriptUpdates(scriptUpdates.getRegularlyAddedPatchScripts()); // Execute all new incremental and all new or modified repeatable scripts executeScriptUpdates(scriptUpdates.getRegularlyAddedOrModifiedScripts()); // If repeatable scripts were removed, also remove them from the executed scripts removeDeletedRepeatableScriptsFromExecutedScripts( scriptUpdates.getRegularlyDeletedRepeatableScripts()); // If regular script renames were detected, update the executed script records to reflect // this performRegularScriptRenamesInExecutedScripts(scriptUpdates.getRegularlyRenamedScripts()); } } if (scriptUpdates.noUpdatesOtherThanRepeatableScriptDeletionsOrRenames()) { logger.info( "No script updates were detected, except for repeatable script deletions and script renames. Therefore, actions such as the execution of postprocessing scripts and disabling the constraints are skipped."); return false; } if (!dryRun) { // Execute all post processing scripts executePostprocessingScripts(); // If the disable constraints option is enabled, disable all FK and not null constraints if (disableConstraints) { constraintsDisabler.disableConstraints(); } // the scripts could have added data, if cleandb is enabled, remove all data from the // database. if (cleanDb) { dbCleaner.cleanDatabase(); } // If the update sequences option is enabled, update all sequences to have a value equal to // or higher than the configured threshold if (updateSequences) { sequenceUpdater.updateSequences(); } logger.info("The database has been updated successfully."); } return true; } finally { sqlHandler.closeAllConnections(); } }