/** 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();
    }
  }
  /**
   * Drops all objects owned by the connected user.
   *
   * @param schema
   */
  @Override
  public void dropDatabaseObjects(String schema) throws DatabaseException {
    try {
      DatabaseSnapshotGeneratorFactory factory = DatabaseSnapshotGeneratorFactory.getInstance();
      SnapshotContext context = new SnapshotContext();
      context.setDatabase(this);
      context.setSchema(schema);
      context.setListeners(new HashSet<DiffStatusListener>());
      DatabaseSnapshot snapshot = factory.createSnapshot(context);

      List<Change> dropChanges = new ArrayList<Change>();

      for (View view : snapshot.getViews()) {
        DropViewChange dropChange = new DropViewChange();
        dropChange.setViewName(view.getName());
        dropChange.setSchemaName(schema);

        dropChanges.add(dropChange);
      }

      if (!supportsForeignKeyDisable()) {
        for (ForeignKey fk : snapshot.getForeignKeys()) {
          DropForeignKeyConstraintChange dropFK = new DropForeignKeyConstraintChange();
          dropFK.setBaseTableSchemaName(schema);
          dropFK.setBaseTableName(fk.getForeignKeyTable().getName());
          dropFK.setConstraintName(fk.getName());

          dropChanges.add(dropFK);
        }
      }

      // for (Index index : snapshotGenerator.getIndexes()) {
      // DropIndexChange dropChange = new DropIndexChange();
      // dropChange.setIndexName(index.getName());
      // dropChange.setSchemaName(schema);
      // dropChange.setTableName(index.getTableName());
      //
      // dropChanges.add(dropChange);
      // }

      for (Table table : snapshot.getTables()) {
        DropTableChange dropChange = new DropTableChange();
        dropChange.setSchemaName(schema);
        dropChange.setTableName(table.getName());
        if (supportsDropTableCascadeConstraints()) {
          dropChange.setCascadeConstraints(true);
        }

        dropChanges.add(dropChange);
      }

      if (this.supportsSequences()) {
        for (Sequence seq : snapshot.getSequences()) {
          DropSequenceChange dropChange = new DropSequenceChange();
          dropChange.setSequenceName(seq.getName());
          dropChange.setSchemaName(schema);

          dropChanges.add(dropChange);
        }
      }

      if (snapshot.hasDatabaseChangeLogTable()) {
        dropChanges.add(new AnonymousChange(new ClearDatabaseChangeLogTableStatement(schema)));
      }

      final boolean reEnableFK = supportsForeignKeyDisable() && disableForeignKeyChecks();
      try {
        for (Change change : dropChanges) {
          for (SqlStatement statement : change.generateStatements(this)) {
            ExecutorService.getInstance().getExecutor(this).execute(statement);
          }
        }
      } finally {
        if (reEnableFK) {
          enableForeignKeyChecks();
        }
      }

    } finally {
      this.commit();
    }
  }