protected void alter(Class<?> tableClass, Alterable... alterables) throws Exception {

    try (LoggingTimer loggingTimer = new LoggingTimer()) {
      Field tableNameField = tableClass.getField("TABLE_NAME");

      String tableName = (String) tableNameField.get(null);

      DatabaseMetaData databaseMetaData = connection.getMetaData();

      try (ResultSet rs1 = databaseMetaData.getPrimaryKeys(null, null, tableName);
          ResultSet rs2 =
              databaseMetaData.getIndexInfo(
                  null, null, normalizeName(tableName, databaseMetaData), false, false)) {

        Set<String> primaryKeyNames = new HashSet<>();

        while (rs1.next()) {
          String primaryKeyName = StringUtil.toUpperCase(rs1.getString("PK_NAME"));

          if (primaryKeyName != null) {
            primaryKeyNames.add(primaryKeyName);
          }
        }

        Map<String, Set<String>> columnNamesMap = new HashMap<>();

        while (rs2.next()) {
          String indexName = StringUtil.toUpperCase(rs2.getString("INDEX_NAME"));

          if ((indexName == null) || primaryKeyNames.contains(indexName)) {

            continue;
          }

          Set<String> columnNames = columnNamesMap.get(indexName);

          if (columnNames == null) {
            columnNames = new HashSet<>();

            columnNamesMap.put(indexName, columnNames);
          }

          columnNames.add(StringUtil.toUpperCase(rs2.getString("COLUMN_NAME")));
        }

        for (Alterable alterable : alterables) {
          for (Map.Entry<String, Set<String>> entry : columnNamesMap.entrySet()) {

            if (alterable.shouldDropIndex(entry.getValue())) {
              runSQL("drop index " + entry.getKey() + " on " + tableName);
            }
          }

          runSQL(alterable.getSQL(tableName));

          List<ObjectValuePair<String, IndexMetadata>> objectValuePairs =
              getIndexesSQL(tableClass.getClassLoader(), tableName);

          if (objectValuePairs == null) {
            continue;
          }

          for (ObjectValuePair<String, IndexMetadata> objectValuePair : objectValuePairs) {

            IndexMetadata indexMetadata = objectValuePair.getValue();

            if (alterable.shouldAddIndex(Arrays.asList(indexMetadata.getColumnNames()))) {

              runSQLTemplateString(objectValuePair.getKey(), false, true);
            }
          }
        }
      } catch (SQLException sqle) {
        if (_log.isWarnEnabled()) {
          _log.warn("Fallback to recreating the table", sqle);
        }

        Field tableColumnsField = tableClass.getField("TABLE_COLUMNS");
        Field tableSQLCreateField = tableClass.getField("TABLE_SQL_CREATE");
        Field tableSQLAddIndexesField = tableClass.getField("TABLE_SQL_ADD_INDEXES");

        upgradeTable(
            tableName,
            (Object[][]) tableColumnsField.get(null),
            (String) tableSQLCreateField.get(null),
            (String[]) tableSQLAddIndexesField.get(null));
      }
    }
  }
 @Override
 public boolean shouldDropIndex(Collection<String> columnNames) {
   return Alterable.containsIgnoreCase(columnNames, _columnName);
 }