/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-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.oracle; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; import oracle.jdbc.OracleConnection; import oracle.sql.STRUCT; import org.geotools.data.DataSourceException; import org.geotools.data.DataUtilities; import org.geotools.data.FeatureReader; import org.geotools.data.jdbc.JDBCTextFeatureWriter; import org.geotools.data.jdbc.MutableFIDFeature; import org.geotools.data.jdbc.QueryData; import org.geotools.data.jdbc.datasource.DataSourceFinder; import org.geotools.data.jdbc.datasource.UnWrapper; import org.geotools.data.oracle.sdo.GeometryConverter; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.GeometryDescriptor; import com.vividsolutions.jts.geom.Geometry; /** * Subclasses JDBCTextFeatureWriter to issue Oracle transactions directly as * sql text statements. The super class takes care of all the nasty details, * this just returns the encoded geometry. To get some speed increases Jody * maintains that this class should not be used, that the updatable result * sets of JDBCFeatureWriter will work better. But I couldn't get those to * work at all, whereas this works great for me. We could also consider * putting the option for this or jdbc in the factory for OracleDataStore. * Should also consider using prepared statements for inserts, as they should * work faster - this should probably be done in the superclass. * * @author Chris Holmes, TOPP * @source $URL$ * @version $Id$ */ public class OracleFeatureWriter extends JDBCTextFeatureWriter { private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.data.oracle"); GeometryConverter converter; public OracleFeatureWriter(FeatureReader <SimpleFeatureType, SimpleFeature> fReader, QueryData queryData ) throws IOException { super(fReader, queryData); Connection conn = queryData.getConnection(); if(!(conn instanceof OracleConnection)) { UnWrapper uw = DataSourceFinder.getUnWrapper(conn); if(uw != null) conn = uw.unwrap(conn); } OracleConnection oracleConnection = (OracleConnection) conn; this.converter = new GeometryConverter(oracleConnection); } protected String getGeometryInsertText(Geometry geom, int srid) throws IOException { return "?"; // Please use a prepaired statement to insert your geometry //String geomText = SQLEncoderOracle.toSDOGeom(geom, srid); //return geomText; } /** * Override that uses sql statements to perform the operation. * * @see org.geotools.data.jdbc.JDBCFeatureWriter#doUpdate(org.geotools.feature.Feature, * org.geotools.feature.Feature) */ protected void doUpdate(SimpleFeature live, SimpleFeature current) throws IOException, SQLException { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("updating postgis feature " + current); } PreparedStatement statement = null; Connection conn = null; try { conn = queryData.getConnection(); String sql = makeUpdateSql(live, current); statement = conn.prepareStatement(sql); SimpleFeatureType schema = current.getFeatureType(); int position = 1; for (int i = 0; i < current.getAttributeCount(); i++) { AttributeDescriptor type = schema.getDescriptor(i); if (type instanceof GeometryDescriptor && !DataUtilities.attributesEqual(current.getAttribute(i), live.getAttribute(i))) { Geometry geometry = (Geometry) current.getAttribute(i); LOGGER.fine("ORACLE SPATIAL: geometry to be written:" + geometry); int srid = queryData.getFeatureTypeInfo().getSRID(type.getLocalName()); geometry.setSRID(srid); STRUCT struct = converter.toSDO(geometry); statement.setObject(position, struct); LOGGER.fine( "ORACLE SPATIAL: set geometry parameter at position:" + position); position++; break; } } // System.out.println(sql); LOGGER.fine(sql); statement.execute(); } catch (SQLException sqle) { String msg = "SQL Exception writing geometry column" + sqle.getLocalizedMessage(); LOGGER.log(Level.SEVERE, msg, sqle); queryData.close(sqle); throw new DataSourceException(msg, sqle); } finally { if (statement != null) { try { statement.close(); } catch (SQLException e) { String msg = "Error closing JDBC Statement"; LOGGER.log(Level.WARNING, msg, e); } } } } /** * Override that uses sql prepaired statements to perform the operation. * * @see org.geotools.data.jdbc.JDBCFeatureWriter#doInsert(org.geotools.data.jdbc.MutableFIDFeature) */ protected void doInsert(MutableFIDFeature current) throws IOException, SQLException { LOGGER.fine("inserting into postgis feature " + current); PreparedStatement statement = null; Connection conn = null; try { conn = queryData.getConnection(); String sql = makeInsertSql(current); statement = conn.prepareStatement( sql ); int position = 1; SimpleFeatureType schema = current.getFeatureType(); for( int i=0; i<current.getNumberOfAttributes();i++){ AttributeDescriptor type = schema.getDescriptor( i ); if( type instanceof GeometryDescriptor ){ Geometry geometry = (Geometry) current.getAttribute( i ); // set the proper SRID, otherwise insertion will fail due to issues // with the spatial index int srid = queryData.getFeatureTypeInfo().getSRID(type.getLocalName()); geometry.setSRID(srid); STRUCT struct = converter.toSDO( geometry ); statement.setObject( position, struct ); position++; } } LOGGER.fine(sql); statement.execute(); // should the ID be generated during an insert, we need to read it back // and set it into the feature if (((mapper.getColumnCount() > 0) && mapper.hasAutoIncrementColumns())) { // if (((mapper.getColumnCount() > 0))) { current.setID(mapper.createID(conn, current, statement)); } } catch (SQLException sqle) { String msg = "SQL Exception writing geometry column" + sqle.getLocalizedMessage(); LOGGER.log(Level.SEVERE, msg, sqle); queryData.close(sqle); throw new DataSourceException(msg, sqle); } finally { if (statement != null) { try { statement.close(); } catch (SQLException e) { String msg = "Error closing JDBC Statement"; LOGGER.log(Level.WARNING, msg, e); } } } } }