/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.gce.imagemosaic.jdbc;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.logging.Level;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKBReader;
import com.vividsolutions.jts.io.WKBWriter;
/**
* JDBCAccess implentation for PostGis
*
* @author mcr
*
*/
class JDBCAccessPostGis extends JDBCAccessBase {
static String SRSSelect = "select srid from geometry_columns where f_table_schema=? and f_table_name=? and f_geometry_column=? ";
static String CRSSelect = "select srtext from spatial_ref_sys where srid=?";
private String extentSelect = null;
private String allSelect = null;
private String allSelectJoined = null;
private String gridSelect = null;
private String gridSelectJoined = null;
// Since PostGis 1.2.2
private String functionPrefix = "st_";
JDBCAccessPostGis(Config config) throws IOException {
super(config);
initForPostGisVersion();
initStatementStrings(config);
}
/**
* Check if we have an instance of PostGis that uses the "st_" prefix for
* functions or not.
* Eg: the extent function is replaced PostGis by st_extent.
* The prefix is added since version 1.2.2
*/
private void initForPostGisVersion() {
String extentFunctionName="st_extent";
Connection con=null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
con = dataSource.getConnection();
ps = con.prepareStatement("select proname from pg_proc where proname='"+extentFunctionName+"'");
rs = ps.executeQuery();
if (rs.next()==false) {
functionPrefix="";
LOGGER.info("Using depricated postgis functions eg 'extent' instead of 'st_extent'");
}
} catch (SQLException ex) {
LOGGER.log(Level.WARNING, "could not verify existence of postgis function 'st_extent', falling back to depricated 'extent'");
functionPrefix="";
}
finally {
try { if (rs!=null) rs.close(); } catch (SQLException ex) {};
try { if (ps!=null) ps.close(); } catch (SQLException ex) {};
try { if (con!=null) ps.close(); } catch (SQLException ex) {};
}
}
/**
* Initialize needed sql statement strings
*
* @param config
*/
private void initStatementStrings(Config config) {
final String geomAttr = config.getGeomAttributeNameInSpatialTable();
extentSelect = "select "+ functionPrefix +"extent(" + geomAttr + ") from {0}";
// ////////////
final String spatialSelectClause = "select s." + config.getKeyAttributeNameInSpatialTable()
+ "," + "asbinary(" + functionPrefix + "envelope(s." + geomAttr + "))";
allSelect = spatialSelectClause + ",s." + config.getBlobAttributeNameInTileTable()
+ " from {0} s";
allSelectJoined = spatialSelectClause + ",t." + config.getBlobAttributeNameInTileTable()
+ " from {0} s, {1} t WHERE ";
allSelectJoined += (" s." + config.getKeyAttributeNameInSpatialTable() + " = t." + config
.getKeyAttributeNameInTileTable());
String whereClause = functionPrefix + "intersects(" + geomAttr + "," + "GeomFromWKB(?,?))";
gridSelect = allSelect + " WHERE " + whereClause;
gridSelectJoined = allSelectJoined + " AND " + whereClause;
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#getExtentSelectStatment(org.geotools.gce.imagemosaic.jdbc.ImageLevelInfo)
*/
@Override
protected String getExtentSelectStatment(ImageLevelInfo li) {
return MessageFormat.format(extentSelect, new Object[] { li.getSpatialTableName() });
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#getExtent(org.geotools.gce.imagemosaic.jdbc.ImageLevelInfo,
* java.sql.Connection)
*/
@Override
protected Envelope getExtent(ImageLevelInfo li, Connection con) throws SQLException,
IOException {
String extentSelect = getExtentSelectStatment(li);
String statementString = MessageFormat.format(extentSelect, new Object[] { li
.getSpatialTableName() });
Envelope extent = null;
PreparedStatement s = con.prepareStatement(statementString);
ResultSet r = s.executeQuery();
if (r.next()) {
Object o = r.getObject(1);
String pgString = o.toString();
int start = pgString.indexOf("(") + 1;
int end = pgString.indexOf(")");
pgString = pgString.substring(start, end);
String[] coords = pgString.split(",");
String[] lower = coords[0].split(" ");
String[] upper = coords[1].split(" ");
extent = new Envelope(new Coordinate(new Double(lower[0]), new Double(lower[1])),
new Coordinate(new Double(upper[0]), new Double(upper[1])));
}
r.close();
s.close();
return extent;
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#getEnvelopeFromResultSet(java.sql.ResultSet)
*/
@Override
protected Envelope getEnvelopeFromResultSet(ResultSet r) throws SQLException {
byte[] bytes = r.getBytes(2);
WKBReader reader = new WKBReader();
Geometry bbox = null;
try {
bbox = reader.read(bytes);
} catch (ParseException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
throw new SQLException(e.getMessage());
}
return bbox.getEnvelopeInternal();
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#getRandomTileStatement(org.geotools.gce.imagemosaic.jdbc.ImageLevelInfo)
*/
@Override
protected String getRandomTileStatement(ImageLevelInfo li) {
if (li.isImplementedAsTableSplit()) {
return MessageFormat.format(allSelectJoined, new Object[] { li.getSpatialTableName(),
li.getTileTableName() });
} else {
return MessageFormat.format(allSelect, new Object[] { li.getSpatialTableName() });
}
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#getGridSelectStatement(org.geotools.gce.imagemosaic.jdbc.ImageLevelInfo)
*/
@Override
protected String getGridSelectStatement(ImageLevelInfo li) {
if (li.isImplementedAsTableSplit()) {
return MessageFormat.format(gridSelectJoined, new Object[] { li.getSpatialTableName(),
li.getTileTableName() });
} else {
return MessageFormat.format(gridSelect, new Object[] { li.getSpatialTableName() });
}
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#setGridSelectParams(java.sql.PreparedStatement,
* org.geotools.geometry.GeneralEnvelope, org.geotools.gce.imagemosaic.jdbc.ImageLevelInfo)
*/
@Override
protected void setGridSelectParams(PreparedStatement s, GeneralEnvelope envelope,
ImageLevelInfo li) throws SQLException {
WKBWriter w = new WKBWriter();
byte[] bytes = w.write(polyFromEnvelope(envelope));
s.setBytes(1, bytes);
s.setInt(2, li.getSrsId());
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#getSRSID(org.geotools.gce.imagemosaic.jdbc.ImageLevelInfo,
* java.sql.Connection)
*/
@Override
protected Integer getSRSID(ImageLevelInfo li, Connection con) throws IOException {
Integer result = null;
String schema = null;
try {
schema = getSchemaFromSpatialTable(li.getSpatialTableName());
PreparedStatement s = null;
if (schema == null) {
schema = "public";
}
s = con.prepareStatement(SRSSelect);
s.setString(1, schema);
s.setString(2, li.getSpatialTableName());
s.setString(3, config.getGeomAttributeNameInSpatialTable());
ResultSet r = s.executeQuery();
if (r.next()) {
result = (Integer) r.getObject(1);
}
r.close();
s.close();
} catch (SQLException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
throw new IOException(e.getMessage());
}
if (result == null) {
String msg = MessageFormat.format("No entry in geometry_columns for {0},{1},{2}",
new Object[] { schema, li.getSpatialTableName(),
config.getGeomAttributeNameInSpatialTable() });
LOGGER.log(Level.SEVERE, msg);
throw new IOException(msg);
}
return result;
}
/*
* (non-Javadoc)
*
* @see org.geotools.gce.imagemosaic.jdbc.JDBCAccessBase#getCRS(org.geotools.gce.imagemosaic.jdbc.ImageLevelInfo,
* java.sql.Connection)
*/
@Override
protected CoordinateReferenceSystem getCRS(ImageLevelInfo li, Connection con)
throws IOException {
CoordinateReferenceSystem result = null;
try {
PreparedStatement s = con.prepareStatement(CRSSelect);
s.setInt(1, li.getSrsId());
ResultSet r = s.executeQuery();
if (r.next()) {
String definition = r.getString(1);
result = CRS.parseWKT(definition);
}
r.close();
s.close();
} catch (Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
throw new IOException(e.getMessage());
}
return result;
}
}