001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * Created on 16/10/2003
017: */
018: package org.geotools.data.oracle;
019:
020: import java.io.IOException;
021: import java.sql.Connection;
022: import java.sql.ResultSet;
023: import java.sql.SQLException;
024: import java.sql.Statement;
025: import java.util.ArrayList;
026: import java.util.Arrays;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Map;
030: import java.util.logging.Level;
031: import java.util.logging.Logger;
032:
033: import javax.sql.DataSource;
034: import oracle.jdbc.OracleConnection;
035: import oracle.sql.ARRAY;
036: import oracle.sql.Datum;
037: import oracle.sql.STRUCT;
038:
039: import org.geotools.data.DataSourceException;
040: import org.geotools.data.DataUtilities;
041: import org.geotools.data.DefaultQuery;
042: import org.geotools.data.DefaultTransaction;
043: import org.geotools.data.FeatureReader;
044: import org.geotools.data.FeatureSource;
045: import org.geotools.data.Query;
046: import org.geotools.data.Transaction;
047: import org.geotools.data.jdbc.DefaultSQLBuilder;
048: import org.geotools.data.jdbc.FeatureTypeInfo;
049: import org.geotools.data.jdbc.JDBCDataStore;
050: import org.geotools.data.jdbc.JDBCDataStoreConfig;
051: import org.geotools.data.jdbc.JDBCFeatureWriter;
052: import org.geotools.data.jdbc.JDBCUtils;
053: import org.geotools.data.jdbc.QueryData;
054: import org.geotools.data.jdbc.SQLBuilder;
055: import org.geotools.data.jdbc.attributeio.AttributeIO;
056: import org.geotools.data.jdbc.datasource.DataSourceFinder;
057: import org.geotools.data.jdbc.datasource.UnWrapper;
058: import org.geotools.data.oracle.attributeio.SDOAttributeIO;
059: import org.geotools.data.oracle.referencing.OracleAuthorityFactory;
060: import org.geotools.data.oracle.sdo.GeometryConverter;
061: import org.geotools.data.oracle.sdo.TT;
062: import org.geotools.feature.AttributeType;
063: import org.geotools.feature.AttributeTypeFactory;
064: import org.geotools.feature.FeatureType;
065: import org.geotools.feature.GeometryAttributeType;
066: import org.geotools.feature.SchemaException;
067: import org.geotools.filter.SQLEncoder;
068: import org.geotools.filter.SQLEncoderException;
069: import org.geotools.filter.SQLEncoderOracle;
070: import org.geotools.geometry.jts.ReferencedEnvelope;
071: import org.geotools.referencing.CRS;
072: import org.opengis.filter.Filter;
073: import org.opengis.referencing.FactoryException;
074: import org.opengis.referencing.crs.CoordinateReferenceSystem;
075: import org.opengis.referencing.crs.GeodeticCRS;
076:
077: import com.vividsolutions.jts.geom.Envelope;
078: import com.vividsolutions.jts.geom.Geometry;
079: import com.vividsolutions.jts.geom.GeometryFactory;
080: import com.vividsolutions.jts.io.ParseException;
081:
082: /**
083: * @author Sean Geoghegan, Defence Science and Technology Organisation.
084: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/oracle-spatial/src/main/java/org/geotools/data/oracle/OracleDataStore.java $
085: */
086: public class OracleDataStore extends JDBCDataStore {
087: private static final Logger LOGGER = org.geotools.util.logging.Logging
088: .getLogger("org.geotools.data.oracle");
089: private OracleAuthorityFactory af;
090:
091: /**
092: * @param connectionPool
093: * @param config
094: * @throws IOException
095: */
096: public OracleDataStore(DataSource dataSource,
097: JDBCDataStoreConfig config) throws IOException {
098: super (dataSource, config);
099: }
100:
101: /**
102: * @param connectionPool
103: * @throws DataSourceException
104: */
105: public OracleDataStore(DataSource dataSource, String schemaName,
106: Map fidGeneration) throws IOException {
107: this (dataSource, schemaName, schemaName, fidGeneration);
108: }
109:
110: /**
111: * @param connectionPool
112: * @param namespace
113: * @throws DataSourceException
114: */
115: public OracleDataStore(DataSource dataSource, String namespace,
116: String schemaName, Map fidGeneration) throws IOException {
117: //Ok, this needs more investigation, since the config constructor being
118: //used seems to ignoe the fid map stuff. I don't quite understand it,
119: //and I think it may get picked up later, or at least auto-generated
120: //later - maybe this is for the user specified stuff that never got
121: //implemented. Point being this needs to be looked into, I'm just
122: //setting it like this to get things working. -ch
123: this (dataSource, new JDBCDataStoreConfig(namespace, schemaName,
124: null, fidGeneration));
125:
126: }
127:
128: /** Crops non feature type tables.
129: * There are alot of additional tables in a Oracle tablespace. This tries
130: * to remove some of them. If the schemaName is provided in the Constructor
131: * then the job of narrowing down tables will be mush easier. Otherwise
132: * there are alot of Meta tables and SDO tables to cull. This method tries
133: * to remove as many as possible.
134: *
135: * @see org.geotools.data.jdbc.JDBCDataStore#allowTable(java.lang.String)
136: */
137: protected boolean allowTable(String tablename) {
138: LOGGER.finer("checking table name: " + tablename);
139: if (tablename.endsWith("$")) {
140: return false;
141: } else if (tablename.startsWith("BIN$")) { // Added to ignore some Oracle 10g tables
142: return false;
143: } else if (tablename.startsWith("XDB$")) {
144: return false;
145: } else if (tablename.startsWith("DR$")) {
146: return false;
147: } else if (tablename.startsWith("DEF$")) {
148: return false;
149: } else if (tablename.startsWith("SDO_")) {
150: return false;
151: } else if (tablename.startsWith("WM$")) {
152: return false;
153: } else if (tablename.startsWith("WK$")) {
154: return false;
155: } else if (tablename.startsWith("AW$")) {
156: return false;
157: } else if (tablename.startsWith("AQ$")) {
158: return false;
159: } else if (tablename.startsWith("APPLY$")) {
160: return false;
161: } else if (tablename.startsWith("REPCAT$")) {
162: return false;
163: } else if (tablename.startsWith("CWM$")) {
164: return false;
165: } else if (tablename.startsWith("CWM2$")) {
166: return false;
167: } else if (tablename.startsWith("EXF$")) {
168: return false;
169: } else if (tablename.startsWith("DM$")) {
170: return false;
171: }
172: LOGGER.finer("returning true for tablename: " + tablename);
173: return true;
174: }
175:
176: /**
177: * Overrides the buildAttributeType method to check for SDO_GEOMETRY columns.
178: *
179: * @see <a href="http://download-west.oracle.com/docs/cd/B14117_01/appdev.101/b10826.pdf">A doc from Oracle.</a>
180: *
181: * TODO: Determine the specific type of the geometry.
182: */
183: protected AttributeType buildAttributeType(ResultSet rs)
184: throws IOException {
185: final int TABLE_NAME = 3;
186: final int COLUMN_NAME = 4;
187: final int TYPE_NAME = 6;
188: final int IS_NULLABLE = 18; // "NO", "YES" or ""
189: try {
190: if (rs.getString(TYPE_NAME).equals("SDO_GEOMETRY")) {
191: String tableName = rs.getString(TABLE_NAME);
192: String columnName = rs.getString(COLUMN_NAME);
193: String isNullable = rs.getString(IS_NULLABLE);
194: return getSDOGeometryAttribute(tableName, columnName,
195: "YES".equals(isNullable));
196: } else {
197: return super .buildAttributeType(rs);
198: }
199: } catch (SQLException e) {
200: throw new DataSourceException("Sql error occurred", e);
201: }
202: }
203:
204: /**
205: * Construct and SDO_GEOMETRY attribute.
206: *
207: * @see org.geotools.data.jdbc.JDBCDataStore#buildAttributeType(java.sql.ResultSet)
208: * @param tableName
209: * @param columnName
210: * @param isNillable
211: */
212: private AttributeType getSDOGeometryAttribute(String tableName,
213: String columnName, boolean isNullable) {
214: int srid = 0; // aka NULL
215: CoordinateReferenceSystem crs = null;
216: // here we have two separate point of failure, better keep them separated,
217: try {
218: srid = determineSRID(tableName, columnName);
219: try {
220: crs = CRS.decode("EPSG:" + srid);
221: } catch (Exception e) {
222: // decode failed, let's try the internal authority
223: crs = determineCRS(srid);
224: }
225: } catch (Exception e) {
226: LOGGER.warning("Could not map SRID " + srid + " to CRS:"
227: + e);
228: }
229: try {
230: Class geomClass = determineGeometryClass(tableName,
231: columnName);
232: return AttributeTypeFactory.newAttributeType(columnName,
233: geomClass, isNullable, 0, null, crs);
234: } catch (IOException e) {
235: LOGGER.warning("Could not determine geometry class for ["
236: + tableName + "." + columnName + "]");
237: }
238: return AttributeTypeFactory.newAttributeType(columnName,
239: Geometry.class, isNullable);
240: }
241:
242: private Class determineGeometryClass(String tableName,
243: String columnName) throws IOException {
244: Connection conn = null;
245: Statement statement = null;
246: ResultSet result = null;
247: try {
248: String sqlStatement = //
249: "select meta.sdo_layer_gtype \n"
250: + "from mdsys.ALL_SDO_INDEX_INFO info \n"
251: + " inner join mdsys.user_sdo_index_metadata meta \n"
252: + " on info.index_name = meta.sdo_index_name \n" //
253: + "where info.table_name = '" + tableName + "' \n" //
254: + "and info.column_name = '" + columnName + "'";
255: String schema = config.getDatabaseSchemaName();
256: if (schema != null && !"".equals(schema)) {
257: sqlStatement += " and info.table_owner = '" + schema
258: + "'";
259: }
260: conn = getConnection(Transaction.AUTO_COMMIT);
261: LOGGER
262: .finer("the sql statement for geometry type check is "
263: + sqlStatement);
264: statement = conn.createStatement();
265: result = statement.executeQuery(sqlStatement);
266:
267: if (result.next()) {
268: String gType = result.getString(1);
269: Class geometryClass = (Class) TT.GEOM_CLASSES
270: .get(gType);
271: if (geometryClass == null)
272: geometryClass = Geometry.class;
273:
274: return geometryClass;
275: } else {
276: return Geometry.class;
277: }
278: } catch (SQLException sqle) {
279: String message = sqle.getMessage();
280: LOGGER
281: .fine("Could not determine geometry class due to an error_: "
282: + sqle);
283:
284: throw new DataSourceException(message, sqle);
285: } finally {
286: JDBCUtils.close(result);
287: JDBCUtils.close(statement);
288: JDBCUtils.close(conn, Transaction.AUTO_COMMIT, null);
289: }
290:
291: }
292:
293: protected CoordinateReferenceSystem determineCRS(int srid)
294: throws IOException {
295: try {
296: return getOracleAuthorityFactory().createCRS(srid);
297: } catch (FactoryException e) {
298: return null;
299: }
300: }
301:
302: /**
303: * @see org.geotools.data.jdbc.JDBCDataStore#determineSRID(java.lang.String, java.lang.String)
304: */
305: protected int determineSRID(String tableName,
306: String geometryColumnName) throws IOException {
307: Connection conn = null;
308: try {
309: String sqlStatement = "SELECT SRID FROM MDSYS.ALL_SDO_GEOM_METADATA "
310: + "WHERE TABLE_NAME='"
311: + tableName
312: + "' AND COLUMN_NAME='" + geometryColumnName + "'";
313: String schema = config.getDatabaseSchemaName();
314: if (schema != null && !"".equals(schema)) {
315: sqlStatement += " and OWNER = '" + schema + "'";
316: }
317: conn = getConnection(Transaction.AUTO_COMMIT);
318: LOGGER.finer("the sql statement for srid is "
319: + sqlStatement);
320: Statement statement = conn.createStatement();
321: ResultSet result = statement.executeQuery(sqlStatement);
322:
323: if (result.next()) {
324: int retSrid = result.getInt("srid");
325: JDBCUtils.close(statement);
326:
327: return retSrid;
328: } else {
329: String mesg = "No geometry column row for srid in table: "
330: + tableName
331: + ", geometry column "
332: + geometryColumnName
333: + ", be sure column is defined in USER_SDO_GEOM_METADATA";
334: throw new DataSourceException(mesg);
335: }
336: } catch (SQLException sqle) {
337: String message = sqle.getMessage();
338:
339: throw new DataSourceException(message, sqle);
340: } finally {
341: JDBCUtils.close(conn, Transaction.AUTO_COMMIT, null);
342: }
343: }
344:
345: private OracleAuthorityFactory getOracleAuthorityFactory() {
346: if (af == null) {
347: af = new OracleAuthorityFactory(dataSource);
348: }
349:
350: return af;
351: }
352:
353: /**
354: * @see org.geotools.data.jdbc.JDBCDataStore#getSqlBuilder(java.lang.String)
355: */
356: public SQLBuilder getSqlBuilder(String typeName) throws IOException {
357: FeatureTypeInfo info = typeHandler.getFeatureTypeInfo(typeName);
358: SQLEncoder encoder = new SQLEncoderOracle(info.getSRIDs());
359: encoder.setFIDMapper(getFIDMapper(typeName));
360: return new DefaultSQLBuilder(encoder, info.getSchema(), null);
361: }
362:
363: /**
364: * @see org.geotools.data.jdbc.JDBCDataStore#getGeometryAttributeIO(org.geotools.feature.AttributeType, org.geotools.data.jdbc.QueryData)
365: */
366: protected AttributeIO getGeometryAttributeIO(AttributeType type,
367: QueryData queryData) throws IOException {
368: return new SDOAttributeIO(type, queryData);
369: }
370:
371: /**
372: * Returns a Oracle text based feature writer that just issues the sql
373: * statements directly, as text. Jody and Sean say things will go faster
374: * if we use updatable resultsets and all that jazz, but I can't get
375: * those to work, and this does, so I'm going forth with it.
376: *
377: * @task TODO: Comment out this method and try out the default JDBC
378: * FeatureWriter - Jody thinks it will go faster. It will
379: * need to be debugged, however, as it would not work.
380: */
381: protected JDBCFeatureWriter createFeatureWriter(
382: FeatureReader fReader, QueryData queryData)
383: throws IOException {
384: return new OracleFeatureWriter(fReader, queryData);
385: }
386:
387: /**
388: * Retrieve approx bounds of all Features.
389: * <p>
390: * This result is suitable for a quick map display, illustrating the data.
391: * This value is often stored as metadata in databases such as oraclespatial.
392: * </p>
393: * @return null as a generic implementation is not provided.
394: */
395:
396: public Envelope getEnvelope(String typeName) {
397: try {
398: return bounds(new DefaultQuery(typeName));
399: } catch (IOException e) {
400: LOGGER.log(Level.WARNING,
401: "Could not compute feature type bounds", e);
402: return null;
403: }
404: }
405:
406: /** This is used by helper classes to hammer sql back to the database */
407: public boolean sql(Transaction t, String sql) throws IOException,
408: SQLException {
409: Connection conn = getConnection(t);
410: Statement st = conn.createStatement();
411: LOGGER.info(sql);
412: return st.execute(sql);
413: }
414:
415: public void createSchema(FeatureType featureType)
416: throws IOException {
417: String tableName = featureType.getTypeName();
418: Transaction t = new DefaultTransaction("createSchema");
419:
420: //CoordinateReferenceSystem crs = featureType.getDefaultGeometry().getCoordinateSystem();
421: // TODO: lookup srid for crs
422: Envelope bounds = new Envelope();
423: bounds.expandToInclude(-180, -90);
424: bounds.expandToInclude(180, 90);
425: int srid = -1;
426:
427: SQLEncoderOracle encoder = new SQLEncoderOracle("fid", srid); // should figure out from encoding
428: SqlStatementEncoder statements = new SqlStatementEncoder(
429: encoder, tableName, "fid");
430:
431: try {
432: sql(t, "DROP TABLE " + tableName);
433: sql(t,
434: "DELETE FROM user_sdo_geom_metadata WHERE TABLE_NAME='"
435: + tableName + "'");
436: } catch (SQLException ignore) {
437: // table probably did not exist
438: }
439: try {
440: sql(t, statements.makeCreateTableSQL(featureType));
441:
442: sql(t, statements.makeAddGeomMetadata(featureType, bounds,
443: srid));
444: //sql( t, statements.makeCreateFidIndex() );
445: //sql( t, statements.makeCreateGeomIndex( featureType ) );
446:
447: t.commit();
448:
449: } catch (SQLException e) {
450: t.rollback();
451: throw (IOException) new IOException(e.getLocalizedMessage())
452: .initCause(e);
453: } finally {
454: t.close();
455: }
456: }
457:
458: /**
459: * Default implementation based on getFeatureReader and getFeatureWriter.
460: *
461: * <p>
462: * We should be able to optimize this to only get the RowSet once
463: * </p>
464: *
465: * @see org.geotools.data.DataStore#getFeatureSource(java.lang.String)
466: */
467: public FeatureSource getFeatureSource(String typeName)
468: throws IOException {
469: if (!typeHandler.getFIDMapper(typeName).isVolatile()
470: || allowWriteOnVolatileFIDs) {
471: if (getLockingManager() != null) {
472: // Use default JDBCFeatureLocking that delegates all locking
473: // the getLockingManager
474: //
475: return new OracleFeatureLocking(this ,
476: getSchema(typeName));
477: } else {
478: // subclass should provide a FeatureLocking implementation
479: // but for now we will simply forgo all locking
480: return new OracleFeatureStore(this , getSchema(typeName));
481: }
482: } else {
483: return new OracleFeatureSource(this , getSchema(typeName));
484: }
485: }
486:
487: /**
488: * This is (unfortunately) a copy and paste from PostgisFeatureStore, I simply did not
489: * know a better place to put this...
490: * @param query
491: * @return
492: * @throws IOException
493: */
494: protected ReferencedEnvelope bounds(Query query) throws IOException {
495: Filter filter = query.getFilter();
496:
497: if (filter == Filter.EXCLUDE) {
498: return new ReferencedEnvelope(new Envelope(), query
499: .getCoordinateSystem());
500: }
501:
502: FeatureType schema = getSchema(query.getTypeName());
503: SQLBuilder sqlBuilder = getSqlBuilder(schema.getTypeName());
504:
505: Filter postQueryFilter = sqlBuilder.getPostQueryFilter(query
506: .getFilter());
507: if (postQueryFilter != null
508: && !postQueryFilter.equals(Filter.INCLUDE)) {
509: // this would require postprocessing the filter
510: // so we cannot optimize
511: return null;
512: }
513:
514: Connection conn = null;
515: try {
516: conn = getConnection(Transaction.AUTO_COMMIT);
517:
518: Envelope retEnv = new Envelope();
519: Filter preFilter = sqlBuilder.getPreQueryFilter(query
520: .getFilter());
521: AttributeType[] attributeTypes = schema.getAttributeTypes();
522: FeatureType schemaNew = schema;
523: if (!query.retrieveAllProperties()) {
524: try {
525: schemaNew = DataUtilities.createSubType(schema,
526: query.getPropertyNames());
527: if (schemaNew.getDefaultGeometry() == null) // does the sub-schema have a
528: // geometry in it?
529: {
530: // uh-oh better get one!
531: if (schema.getDefaultGeometry() != null) // does the entire schema have a
532: // geometry in it?
533: {
534: // buff-up the sub-schema so it has the default geometry in it.
535: ArrayList al = new ArrayList(Arrays
536: .asList(query.getPropertyNames()));
537: al.add(schema.getDefaultGeometry()
538: .getName());
539: schemaNew = DataUtilities.createSubType(
540: schema, (String[]) al
541: .toArray(new String[1]));
542: }
543: }
544: } catch (SchemaException e1) {
545: throw new DataSourceException(
546: "Could not create subtype", e1);
547: }
548: }
549: // at this point, the query should have a geometry in it.
550: // BUT, if there's no geometry in the table, then the query will not (obviously) have a
551: // geometry in it.
552:
553: attributeTypes = schemaNew.getAttributeTypes();
554:
555: for (int j = 0, n = schemaNew.getAttributeCount(); j < n; j++) {
556: if (Geometry.class.isAssignableFrom(attributeTypes[j]
557: .getType())) // same as
558: // .isgeometry()
559: // - see new
560: // featuretype
561: // javadoc
562: {
563: String attName = attributeTypes[j].getName();
564: Envelope curEnv = getEnvelope(conn, schemaNew,
565: attName, sqlBuilder, filter);
566:
567: if (curEnv == null) {
568: return null;
569: }
570:
571: retEnv.expandToInclude(curEnv);
572: }
573: }
574:
575: LOGGER.finer("returning bounds " + retEnv);
576:
577: if ((schemaNew != null)
578: && (schemaNew.getDefaultGeometry() != null))
579: return new ReferencedEnvelope(retEnv, schemaNew
580: .getDefaultGeometry().getCoordinateSystem());
581: if (query.getCoordinateSystem() != null)
582: return new ReferencedEnvelope(retEnv, query
583: .getCoordinateSystem());
584: return new ReferencedEnvelope(retEnv, null);
585: } catch (SQLException sqlException) {
586: JDBCUtils
587: .close(conn, Transaction.AUTO_COMMIT, sqlException);
588: conn = null;
589: throw new DataSourceException("Could not count "
590: + query.getHandle(), sqlException);
591: } catch (SQLEncoderException e) {
592: // could not encode count
593: // but at least we did not break the connection
594: return null;
595: } catch (ParseException parseE) {
596: String message = "Could not read geometry: "
597: + parseE.getMessage();
598:
599: return null;
600: } finally {
601: JDBCUtils.close(conn, Transaction.AUTO_COMMIT, null);
602: }
603: }
604:
605: protected Envelope getEnvelope(Connection conn, FeatureType schema,
606: String geomName, SQLBuilder sqlBuilder, Filter filter)
607: throws SQLException, SQLEncoderException, IOException,
608: ParseException {
609:
610: StringBuffer sql = new StringBuffer();
611: GeometryAttributeType gat = (GeometryAttributeType) schema
612: .getAttributeType(geomName);
613: // from the Oracle docs: "The SDO_TUNE.EXTENT_OF function has better performance than the
614: // SDO_AGGR_MBR function if the data is non-geodetic and if a spatial index is defined
615: // on the geometry column; however, the SDO_TUNE.EXTENT_OF function is limited to
616: // two-dimensional geometries, whereas the SDO_AGGR_MBR function is not".
617: // And also: "In addition, the SDO_TUNE.EXTENT_OF function computes the extent for all
618: // geometries in a table; by contrast, the SDO_AGGR_MBR function can operate on
619: // subsets of rows. The SDO_TUNE.EXTENT_OF function returns NULL if the data is inconsistent."
620: // Long story short: under restrictive conditions SDO_TUNE.EXTENT_OF works, but we have
621: // to be prepared to fall back on SDO_AGGR_MBR.
622: List queries = new ArrayList();
623: if (Filter.INCLUDE.equals(filter)
624: && !(gat.getCoordinateSystem() instanceof GeodeticCRS)) {
625: sql.append("SELECT SDO_TUNE.EXTENT_OF('").append(
626: schema.getTypeName()).append("', '");
627: sql.append(geomName).append("') from dual");
628: queries.add(sql.toString());
629: sql = new StringBuffer();
630: }
631: sql.append("SELECT SDO_AGGR_MBR(").append(geomName)
632: .append(") ");
633: sqlBuilder.sqlFrom(sql, schema.getTypeName());
634: sqlBuilder.sqlWhere(sql, filter);
635: queries.add(sql.toString());
636:
637: LOGGER.fine("SQL: " + sql);
638:
639: // loop over the (eventual) two sql statements, so that if the first does not provide
640: // an answer, we fall back on the second
641: Statement statement = null;
642: ResultSet results = null;
643: Envelope result = null;
644: for (Iterator it = queries.iterator(); it.hasNext();) {
645: String query = (String) it.next();
646: try {
647: statement = conn.createStatement();
648: results = statement.executeQuery(query);
649:
650: results.next();
651:
652: Geometry geom = null;
653: Object struct = results.getObject(1);
654: UnWrapper unwrapper = DataSourceFinder
655: .getUnWrapper(conn);
656: OracleConnection oraConn = (OracleConnection) unwrapper
657: .unwrap(conn);
658: GeometryConverter converter = new GeometryConverter(
659: oraConn, new GeometryFactory());
660: geom = converter.asGeometry((STRUCT) struct);
661:
662: // Oracle may return a point, a line or a polygon
663: if (geom != null)
664: return geom.getEnvelopeInternal();
665: } finally {
666: JDBCUtils.close(results);
667: JDBCUtils.close(statement);
668: }
669: }
670: return result;
671: }
672: }
|