示例#1
0
  public void repair() {
    if (!table.existsNoQuotes() && !table.exists()) {
      LOG.info(
          "Repair of metadata table " + table + " not necessary. No failed migration detected.");
      return;
    }

    createIfNotExists();

    try {
      int failedCount =
          jdbcTemplate.queryForInt(
              "SELECT COUNT(*) FROM "
                  + table
                  + " WHERE "
                  + dbSupport.quote("success")
                  + "="
                  + dbSupport.getBooleanFalse());
      if (failedCount == 0) {
        LOG.info(
            "Repair of metadata table " + table + " not necessary. No failed migration detected.");
        return;
      }
    } catch (SQLException e) {
      throw new FlywayException(
          "Unable to check the metadata table " + table + " for failed migrations", e);
    }

    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    try {
      jdbcTemplate.execute(
          "DELETE FROM "
              + table
              + " WHERE "
              + dbSupport.quote("success")
              + " = "
              + dbSupport.getBooleanFalse());
    } catch (SQLException e) {
      throw new FlywayException("Unable to repair metadata table " + table, e);
    }

    stopWatch.stop();

    LOG.info(
        "Metadata table "
            + table
            + " successfully repaired (execution time "
            + TimeFormat.format(stopWatch.getTotalTimeMillis())
            + ").");
    LOG.info("Manual cleanup of the remaining effects the failed migration may still be required.");
  }
示例#2
0
  /** Creates the metatable if it doesn't exist, upgrades it if it does. */
  private void createIfNotExists() {
    if (table.existsNoQuotes() || table.exists()) {
      if (!upgraded) {
        new MetaDataTableTo20FormatUpgrader(dbSupport, table, migrationResolver).upgrade();
        new MetaDataTableTo202FormatUpgrader(dbSupport, table).upgrade();
        upgraded = true;
      }
      return;
    }

    LOG.info("Creating Metadata table: " + table);

    final String source =
        new ClassPathResource(dbSupport.getScriptLocation() + "createMetaDataTable.sql")
            .loadAsString("UTF-8");

    Map<String, String> placeholders = new HashMap<String, String>();
    placeholders.put("schema", table.getSchema().getName());
    placeholders.put("table", table.getName());
    final String sourceNoPlaceholders =
        new PlaceholderReplacer(placeholders, "${", "}").replacePlaceholders(source);

    SqlScript sqlScript = new SqlScript(sourceNoPlaceholders, dbSupport);
    sqlScript.execute(jdbcTemplate);

    LOG.debug("Metadata table " + table + " created.");
  }
示例#3
0
  public boolean hasInitMarker() {
    if (!table.existsNoQuotes() && !table.exists()) {
      return false;
    }

    createIfNotExists();

    try {
      int count =
          jdbcTemplate.queryForInt(
              "SELECT COUNT(*) FROM " + table + " WHERE " + dbSupport.quote("type") + "='INIT'");
      return count > 0;
    } catch (SQLException e) {
      throw new FlywayException(
          "Unable to check whether the metadata table " + table + " has an init marker migration",
          e);
    }
  }
示例#4
0
  /**
   * Calculate the rank for this new version about to be inserted.
   *
   * @param version The version to calculated for.
   * @return The rank.
   */
  private int calculateVersionRank(MigrationVersion version) throws SQLException {
    List<String> versions =
        jdbcTemplate.queryForStringList("select " + dbSupport.quote("version") + " from " + table);

    List<MigrationVersion> migrationVersions = new ArrayList<MigrationVersion>();
    for (String versionStr : versions) {
      migrationVersions.add(new MigrationVersion(versionStr));
    }

    Collections.sort(migrationVersions);

    for (int i = 0; i < migrationVersions.size(); i++) {
      if (version.compareTo(migrationVersions.get(i)) < 0) {
        return i + 1;
      }
    }

    return migrationVersions.size() + 1;
  }
