Example #1
0
 public boolean isSameAs(ChangeSet changeSet) {
   return this.getChangeLog()
           .replace('\\', '/')
           .equalsIgnoreCase(changeSet.getFilePath().replace('\\', '/'))
       && this.getId().equalsIgnoreCase(changeSet.getId())
       && this.getAuthor().equalsIgnoreCase(changeSet.getAuthor());
 }
  public void printNonRenames(DatabaseSnapshot reference, DatabaseSnapshot target, StringBuilder sb)
      throws Exception {
    CompareControl compareControl =
        new CompareControl(reference.getSnapshotControl().getTypesToInclude());
    DiffResult diffResult =
        DiffGeneratorFactory.getInstance().compare(reference, target, compareControl);

    DiffToChangeLog diffToChangeLog =
        new DiffToChangeLog(diffResult, new DiffOutputControl(false, false, false));

    SqlGeneratorFactory generatorFactory = SqlGeneratorFactory.getInstance();
    for (ChangeSet changeSet : diffToChangeLog.generateChangeSets()) {
      for (Change change : changeSet.getChanges()) {
        for (SqlStatement sqlStatement :
            change.generateStatements(LiquibaseModelFactory.DATABASE)) {
          for (Sql sql :
              generatorFactory.generateSql(sqlStatement, LiquibaseModelFactory.DATABASE)) {

            final String sqlString = sql.toSql();
            if (sqlString.endsWith("DROP INDEX")) {
              sb.append(StringUtils.substringBefore(sqlString, " DROP INDEX")).append(";\n");
            } else {
              sb.append(sqlString).append(";\n");
            }
          }
        }
      }
    }
  }
Example #3
0
 public RanChangeSet(ChangeSet changeSet, ChangeSet.ExecType execType) {
   this(
       changeSet.getFilePath(),
       changeSet.getId(),
       changeSet.getAuthor(),
       changeSet.generateCheckSum(),
       new Date(),
       null,
       execType,
       changeSet.getDescription());
 }
  @Test
  public void parseAndGenerate() throws Exception {
    Database database = liquiBase.getDatabase();
    ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor();

    ChangeLogParameters changeLogParameters = new ChangeLogParameters();

    DatabaseChangeLog changeLog =
        ChangeLogParserFactory.getInstance()
            .getParser(changeLogFile, resourceAccessor)
            .parse(changeLogFile, changeLogParameters, resourceAccessor);

    database.checkDatabaseChangeLogTable(false, changeLog, null);
    changeLog.validate(database);

    List<ChangeSet> changeSets = changeLog.getChangeSets();

    List<String> expectedQuery = new ArrayList<String>();

    expectedQuery.add(
        "MERGE INTO LIQUIBASE.myTable2 m "
            + "USING LIQUIBASE.myTable d "
            + "ON (m.pid=d.pid) "
            + "WHEN MATCHED THEN UPDATE SET m.sales=m.sales+d.sales,m.status=d.status "
            + "DELETE WHERE (m.status='OBS') "
            + "WHEN NOT MATCHED THEN INSERT VALUES(d.pid,d.sales,'OLD')");

    int i = 0;

    for (ChangeSet changeSet : changeSets) {
      for (Change change : changeSet.getChanges()) {
        Sql[] sql =
            SqlGeneratorFactory.getInstance()
                .generateSql(change.generateStatements(database)[0], database);
        if (i == 3) {
          assertEquals(expectedQuery.get(0), sql[0].toSql());
        }
      }
      i++;
    }
  }
 @Override
 public void check(Database database, DatabaseChangeLog changeLog, ChangeSet changeSet)
     throws PreconditionFailedException, PreconditionErrorException {
   ObjectQuotingStrategy objectQuotingStrategy = null;
   if (changeSet == null) {
     objectQuotingStrategy = ObjectQuotingStrategy.LEGACY;
   } else {
     objectQuotingStrategy = changeSet.getObjectQuotingStrategy();
   }
   String changeLogFile = getChangeLogFile();
   if (changeLogFile == null) {
     changeLogFile = changeLog.getLogicalFilePath();
   }
   ChangeSet interestedChangeSet =
       new ChangeSet(
           getId(),
           getAuthor(),
           false,
           false,
           changeLogFile,
           null,
           null,
           false,
           objectQuotingStrategy,
           changeLog);
   RanChangeSet ranChangeSet;
   try {
     ranChangeSet = database.getRanChangeSet(interestedChangeSet);
   } catch (Exception e) {
     throw new PreconditionErrorException(e, changeLog, this);
   }
   if (ranChangeSet == null
       || ranChangeSet.getExecType() == null
       || !ranChangeSet.getExecType().ran) {
     throw new PreconditionFailedException(
         "Change Set '" + interestedChangeSet.toString(false) + "' has not been run",
         changeLog,
         this);
   }
 }
