/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-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.data.postgis; import java.io.IOException; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import org.geotools.data.DataSourceException; import org.geotools.data.DataStore; import org.geotools.data.Transaction; import org.geotools.data.jdbc.FeatureTypeInfo; import org.geotools.data.jdbc.JDBCDataStoreConfig; import org.geotools.data.jdbc.JDBCUtils; import org.geotools.data.jdbc.SQLBuilder; import org.geotools.data.jdbc.fidmapper.FIDMapper; import org.geotools.factory.Hints; import org.geotools.filter.RegfuncFilterFactoryImpl; import org.geotools.filter.SQLEncoderPostgis; import org.opengis.feature.simple.SimpleFeatureType; /** * {@link DataStore} with support for registered functions, that is, functions that can be executed * on the database server side. * * <p> * * TODO: everything in this class should be pulled up into ancestor classes. * * @author Ben Caradoc-Davies, CSIRO Exploration and Mining * @version $Id$ * * @source $URL$ * @since 2.4 */ public class RegfuncPostgisDataStore extends PostgisDataStore { /* * SPI mechanism cannot be used as we only want one FilterFactory implementation system wide. * Why provide more than one? Which one should be used? This would be SPI misuse. * * FIXME: This should go away when registered function support is refactored into core. At the * moment, this is required because otherwise DuplicatingFilterVisitor gets the wrong * FeatureFactory. */ static { Hints.putSystemDefault(Hints.FILTER_FACTORY, new RegfuncFilterFactoryImpl()); } /** * Constructor. * * @see org.geotools.data.postgis.PostgisDataStore#PostgisDataStore(DataSource) * * @param dataSource * @throws IOException */ public RegfuncPostgisDataStore(DataSource dataSource) throws IOException { super(dataSource); } /** * Constructor. * * @see org.geotools.data.postgis.PostgisDataStore#PostgisDataStore(DataSource, String) * * @param dataSource * @param namespace * @throws IOException */ public RegfuncPostgisDataStore(DataSource dataSource, String namespace) throws IOException { super(dataSource, namespace); } /** * Constructor. * * @see org.geotools.data.postgis.PostgisDataStore#PostgisDataStore(DataSource, String, String) * * @param dataSource * @param schema * @param namespace * @throws IOException */ public RegfuncPostgisDataStore(DataSource dataSource, String schema, String namespace) throws IOException { super(dataSource, schema, namespace); } /** * Constructor. * * @see org.geotools.data.postgis.PostgisDataStore#PostgisDataStore(DataSource, * JDBCDataStoreConfig, int) * * @param dataSource * @param config * @param optimizeMode * @throws IOException */ public RegfuncPostgisDataStore(DataSource dataSource, JDBCDataStoreConfig config, int optimizeMode) throws IOException { super(dataSource, config, optimizeMode); } /** * Constructor. * * @see org.geotools.data.postgis.PostgisDataStore#PostgisDataStore(DataSource, String, String, * int) * * @param dataSource * @param schema * @param namespace * @param optimizeMode * @throws IOException */ public RegfuncPostgisDataStore(DataSource dataSource, String schema, String namespace, int optimizeMode) throws IOException { super(dataSource, schema, namespace, optimizeMode); } /** * Creates a new sql builder for encoding raw sql statements. * * <p> * * This method duplicates the implementation in {@link PostgisDataStore}, except that it * ensures a {@link RegfuncSQLEncoderPostgis} is passed to {@link PostgisSQLBuilder}, enabling * support for registered functions. * * @see org.geotools.data.postgis.PostgisDataStore#createSQLBuilder() */ // @Override protected PostgisSQLBuilder createSQLBuilder() { PostgisSQLBuilder builder = new PostgisSQLBuilder(new RegfuncSQLEncoderPostgis(), config); initBuilder(builder); return builder; } /** * This method duplicates the implementation in {@link PostgisDataStore}, except that it * ensures a {@link RegfuncSQLEncoderPostgis} is passed to {@link PostgisSQLBuilder}, enabling * support for registered functions. * * @see org.geotools.data.postgis.PostgisDataStore#getSqlBuilder(java.lang.String) */ // @Override public SQLBuilder getSqlBuilder(String typeName) throws IOException { FeatureTypeInfo info = typeHandler.getFeatureTypeInfo(typeName); int srid = -1; SQLEncoderPostgis encoder = new RegfuncSQLEncoderPostgis(); encoder.setSupportsGEOS(useGeos); encoder.setFIDMapper(typeHandler.getFIDMapper(typeName)); if (info.getSchema().getGeometryDescriptor() != null) { String geom = info.getSchema().getGeometryDescriptor().getLocalName(); srid = info.getSRID(geom); encoder.setDefaultGeometry(geom); } encoder.setFeatureType(info.getSchema()); encoder.setSRID(srid); encoder.setLooseBbox(looseBbox); PostgisSQLBuilder builder = new PostgisSQLBuilder(encoder, config, info.getSchema()); initBuilder(builder); return builder; } /** * At the moment, this method does the same as the method of the superclass. * * @see org.geotools.data.postgis.PostgisDataStore#buildSchema(java.lang.String, * org.geotools.data.jdbc.fidmapper.FIDMapper) */ // Should be OK to allow super to use its SQLEncoderPostgis (no Regfunc) // because only used for permission checks. // @Override protected SimpleFeatureType buildSchema(String typeName, FIDMapper mapper) throws IOException { if (false) { // kept this code as probing for registered_functions goes here Connection conn = getConnection(Transaction.AUTO_COMMIT); try { Statement st = conn.createStatement(); try { st.execute("SELECT * FROM geometry_columns LIMIT 0;"); } catch (Throwable t) { String msg = "Error querying relation: geometry_columns." + " Possible cause:" + t.getLocalizedMessage(); throw new DataSourceException(msg, t); } try { SQLEncoderPostgis encoder = new RegfuncSQLEncoderPostgis(-1); encoder.setSupportsGEOS(useGeos); PostgisSQLBuilder builder = new PostgisSQLBuilder(encoder, config); initBuilder(builder); st.execute("SELECT * FROM " + builder.encodeTableName(typeName) + " LIMIT 0;"); } catch (Throwable t) { String msg = "Error querying relation: " + typeName + "." + " Possible cause:" + t.getLocalizedMessage(); throw new DataSourceException(msg, t); } st.close(); } catch (SQLException e) { JDBCUtils.close(conn, Transaction.AUTO_COMMIT, e); throw new DataSourceException(e); } finally { JDBCUtils.close(conn, Transaction.AUTO_COMMIT, null); } // everything is cool, keep going } return super.buildSchema(typeName, mapper); } }