/**
   * Executes the given script and updates the database execution registry appropriately. If
   * successfully, the script execution is registered in the database and marked as successful. If
   * an error occurred executing the script, the script execution is registered in the database and
   * marked as unsuccessful.
   *
   * @param script The script to execute, not null
   */
  protected void executeScript(Script script) {
    try {
      // We register the script execution, but we indicate it to be unsuccessful. If anything goes
      // wrong or if the update is
      // interrupted before being completed, this will be the final state and the DbMaintainer will
      // do a from-scratch update the next time
      ExecutedScript executedScript = new ExecutedScript(script, new Date(), false);
      executedScriptInfoSource.registerExecutedScript(executedScript);

      scriptRunner.execute(script);
      // We now register the previously registered script execution as being successful
      executedScript.setSuccessful(true);
      executedScriptInfoSource.updateExecutedScript(executedScript);

    } catch (DbMaintainException e) {
      String message = getErrorMessage(script, e);
      throw new DbMaintainException(message, e.getCause());
    }
  }
  protected String getErrorMessage(Script script, DbMaintainException e) {
    String exceptionMessage = e.getMessage();
    Throwable cause = e.getCause();
    if (cause != null) {
      exceptionMessage += "\n\nCaused by: " + cause.getMessage();
      if (cause instanceof SQLException) {
        SQLException sqlException = (SQLException) cause;
        if (!exceptionMessage.endsWith("\n")) {
          exceptionMessage += "\n";
        }
        exceptionMessage +=
            "Error code: "
                + sqlException.getErrorCode()
                + ", sql state: "
                + sqlException.getSQLState();
      }
    }

    String message =
        "\nError while executing script " + script.getFileName() + ": " + exceptionMessage + "\n\n";
    message +=
        "A rollback was performed but there could still be changes that were committed in the database (for example a creation of a table).\n"
            + getErrorScriptOptionsMessage(script)
            + "\n\n";
    if (maxNrOfCharsWhenLoggingScriptContent > 0) {
      String scriptContents =
          script
              .getScriptContentHandle()
              .getScriptContentsAsString(maxNrOfCharsWhenLoggingScriptContent);
      message += "Full contents of failed script " + script.getFileName() + ":\n";
      message += "----------------------------------------------------\n";
      message += scriptContents + "\n";
      message += "----------------------------------------------------\n";
    }
    return message;
  }