package liquibase.ext.oracle.preconditions;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import liquibase.changelog.ChangeSet;
import liquibase.changelog.DatabaseChangeLog;
import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.exception.PreconditionErrorException;
import liquibase.exception.PreconditionFailedException;
import liquibase.exception.ValidationErrors;
import liquibase.exception.Warnings;
import liquibase.precondition.Precondition;
public class OracleIndexExistsPrecondition extends OraclePrecondition {
private String indexName;
private String tableName;
private String columnNames;
public String getIndexName() {
return indexName;
}
public void setIndexName( String indexName ) {
this.indexName = indexName;
}
public String getTableName() {
return tableName;
}
public void setTableName( String tableName ) {
this.tableName = tableName;
}
public String getColumnNames() {
return columnNames;
}
public void setColumnNames( String columnNames ) {
this.columnNames = columnNames;
}
public String getName() {
return "oracleIndexExists";
}
public Warnings warn( Database database ) {
return new Warnings();
}
public ValidationErrors validate( Database database ) {
ValidationErrors validationErrors = new ValidationErrors();
if ( getIndexName() == null && getTableName() == null && getColumnNames() == null ) {
validationErrors.addError( "indexName OR tableName and columnNames is required" );
}
return validationErrors;
}
public void check( Database database, DatabaseChangeLog changeLog, ChangeSet changeSet ) throws PreconditionFailedException, PreconditionErrorException {
JdbcConnection connection = (JdbcConnection) database.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
try {
if ( getIndexName() != null ) {
final String sql = "select count(*) from all_indexes i join dual d on upper(i.index_name) = upper(?) and upper(i.owner) = upper(?) left join all_constraints c on i.index_name = c.constraint_name where c.constraint_name is null";
ps = connection.prepareStatement( sql );
ps.setString( 1, getIndexName() );
ps.setString( 2, database.getLiquibaseSchemaName() );
rs = ps.executeQuery();
if ( !rs.next() || rs.getInt( 1 ) <= 0 ) {
throw new PreconditionFailedException( String.format( "The index '%s.%s' was not found.", database.getLiquibaseSchemaName(), getIndexName() ), changeLog, this );
}
} else {
final String sql = "select i.index_name, i.column_name from ( select * from all_ind_columns where upper(table_name) = upper (?) and upper(index_owner) = upper(?) ) i left join all_constraints c on i.index_name = c.constraint_name where c.constraint_name is null";
ps = connection.prepareStatement( sql );
ps.setString( 1, getTableName() );
ps.setString( 2, database.getLiquibaseSchemaName() );
rs = ps.executeQuery();
Map<String, List<String>> columnsMap = new HashMap<String, List<String>>();
while ( rs.next() ) {
String indexName = rs.getString( 1 );
String columnName = rs.getString( 2 );
List<String> cols = columnsMap.get( indexName );
if ( cols == null ) {
cols = new ArrayList<String>();
columnsMap.put( indexName, cols );
}
cols.add( columnName.toUpperCase() );
}
String[] expectedColumns = getColumnNames().toUpperCase().split( "\\s*,\\s*" );
// check for an index with all columns listed.
for ( String index : columnsMap.keySet() ) {
List<String> columnNames = columnsMap.get( index );
if ( columnNames.size() == expectedColumns.length ) {
if ( columnNames.containsAll( Arrays.asList( expectedColumns ) ) ) {
return;
}
}
}
throw new PreconditionFailedException( String.format( "No index was found on table '%s.%s' with columns '%s'.", database.getLiquibaseSchemaName(), getTableName(), getColumnNames() ), changeLog, this );
}
} catch ( SQLException e ) {
throw new PreconditionErrorException( e, changeLog, this );
} catch ( DatabaseException e ) {
throw new PreconditionErrorException( e, changeLog, this );
} finally {
closeSilently( rs );
closeSilently( ps );
}
}
}