示例#5
0
  public boolean hasAppliedMigrations() {
    if (!table.existsNoQuotes() && !table.exists()) {
      return false;
    }

    createIfNotExists();

    try {
      int count =
          jdbcTemplate.queryForInt(
              "SELECT COUNT(*) FROM "
                  + table
                  + " WHERE "
                  + dbSupport.quote("type")
                  + " NOT IN ('SCHEMA', 'INIT')");
      return count > 0;
    } catch (SQLException e) {
      throw new FlywayException(
          "Unable to check whether the metadata table " + table + " has applied migrations", e);
    }
  }
示例#6
0
  public MigrationVersion getCurrentSchemaVersion() {
    if (!table.existsNoQuotes() && !table.exists()) {
      return MigrationVersion.EMPTY;
    }

    try {
      if (jdbcTemplate.queryForInt("SELECT COUNT(*) FROM " + table) == 0) {
        return MigrationVersion.EMPTY;
      }
    } catch (SQLException e) {
      throw new FlywayException(
          "Error checking if the metadata table " + table + " has at least one row", e);
    }

    createIfNotExists();

    // Determine the version associated with the highest version_rank
    String query =
        "SELECT t1."
            + dbSupport.quote("version")
            + " FROM "
            + table
            + " t1"
            + " LEFT OUTER JOIN "
            + table
            + " t2 ON"
            + " (t1."
            + dbSupport.quote("version")
            + " = t2."
            + dbSupport.quote("version")
            + " AND t1."
            + dbSupport.quote("version_rank")
            + " < t2."
            + dbSupport.quote("version_rank")
            + ")"
            + " WHERE t2."
            + dbSupport.quote("version")
            + " IS NULL";
    try {
      String version = jdbcTemplate.queryForString(query);
      return new MigrationVersion(version);
    } catch (SQLException e) {
      throw new FlywayException(
          "Error determining current schema version from metadata table " + table, e);
    }
  }
示例#7
0
 /**
  * Creates a new instance of the metadata table support.
  *
  * @param dbSupport Database-specific functionality.
  * @param table The metadata table used by flyway.
  * @param migrationResolver For resolving available migrations.
  */
 public MetaDataTableImpl(DbSupport dbSupport, Table table, MigrationResolver migrationResolver) {
   this.jdbcTemplate = dbSupport.getJdbcTemplate();
   this.dbSupport = dbSupport;
   this.table = table;
   this.migrationResolver = migrationResolver;
 }
示例#8
0
  public List<AppliedMigration> allAppliedMigrations() {
    if (!table.existsNoQuotes() && !table.exists()) {
      return new ArrayList<AppliedMigration>();
    }

    createIfNotExists();

    String query =
        "SELECT "
            + dbSupport.quote("version_rank")
            + ","
            + dbSupport.quote("installed_rank")
            + ","
            + dbSupport.quote("version")
            + ","
            + dbSupport.quote("description")
            + ","
            + dbSupport.quote("type")
            + ","
            + dbSupport.quote("script")
            + ","
            + dbSupport.quote("checksum")
            + ","
            + dbSupport.quote("installed_on")
            + ","
            + dbSupport.quote("installed_by")
            + ","
            + dbSupport.quote("execution_time")
            + ","
            + dbSupport.quote("success")
            + " FROM "
            + table
            + " ORDER BY "
            + dbSupport.quote("version_rank");

    try {
      return jdbcTemplate.query(
          query,
          new RowMapper<AppliedMigration>() {
            public AppliedMigration mapRow(final ResultSet rs) throws SQLException {
              return new AppliedMigration(
                  rs.getInt("version_rank"),
                  rs.getInt("installed_rank"),
                  new MigrationVersion(rs.getString("version")),
                  rs.getString("description"),
                  MigrationType.valueOf(rs.getString("type")),
                  rs.getString("script"),
                  toInteger((Number) rs.getObject("checksum")),
                  rs.getTimestamp("installed_on"),
                  rs.getString("installed_by"),
                  toInteger((Number) rs.getObject("execution_time")),
                  rs.getBoolean("success"));
            }
          });
    } catch (SQLException e) {
      throw new FlywayException(
          "Error while retrieving the list of applied migrations from metadata table " + table, e);
    }
  }