Example #6
0
  /** Returns the run status for the given ChangeSet */
  @Override
  public ChangeSet.RunStatus getRunStatus(ChangeSet changeSet)
      throws DatabaseException, DatabaseHistoryException {
    if (!hasDatabaseChangeLogTable()) {
      return ChangeSet.RunStatus.NOT_RAN;
    }

    RanChangeSet foundRan = getRanChangeSet(changeSet);

    if (foundRan == null) {
      return ChangeSet.RunStatus.NOT_RAN;
    } else {
      if (foundRan.getLastCheckSum() == null) {
        try {
          LogFactory.getLogger().info("Updating NULL md5sum for " + changeSet.toString());
          ExecutorService.getInstance()
              .getExecutor(this)
              .execute(
                  new RawSqlStatement(
                      "UPDATE "
                          + escapeTableName(
                              getLiquibaseSchemaName(), getDatabaseChangeLogTableName())
                          + " SET MD5SUM='"
                          + changeSet.generateCheckSum().toString()
                          + "' WHERE ID='"
                          + changeSet.getId()
                          + "' AND AUTHOR='"
                          + changeSet.getAuthor()
                          + "' AND FILENAME='"
                          + changeSet.getFilePath()
                          + "'"));

          this.commit();
        } catch (DatabaseException e) {
          throw new DatabaseException(e);
        }

        return ChangeSet.RunStatus.ALREADY_RAN;
      } else {
        if (foundRan.getLastCheckSum().equals(changeSet.generateCheckSum())) {
          return ChangeSet.RunStatus.ALREADY_RAN;
        } else {
          if (changeSet.shouldRunOnChange()) {
            return ChangeSet.RunStatus.RUN_AGAIN;
          } else {
            return ChangeSet.RunStatus.INVALID_MD5SUM;
            // throw new DatabaseHistoryException("MD5 Check for " + changeSet.toString() + "
            // failed");
          }
        }
      }
    }
  }
  @Override
  public void setExecType(ChangeSet changeSet, ChangeSet.ExecType execType, Scope scope)
      throws LiquibaseException {
    Logger log = LoggerFactory.getLogger(getClass());
    if (execType == ChangeSet.ExecType.FAILED) {
      log.info("Not marking failed changeSet as ran");
      return;
    }
    if (execType == ChangeSet.ExecType.SKIPPED) {
      log.info("Not marking skipped changeSet as ran");
      return;
    }

    Map<String, Object> data = new LinkedHashMap<>();

    data.put(correctCase("id"), changeSet.id);
    data.put(correctCase("author"), changeSet.author);
    data.put(correctCase("filename"), changeSet.getPath());

    data.put(correctCase("dateexecuted"), scope.getDatabase().getCurrentDateTimeFunction(scope));
    data.put(correctCase("md5sum"), "TODO");
    data.put(correctCase("exectype"), execType.value);
    data.put(correctCase("dateexecuted"), scope.getDatabase().getCurrentDateTimeFunction(scope));
    data.put(correctCase("orderexecuted"), 1); // todo
    data.put(correctCase("description"), "TODO"); // todo
    data.put(correctCase("comments"), "TODO"); // todo
    data.put(correctCase("contexts"), "TODO"); // todo
    data.put(correctCase("labels"), "TODO"); // todo
    data.put(correctCase("liquibase"), "TODO"); // todo
    data.put(correctCase("deployment_id"), "TODO"); // todo

    scope
        .getSingleton(ActionExecutor.class)
        .execute(
            new InsertDataAction(
                new RowData(
                    ((StandardChangeLogHistoryService)
                            scope.get(
                                Scope.Attr.changeLogHistoryService, ChangeLogHistoryService.class))
                        .changeLogTable,
                    data)),
            scope);
  }
  @Override
  public Sql[] generateSql(
      MarkChangeSetRanStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
    String dateValue = database.getCurrentDateTimeFunction();

    ChangeSet changeSet = statement.getChangeSet();

    SqlStatement runStatement;
    try {
      if (statement.getExecType().equals(ChangeSet.ExecType.FAILED)
          || statement.getExecType().equals(ChangeSet.ExecType.SKIPPED)) {
        return new Sql[0]; // don't mark
      } else if (statement.getExecType().ranBefore) {
        runStatement =
            new UpdateStatement(
                    database.getLiquibaseCatalogName(),
                    database.getLiquibaseSchemaName(),
                    database.getDatabaseChangeLogTableName())
                .addNewColumnValue("DATEEXECUTED", new DatabaseFunction(dateValue))
                .addNewColumnValue("MD5SUM", changeSet.generateCheckSum().toString())
                .addNewColumnValue("EXECTYPE", statement.getExecType().value)
                .setWhereClause("ID=? AND AUTHOR=? AND FILENAME=?")
                .addWhereParameters(
                    changeSet.getId(), changeSet.getAuthor(), changeSet.getFilePath());
      } else {
        runStatement =
            new InsertStatement(
                    database.getLiquibaseCatalogName(),
                    database.getLiquibaseSchemaName(),
                    database.getDatabaseChangeLogTableName())
                .addColumnValue("ID", changeSet.getId())
                .addColumnValue("AUTHOR", changeSet.getAuthor())
                .addColumnValue("FILENAME", changeSet.getFilePath())
                .addColumnValue("DATEEXECUTED", new DatabaseFunction(dateValue))
                .addColumnValue(
                    "ORDEREXECUTED",
                    ChangeLogHistoryServiceFactory.getInstance()
                        .getChangeLogService(database)
                        .getNextSequenceValue())
                .addColumnValue("MD5SUM", changeSet.generateCheckSum().toString())
                .addColumnValue("DESCRIPTION", limitSize(changeSet.getDescription()))
                .addColumnValue(
                    "COMMENTS",
                    limitSize(
                        database.escapeStringForDatabase(
                            StringUtils.trimToEmpty(changeSet.getComments()))))
                .addColumnValue("EXECTYPE", statement.getExecType().value)
                .addColumnValue(
                    "LIQUIBASE", LiquibaseUtil.getBuildVersion().replaceAll("SNAPSHOT", "SNP"));

        String tag = null;
        List<Change> changes = changeSet.getChanges();
        if (changes != null && changes.size() == 1) {
          Change change = changes.get(0);
          if (change instanceof TagDatabaseChange) {
            TagDatabaseChange tagChange = (TagDatabaseChange) change;
            tag = tagChange.getTag();
          }
        }
        if (tag != null) {
          ((InsertStatement) runStatement).addColumnValue("TAG", tag);
        }
      }
    } catch (LiquibaseException e) {
      throw new UnexpectedLiquibaseException(e);
    }

    return SqlGeneratorFactory.getInstance().generateSql(runStatement, database);
  }
  /** Drops all objects owned by the connected user. */
  @Override
  public void dropDatabaseObjects(final CatalogAndSchema schemaToDrop) throws LiquibaseException {
    ObjectQuotingStrategy currentStrategy = this.getObjectQuotingStrategy();
    this.setObjectQuotingStrategy(ObjectQuotingStrategy.QUOTE_ALL_OBJECTS);
    try {
      DatabaseSnapshot snapshot;
      try {
        final SnapshotControl snapshotControl = new SnapshotControl(this);
        final Set<Class<? extends DatabaseObject>> typesToInclude =
            snapshotControl.getTypesToInclude();

        // We do not need to remove indexes and primary/unique keys explicitly. They should be
        // removed
        // as part of tables.
        typesToInclude.remove(Index.class);
        typesToInclude.remove(PrimaryKey.class);
        typesToInclude.remove(UniqueConstraint.class);

        if (supportsForeignKeyDisable()) {
          // We do not remove ForeignKey because they will be disabled and removed as parts of
          // tables.
          typesToInclude.remove(ForeignKey.class);
        }

        final long createSnapshotStarted = System.currentTimeMillis();
        snapshot =
            SnapshotGeneratorFactory.getInstance()
                .createSnapshot(schemaToDrop, this, snapshotControl);
        LogFactory.getLogger()
            .debug(
                String.format(
                    "Database snapshot generated in %d ms. Snapshot includes: %s",
                    System.currentTimeMillis() - createSnapshotStarted, typesToInclude));
      } catch (LiquibaseException e) {
        throw new UnexpectedLiquibaseException(e);
      }

      final long changeSetStarted = System.currentTimeMillis();
      DiffResult diffResult =
          DiffGeneratorFactory.getInstance()
              .compare(
                  new EmptyDatabaseSnapshot(this),
                  snapshot,
                  new CompareControl(snapshot.getSnapshotControl().getTypesToInclude()));
      List<ChangeSet> changeSets =
          new DiffToChangeLog(
                  diffResult,
                  new DiffOutputControl(true, true, false).addIncludedSchema(schemaToDrop))
              .generateChangeSets();
      LogFactory.getLogger()
          .debug(
              String.format(
                  "ChangeSet to Remove Database Objects generated in %d ms.",
                  System.currentTimeMillis() - changeSetStarted));

      boolean previousAutoCommit = this.getAutoCommitMode();
      this.commit(); // clear out currently executed statements
      this.setAutoCommit(false); // some DDL doesn't work in autocommit mode
      final boolean reEnableFK = supportsForeignKeyDisable() && disableForeignKeyChecks();
      try {
        for (ChangeSet changeSet : changeSets) {
          changeSet.setFailOnError(false);
          for (Change change : changeSet.getChanges()) {
            if (change instanceof DropTableChange) {
              ((DropTableChange) change).setCascadeConstraints(true);
            }
            SqlStatement[] sqlStatements = change.generateStatements(this);
            for (SqlStatement statement : sqlStatements) {
              ExecutorService.getInstance().getExecutor(this).execute(statement);
            }
          }
          this.commit();
        }
      } finally {
        if (reEnableFK) {
          enableForeignKeyChecks();
        }
      }

      ChangeLogHistoryServiceFactory.getInstance().getChangeLogService(this).destroy();
      LockServiceFactory.getInstance().getLockService(this).destroy();

      this.setAutoCommit(previousAutoCommit);

    } finally {
      this.setObjectQuotingStrategy(currentStrategy);
      this.commit();
    }
  }
