package liquibase.ext.spatial.sqlgenerator;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.util.StringUtils;
/**
* <code>OracleSpatialUtils</code> provides utility methods for Oracle Spatial.
*/
public class OracleSpatialUtils {
/** The Oracle function that converts an EPSG SRID to the corresponding Oracle SRID. */
public static final String EPSG_TO_ORACLE_FUNCTION = "SDO_CS.MAP_EPSG_SRID_TO_ORACLE";
/** The mapping of EPSG SRID to Oracle SRID. */
private final static Map<String, String> EPSG_TO_ORACLE_MAP = Collections
.synchronizedMap(new HashMap<String, String>());
/** Hide the default constructor. */
private OracleSpatialUtils() {
}
/**
* Converts the given Well-Known Text string to one that will work in Oracle. If the string is
* greater than 4000 characters, the string is broken into pieces where each piece is converted
* to a CLOB. The CLOB handling assumes that the result will be wrapped in single quotes so it
* wraps the result in "<code>' || TO_CLOB(...) || '</code>".
*
* @param wkt
* the Well-Known Text string to convert.
* @return the original WKT or a <code>TO_CLOB</code> concatenation of the WKT.
*/
public static String getOracleWkt(final String wkt) {
final String oracleWkt;
// Strings longer than 4000 characters need to be converted to CLOBs.
if (wkt.length() > 4000) {
oracleWkt = "' || " + convertToClob(wkt) + " || '";
} else {
oracleWkt = wkt;
}
return oracleWkt;
}
/**
* Generates the SQL to convert the given string to a CLOB.
*
* @param varchar
* the value to convert.
* @return the SQL to convert the string to a CLOB.
*/
public static String convertToClob(final String varchar) {
int startIndex = 0;
int endIndex = Math.min(startIndex + 4000, varchar.length());
final StringBuilder clobs = new StringBuilder("TO_CLOB('").append(
varchar.substring(startIndex, endIndex)).append("')");
while (endIndex < varchar.length()) {
startIndex = endIndex;
endIndex = Math.min(startIndex + 4000, varchar.length());
clobs.append(" || TO_CLOB('").append(varchar.substring(startIndex, endIndex)).append("')");
}
return clobs.toString();
}
/**
* Converts the given EPSG SRID to the corresponding Oracle SRID.
*
* @param srid
* the EPSG SRID.
* @param database
* the database instance.
* @return the corresponding Oracle SRID.
*/
public static String getOracleSrid(final String srid, final Database database) {
final String oracleSrid;
if (StringUtils.trimToNull(srid) == null) {
oracleSrid = null;
} else if (EPSG_TO_ORACLE_MAP.containsKey(srid)) {
oracleSrid = EPSG_TO_ORACLE_MAP.get(srid);
} else {
oracleSrid = loadOracleSrid(srid, database);
EPSG_TO_ORACLE_MAP.put(srid, oracleSrid);
}
return oracleSrid;
}
/**
* Queries to the database to convert the given EPSG SRID to the corresponding Oracle SRID.
*
* @param srid
* the EPSG SRID.
* @param database
* the database instance.
* @return the corresponding Oracle SRID.
*/
public static String loadOracleSrid(final String srid, final Database database) {
final String oracleSrid;
final JdbcConnection jdbcConnection = (JdbcConnection) database.getConnection();
final Connection connection = jdbcConnection.getUnderlyingConnection();
Statement statement = null;
try {
statement = connection.createStatement();
final ResultSet resultSet = statement.executeQuery("SELECT " + EPSG_TO_ORACLE_FUNCTION
+ "(" + srid + ") FROM dual");
resultSet.next();
oracleSrid = resultSet.getString(1);
} catch (final SQLException e) {
throw new UnexpectedLiquibaseException("Failed to find the Oracle SRID for EPSG:" + srid,
e);
} finally {
try {
statement.close();
} catch (final SQLException ignore) {
}
}
return oracleSrid;
}
}