示例#9
0
 /**
  * Calculates the installed rank for the new migration to be inserted.
  *
  * @return The installed rank.
  */
 private int calculateInstalledRank() throws SQLException {
   int currentMax =
       jdbcTemplate.queryForInt(
           "SELECT MAX(" + dbSupport.quote("installed_rank") + ")" + " FROM " + table);
   return currentMax + 1;
 }
示例#10
0
  public void addAppliedMigration(AppliedMigration appliedMigration) {
    createIfNotExists();

    MigrationVersion version = appliedMigration.getVersion();
    try {
      int versionRank = calculateVersionRank(version);

      jdbcTemplate.update(
          "UPDATE "
              + table
              + " SET "
              + dbSupport.quote("version_rank")
              + " = "
              + dbSupport.quote("version_rank")
              + " + 1 WHERE "
              + dbSupport.quote("version_rank")
              + " >= ?",
          versionRank);
      jdbcTemplate.update(
          "INSERT INTO "
              + table
              + " ("
              + dbSupport.quote("version_rank")
              + ","
              + dbSupport.quote("installed_rank")
              + ","
              + dbSupport.quote("version")
              + ","
              + dbSupport.quote("description")
              + ","
              + dbSupport.quote("type")
              + ","
              + dbSupport.quote("script")
              + ","
              + dbSupport.quote("checksum")
              + ","
              + dbSupport.quote("installed_by")
              + ","
              + dbSupport.quote("execution_time")
              + ","
              + dbSupport.quote("success")
              + ")"
              + " VALUES (?, ?, ?, ?, ?, ?, ?, "
              + dbSupport.getCurrentUserFunction()
              + ", ?, ?)",
          versionRank,
          calculateInstalledRank(),
          version.toString(),
          appliedMigration.getDescription(),
          appliedMigration.getType().name(),
          appliedMigration.getScript(),
          appliedMigration.getChecksum(),
          appliedMigration.getExecutionTime(),
          appliedMigration.isSuccess());
      LOG.debug("MetaData table " + table + " successfully updated to reflect changes");
    } catch (SQLException e) {
      throw new FlywayException(
          "Unable to insert row for version '" + version + "' in metadata table " + table, e);
    }
  }
示例#11
0
  /**
   * Applies this migration to the database. The migration state and the execution time are updated
   * accordingly.
   *
   * @param migration The migration to apply.
   * @param isOutOfOrder If this migration is being applied out of order.
   * @return The result of the migration.
   */
  private MigrationVersion applyMigration(final ResolvedMigration migration, boolean isOutOfOrder) {
    MigrationVersion version = migration.getVersion();
    if (isOutOfOrder) {
      LOG.info("Migrating schema " + schema + " to version " + version + " (out of order)");
    } else {
      LOG.info("Migrating schema " + schema + " to version " + version);
    }

    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    try {
      new TransactionTemplate(connectionUserObjects)
          .execute(
              new TransactionCallback<Void>() {
                public Void doInTransaction() {
                  migration.getExecutor().execute(connectionUserObjects);
                  return null;
                }
              });
      LOG.debug(
          "Successfully completed and committed migration of schema "
              + schema
              + " to version "
              + version);
    } catch (FlywayException e) {
      String failedMsg = "Migration of schema " + schema + " to version " + version + " failed!";
      if (dbSupport.supportsDdlTransactions()) {
        LOG.error(failedMsg + " Changes successfully rolled back.");
      } else {
        LOG.error(failedMsg + " Please restore backups and roll back database and code!");

        stopWatch.stop();
        int executionTime = (int) stopWatch.getTotalTimeMillis();
        AppliedMigration appliedMigration =
            new AppliedMigration(
                version,
                migration.getDescription(),
                migration.getType(),
                migration.getScript(),
                migration.getChecksum(),
                executionTime,
                false);
        metaDataTable.addAppliedMigration(appliedMigration);
      }
      throw e;
    }

    stopWatch.stop();
    int executionTime = (int) stopWatch.getTotalTimeMillis();

    AppliedMigration appliedMigration =
        new AppliedMigration(
            version,
            migration.getDescription(),
            migration.getType(),
            migration.getScript(),
            migration.getChecksum(),
            executionTime,
            true);
    metaDataTable.addAppliedMigration(appliedMigration);

    return version;
  }