package liquibase.ext.spatial.sqlgenerator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import liquibase.database.Database;
import liquibase.database.core.DerbyDatabase;
import liquibase.database.core.H2Database;
import liquibase.datatype.DataTypeFactory;
import liquibase.datatype.LiquibaseDataType;
import liquibase.exception.ValidationErrors;
import liquibase.ext.spatial.datatype.GeometryType;
import liquibase.sql.Sql;
import liquibase.sql.UnparsedSql;
import liquibase.sqlgenerator.SqlGenerator;
import liquibase.sqlgenerator.SqlGeneratorChain;
import liquibase.sqlgenerator.core.AbstractSqlGenerator;
import liquibase.statement.core.AddColumnStatement;
import liquibase.util.StringUtils;
/**
* <code>AddGeometryColumnGeneratorGeoDB</code> is a SQL generator that
* specializes in GeoDB. Regardless of the column type, the next SQL generator
* in the chain is invoked to handle the normal column addition. If the column
* to be added has a geometry type, the <code>AddGeometryColumn</code> stored
* procedure is invoked to ensure that the necessary metadata is created in the
* database.
*/
public class AddGeometryColumnGeneratorGeoDB extends
AbstractSqlGenerator<AddColumnStatement> {
/**
* @see liquibase.sqlgenerator.core.AbstractSqlGenerator#supports(liquibase.statement.SqlStatement,
* liquibase.database.Database)
*/
@Override
public boolean supports(final AddColumnStatement statement,
final Database database) {
return database instanceof DerbyDatabase
|| database instanceof H2Database;
}
/**
* @see liquibase.sqlgenerator.core.AbstractSqlGenerator#getPriority()
*/
@Override
public int getPriority() {
return SqlGenerator.PRIORITY_DATABASE + 1;
}
@Override
public ValidationErrors validate(final AddColumnStatement statement,
final Database database, final SqlGeneratorChain sqlGeneratorChain) {
final ValidationErrors errors = new ValidationErrors();
final LiquibaseDataType dataType = DataTypeFactory.getInstance()
.fromDescription(statement.getColumnType(), database);
// Ensure that the SRID parameter is provided.
if (dataType instanceof GeometryType) {
final GeometryType geometryType = (GeometryType) dataType;
if (geometryType.getSRID() == null) {
errors.addError("The SRID parameter is required on the geometry type");
}
}
final ValidationErrors chainErrors = sqlGeneratorChain.validate(
statement, database);
if (chainErrors != null) {
errors.addAll(chainErrors);
}
return errors;
}
@Override
public Sql[] generateSql(final AddColumnStatement statement,
final Database database, final SqlGeneratorChain sqlGeneratorChain) {
GeometryType geometryType = null;
final LiquibaseDataType dataType = DataTypeFactory.getInstance()
.fromDescription(statement.getColumnType(), database);
if (dataType instanceof GeometryType) {
geometryType = (GeometryType) dataType;
}
final boolean isGeometryColumn = geometryType != null;
// The AddGeometryColumn procedure handles the column already being
// present, so let a
// downstream SQL generator handle the typical column addition logic (e.g.
// placement in the
// table) then invoke the procedure.
final List<Sql> list = new ArrayList<Sql>();
list.addAll(Arrays.asList(sqlGeneratorChain.generateSql(statement,
database)));
if (isGeometryColumn) {
String schemaName = statement.getSchemaName();
if (schemaName == null) {
schemaName = database.getDefaultSchemaName();
}
final String tableName = statement.getTableName();
final String columnName = statement.getColumnName();
final int srid = geometryType.getSRID();
final String geomType = StringUtils.trimToNull(geometryType
.getGeometryType()) == null ? "'Geometry'" : "'"
+ database.escapeStringForDatabase(geometryType
.getGeometryType()) + "'";
final String sql = "CALL AddGeometryColumn('" + schemaName + "', '"
+ tableName + "', '" + columnName + "', " + srid + ", "
+ geomType + ", 2)";
final Sql addGeometryColumn = new UnparsedSql(sql);
list.add(addGeometryColumn);
}
return list.toArray(new Sql[list.size()]);
}
}