package com.vividsolutions.jump.datastore.postgis;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.WKBReader;
import com.vividsolutions.jump.datastore.DataStoreMetadata;
import com.vividsolutions.jump.datastore.SpatialReferenceSystemID;
import com.vividsolutions.jump.datastore.jdbc.JDBCUtil;
import com.vividsolutions.jump.datastore.jdbc.ResultSetBlock;
public class PostgisDSMetadata implements DataStoreMetadata {
private final WKBReader reader = new WKBReader();
private PostgisDSConnection conn;
private Map sridMap = new HashMap();
public PostgisDSMetadata( PostgisDSConnection conn ) {
this.conn = conn;
}
public String[] getDatasetNames() {
final List datasetNames = new ArrayList();
// Spatial tables only.
JDBCUtil.execute(
conn.getConnection(),
"SELECT DISTINCT f_table_schema, f_table_name FROM geometry_columns",
new ResultSetBlock() {
public void yield( ResultSet resultSet ) throws SQLException {
while ( resultSet.next() ) {
String schema = resultSet.getString( 1 );
String table = resultSet.getString( 2 );
if ( !schema.equalsIgnoreCase( "public" ) ) {
table = schema + "." + table;
}
datasetNames.add( table );
}
}
} );
return ( String[] ) datasetNames.toArray( new String[]{} );
}
public Envelope getExtents( String datasetName, String attributeName ) {
final Envelope[] e = new Envelope[]{null};
//
// Use find_extent - sometimes estimated_extent was returning null
//
String sql = "";
//find_extent needs schema and table as separate arguments or it fails with "relation does not exist"
if(datasetName.indexOf('.') != -1) {
String[] parts = datasetName.split("\\.", 2);
sql = "SELECT AsBinary(find_extent( '" + parts[0] + "', '" + parts[1] +"', '" + attributeName + "' ))";
} else {
sql = "SELECT AsBinary(find_extent( '" + datasetName + "', '" + attributeName + "' ))";
}
JDBCUtil.execute(
conn.getConnection(), sql,
new ResultSetBlock() {
public void yield( ResultSet resultSet ) throws Exception {
if ( resultSet.next() ) {
byte[] bytes = ( byte[] ) resultSet.getObject( 1 );
if ( bytes != null ) {
Geometry geom = reader.read( bytes );
if ( geom != null ) {
e[0] = geom.getEnvelopeInternal();
}
}
}
}
} );
return e[0];
}
public SpatialReferenceSystemID getSRID(String tableName, String colName)
throws SQLException {
String key = tableName + "#" + colName;
if (!sridMap.containsKey(key)) {
// not in cache, so query it
String srid = querySRID(tableName, colName);
sridMap.put(key, new SpatialReferenceSystemID(srid));
}
SpatialReferenceSystemID srid = (SpatialReferenceSystemID) sridMap
.get(key);
return srid;
}
private String querySRID(String tableName, String colName)
{
final StringBuffer srid = new StringBuffer();
// Changed by Michael Michaud 2010-05-26 (throwed exception for empty tableName)
// String sql = "SELECT getsrid(" + colName + ") FROM " + tableName + " LIMIT 1";
String[] tokens = tableName.split("\\.", 2);
String schema = tokens.length==2?tokens[0]:"public";
String table = tokens.length==2?tokens[1]:tableName;
String sql = "SELECT srid FROM geometry_columns where (f_table_schema = '" + schema + "' and f_table_name = '" + table + "')";
// End of the fix
JDBCUtil.execute(conn.getConnection(), sql, new ResultSetBlock() {
public void yield(ResultSet resultSet) throws SQLException {
if (resultSet.next()) {
srid.append(resultSet.getString(1));
}
}
});
return srid.toString();
}
public String[] getGeometryAttributeNames( String datasetName ) {
final List geometryAttributeNames = new ArrayList();
String sql = "SELECT f_geometry_column FROM geometry_columns "
+ geomColumnMetadataWhereClause( "f_table_schema", "f_table_name", datasetName );
JDBCUtil.execute(
conn.getConnection(), sql,
new ResultSetBlock() {
public void yield( ResultSet resultSet ) throws SQLException {
while ( resultSet.next() ) {
geometryAttributeNames.add( resultSet.getString( 1 ) );
}
}
} );
return ( String[] ) geometryAttributeNames.toArray( new String[]{} );
}
public String[] getColumnNames( String datasetName ) {
String sql = "SELECT column_name FROM information_schema.columns "
+ geomColumnMetadataWhereClause( "table_schema", "table_name", datasetName );
ColumnNameBlock block = new ColumnNameBlock();
JDBCUtil.execute( conn.getConnection(), sql, block );
return block.colName;
}
private String geomColumnMetadataWhereClause( String schemaCol, String tableCol, String tableName ) {
// [mmichaud 2011-07-24] Fixed a bug related to tables having common
// names in public schema and another schema
int dotPos = tableName.indexOf( "." );
String schema = "public";
String table = tableName.toLowerCase();
if (dotPos != -1) {
schema = tableName.substring( 0, dotPos ).toLowerCase();
table = tableName.substring( dotPos + 1 ).toLowerCase();
}
return "WHERE lower(" + schemaCol + ") = '" + schema + "'"
+ " AND lower(" + tableCol + ") = '" + table + "'";
}
private static class ColumnNameBlock implements ResultSetBlock {
List colList = new ArrayList();
String[] colName;
public void yield( ResultSet resultSet ) throws SQLException {
while ( resultSet.next() ) {
colList.add( resultSet.getString( 1 ) );
}
colName = ( String[] ) colList.toArray( new String[0] );
}
}
}