Example #10
0
  protected void handleRollbackNode(ParsedNode rollbackNode, ResourceAccessor resourceAccessor)
      throws ParsedNodeException {
    String changeSetId = rollbackNode.getChildValue(null, "changeSetId", String.class);
    if (changeSetId != null) {
      String changeSetAuthor = rollbackNode.getChildValue(null, "changeSetAuthor", String.class);
      String changeSetPath = rollbackNode.getChildValue(null, "changeSetPath", getFilePath());

      ChangeSet changeSet =
          this.getChangeLog().getChangeSet(changeSetPath, changeSetAuthor, changeSetId);
      if (changeSet == null) { // check from root
        changeSet =
            getChangeLog()
                .getRootChangeLog()
                .getChangeSet(changeSetPath, changeSetAuthor, changeSetId);
        if (changeSet == null) {
          throw new ParsedNodeException(
              "Change set "
                  + new ChangeSet(
                          changeSetId,
                          changeSetAuthor,
                          false,
                          false,
                          changeSetPath,
                          null,
                          null,
                          null)
                      .toString(false)
                  + " does not exist");
        }
      }
      for (Change change : changeSet.getChanges()) {
        rollback.getChanges().add(change);
      }
      return;
    }

    boolean foundValue = false;
    for (ParsedNode childNode : rollbackNode.getChildren()) {
      Change rollbackChange = toChange(childNode, resourceAccessor);
      if (rollbackChange != null) {
        addRollbackChange(rollbackChange);
        foundValue = true;
      }
    }

    Object value = rollbackNode.getValue();
    if (value != null) {
      if (value instanceof String) {
        String finalValue = StringUtils.trimToNull((String) value);
        if (finalValue != null) {
          String[] strings = StringUtils.processMutliLineSQL(finalValue, true, true, ";");
          for (String string : strings) {
            addRollbackChange(new RawSQLChange(string));
            foundValue = true;
          }
        }
      } else {
        throw new ParsedNodeException(
            "Unexpected object: " + value.getClass().getName() + " '" + value.toString() + "'");
      }
    }
    if (!foundValue) {
      addRollbackChange(new EmptyChange());
    }
  }