From f7f39cb8d29a8315b0166221a5e6b856ee736794 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Mon, 22 Aug 2011 22:05:56 +0200 Subject: [PATCH] HHH-6510 Added Oracle SDOGeometry support. --- hibernate-spatial/hibernate-spatial.gradle | 1 + .../dialect/oracle/ConnectionFinder.java | 52 ++ .../oracle/DefaultConnectionFinder.java | 119 ++++ .../spatial/dialect/oracle/ElemInfo.java | 118 ++++ .../spatial/dialect/oracle/ElementType.java | 93 +++ .../dialect/oracle/GetDimensionFunction.java | 56 ++ .../oracle/GetGeometryTypeFunction.java | 62 ++ .../dialect/oracle/OracleJDBCTypeFactory.java | 213 +++++++ .../oracle/OracleSpatial10gDialect.java | 591 ++++++++++++++++++ .../spatial/dialect/oracle/Ordinates.java | 72 +++ .../dialect/oracle/SDOBooleanType.java | 78 +++ .../spatial/dialect/oracle/SDOGType.java | 105 ++++ .../spatial/dialect/oracle/SDOGeometry.java | 325 ++++++++++ .../oracle/SDOGeometryTypeDescriptor.java | 39 ++ .../oracle/SDOGeometryValueBinder.java | 357 +++++++++++ .../oracle/SDOGeometryValueExtractor.java | 522 ++++++++++++++++ .../dialect/oracle/SDOObjectMethod.java | 109 ++++ .../dialect/oracle/SDOObjectProperty.java | 104 +++ .../spatial/dialect/oracle/SDOPoint.java | 37 ++ .../dialect/oracle/SpatialAggregate.java | 91 +++ .../spatial/dialect/oracle/StructLoader.java | 20 + .../spatial/dialect/oracle/TypeGeometry.java | 32 + .../dialect/oracle/WrappedOGCFunction.java | 77 +++ .../criterion/OracleSpatialAggregate.java | 48 ++ .../criterion/OracleSpatialProjection.java | 86 +++ .../criterion/OracleSpatialProjections.java | 60 ++ .../criterion/OracleSpatialRestrictions.java | 204 ++++++ .../oracle/criterion/RelationshipMask.java | 45 ++ .../oracle/criterion/SDOParameterMap.java | 192 ++++++ .../SqlServer2008GeometryValueBinder.java | 8 + .../SqlServer2008GeometryValueExtractor.java | 8 + .../integration/SpatialIntegrator.java | 6 + .../spatial/SpatialFunctionalTestCase.java | 1 - .../spatial/TestSupportFactories.java | 6 +- .../dialect/oracle/JDBCConnectionProxy.java | 234 +++++++ .../dialect/oracle/OracleSDOTestSupport.java | 37 ++ .../dialect/oracle/SDODataSourceUtils.java | 74 +++ .../SDOGeometryExpectationsFactory.java | 270 ++++++++ .../oracle/SDOGeometryExpressionTemplate.java | 39 ++ .../dialect/oracle/SDOTestDataElement.java | 47 ++ .../dialect/oracle/SDOTestDataReader.java | 50 ++ .../src/test/resources/hibernate.properties | 18 +- ....oracle.OracleSpatial10gDialect.properties | 27 + .../test-sdo-geometry-data-set-2D.xml | 282 +++++++++ .../resources/test-sdo-geometry-data-set.xml | 401 ++++++++++++ 45 files changed, 5407 insertions(+), 9 deletions(-) create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ConnectionFinder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/DefaultConnectionFinder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElemInfo.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElementType.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetDimensionFunction.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetGeometryTypeFunction.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleJDBCTypeFactory.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatial10gDialect.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/Ordinates.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOBooleanType.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGType.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometry.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryTypeDescriptor.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueBinder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueExtractor.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectMethod.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOPoint.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SpatialAggregate.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/StructLoader.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/TypeGeometry.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/WrappedOGCFunction.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialAggregate.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjection.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjections.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialRestrictions.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/RelationshipMask.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/SDOParameterMap.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/JDBCConnectionProxy.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/OracleSDOTestSupport.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDODataSourceUtils.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpectationsFactory.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpressionTemplate.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataElement.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataReader.java create mode 100644 hibernate-spatial/src/test/resources/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties create mode 100644 hibernate-spatial/src/test/resources/test-sdo-geometry-data-set-2D.xml create mode 100644 hibernate-spatial/src/test/resources/test-sdo-geometry-data-set.xml diff --git a/hibernate-spatial/hibernate-spatial.gradle b/hibernate-spatial/hibernate-spatial.gradle index 199f179f11..6f806d9382 100644 --- a/hibernate-spatial/hibernate-spatial.gradle +++ b/hibernate-spatial/hibernate-spatial.gradle @@ -20,6 +20,7 @@ dependencies { testCompile( libraries.junit ) testCompile( project(':hibernate-testing') ) testCompile( [group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4']) + testCompile([group: 'com.oracle.jdbc', name:'ojdbc6', version:'11.1.0.7.0']) } sourceSets { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ConnectionFinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ConnectionFinder.java new file mode 100644 index 0000000000..46dd8ef80f --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ConnectionFinder.java @@ -0,0 +1,52 @@ +/** + * $Id: ConnectionFinder.java 268 2010-10-28 19:16:54Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.Connection; + +import org.hibernate.spatial.helper.FinderStrategy; + +/** + * The ConnectionFinder returns an OracleConnection when given a + * Connection object. + *

+ * The SDOGeometryType requires access to an OracleConnection + * object when converting a geometry to SDOGeometry, prior to + * setting the geometry attribute in prepared statements. In some environments + * the prepared statements do not return an OracleConnection but + * a wrapper. Implementations of this interface attempt to retrieve the + * OracleConnection from the wrapper in such cases. + *

+ * + * @author Karel Maesen + */ +public interface ConnectionFinder extends + FinderStrategy { + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/DefaultConnectionFinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/DefaultConnectionFinder.java new file mode 100644 index 0000000000..4f1807b508 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/DefaultConnectionFinder.java @@ -0,0 +1,119 @@ +/** + * $Id: DefaultConnectionFinder.java 286 2011-02-04 21:16:23Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle; + + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.Connection; + +import org.hibernate.HibernateException; +import org.hibernate.spatial.helper.FinderException; + +/** + * Default ConnectionFinder implementation. + *

+ * This implementation attempts to retrieve the OracleConnection + * by recursive reflection: it searches for methods that return + * Connection objects, executes these methods and checks the + * result. If the result is of type OracleConnection the object + * is returned, otherwise it recurses on it. + *

+ *

+ * + * @author Karel Maesen + */ +public class DefaultConnectionFinder implements ConnectionFinder { + + private final static Class oracleConnectionClass; + + static { + try { + oracleConnectionClass = Class.forName( "oracle.jdbc.driver.OracleConnection" ); + } + catch ( ClassNotFoundException e ) { + throw new HibernateException( "Can't find Oracle JDBC Driver on classpath." ); + } + } + + public Connection find(Connection con) throws FinderException { + if ( con == null ) { + return null; + } + + if ( oracleConnectionClass.isInstance( con ) ) { + return con; + } + // try to find the Oracleconnection recursively + for ( Method method : con.getClass().getMethods() ) { + if ( method.getReturnType().isAssignableFrom( + java.sql.Connection.class + ) + && method.getParameterTypes().length == 0 ) { + + try { + method.setAccessible( true ); + Connection oc = find( (Connection) ( method.invoke( con, new Object[] { } ) ) ); + if ( oc == null ) { + throw new FinderException( + String.format( + "Tried retrieving OracleConnection from %s using method %s, but received null.", + con.getClass().getCanonicalName(), + method.getName() + ) + ); + } + return oc; + } + catch ( IllegalAccessException e ) { + throw new FinderException( + String.format( + "Illegal access on executing method %s when finding OracleConnection", + method.getName() + ) + ); + } + catch ( InvocationTargetException e ) { + throw new FinderException( + String.format( + "Invocation exception on executing method %s when finding OracleConnection", + method.getName() + ) + ); + } + + + } + } + throw new FinderException( + "Couldn't get at the OracleSpatial Connection object from the PreparedStatement." + ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElemInfo.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElemInfo.java new file mode 100644 index 0000000000..82e6c8f61d --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElemInfo.java @@ -0,0 +1,118 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.math.BigDecimal; +import java.sql.Array; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jul 1, 2010 + */ +class ElemInfo { + + static final String TYPE_NAME = "MDSYS.SDO_ELEM_INFO_ARRAY"; + + private BigDecimal[] triplets; + + public ElemInfo(int size) { + this.triplets = new BigDecimal[3 * size]; + } + + public ElemInfo(BigDecimal[] elem_info) { + this.triplets = elem_info; + } + + public ElemInfo(Array array) { + if (array == null) { + this.triplets = new BigDecimal[]{}; + return; + } + try { + triplets = (BigDecimal[]) array.getArray(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + public BigDecimal[] getElements() { + return this.triplets; + } + + public int getSize() { + return this.triplets.length / 3; + } + + public int getOrdinatesOffset(int i) { + return this.triplets[i * 3].intValue(); + } + + public void setOrdinatesOffset(int i, int offset) { + this.triplets[i * 3] = new BigDecimal(offset); + } + + public ElementType getElementType(int i) { + int etype = this.triplets[i * 3 + 1].intValue(); + int interp = this.triplets[i * 3 + 2].intValue(); + ElementType et = ElementType.parseType(etype, interp); + return et; + } + + public boolean isCompound(int i) { + return getElementType(i).isCompound(); + } + + public int getNumCompounds(int i) { + if (getElementType(i).isCompound()) { + return this.triplets[i * 3 + 2].intValue(); + } else { + return 1; + } + } + + public void setElement(int i, int ordinatesOffset, ElementType et, + int numCompounds) { + if (i > getSize()) { + throw new RuntimeException( + "Attempted to set more elements in ElemInfo Array than capacity."); + } + this.triplets[i * 3] = new BigDecimal(ordinatesOffset); + this.triplets[i * 3 + 1] = new BigDecimal(et.getEType()); + this.triplets[i * 3 + 2] = et.isCompound() ? new BigDecimal(numCompounds) : new BigDecimal(et + .getInterpretation()); + } + + public String toString() { + return SDOGeometry.arrayToString(this.triplets); + } + + public void addElement(BigDecimal[] element) { + BigDecimal[] newTriplets = new BigDecimal[this.triplets.length + element.length]; + System.arraycopy(this.triplets, 0, newTriplets, 0, + this.triplets.length); + System.arraycopy(element, 0, newTriplets, this.triplets.length, + element.length); + this.triplets = newTriplets; + } + + public void addElement(ElemInfo element) { + this.addElement(element.getElements()); + } + + public BigDecimal[] getElement(int i) { + BigDecimal[] ea = null; + if (this.getElementType(i).isCompound()) { + int numCompounds = this.getNumCompounds(i); + ea = new BigDecimal[numCompounds + 1]; + } else { + ea = new BigDecimal[3]; + } + System.arraycopy(this.triplets, 3 * i, ea, 0, ea.length); + return ea; + } + +// public ARRAY toOracleArray(Connection conn) throws SQLException { +// ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor( +// TYPE_NAME, conn); +// return new ARRAY(arrayDescriptor, conn, this.triplets); +// } +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElementType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElementType.java new file mode 100644 index 0000000000..c0eb74a4d9 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/ElementType.java @@ -0,0 +1,93 @@ +package org.hibernate.spatial.dialect.oracle; + + + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jul 1, 2010 + */ +enum ElementType { + UNSUPPORTED(0, true), POINT(1, 1), ORIENTATION(1, 0), POINT_CLUSTER(1, + true), LINE_STRAITH_SEGMENTS(2, 1), LINE_ARC_SEGMENTS(2, 2), INTERIOR_RING_STRAIGHT_SEGMENTS( + 2003, 1), EXTERIOR_RING_STRAIGHT_SEGMENTS(1003, 1), INTERIOR_RING_ARC_SEGMENTS( + 2003, 2), EXTERIOR_RING_ARC_SEGMENTS(1003, 2), INTERIOR_RING_RECT( + 2003, 3), EXTERIOR_RING_RECT(1003, 3), INTERIOR_RING_CIRCLE( + 2003, 4), EXTERIOR_RING_CIRCLE(1003, 4), COMPOUND_LINE(4, true), COMPOUND_EXTERIOR_RING( + 1005, true), COMPOUND_INTERIOR_RING(2005, true); + + private int etype; + + private int interpretation = 2; + + private boolean compound = false; + + private ElementType(int etype, int interp) { + this.etype = etype; + this.interpretation = interp; + + } + + private ElementType(int etype, boolean compound) { + this.etype = etype; + this.compound = compound; + } + + public int getEType() { + return this.etype; + } + + public int getInterpretation() { + return this.interpretation; + } + + /** + * @return true, if the SDO_INTERPRETATION value is the number of points + * or compounds in the element. + */ + public boolean isCompound() { + return this.compound; + } + + public boolean isLine() { + return (etype == 2 || etype == 4); + } + + public boolean isInteriorRing() { + return (etype == 2003 || etype == 2005); + } + + public boolean isExteriorRing() { + return (etype == 1003 || etype == 1005); + } + + public boolean isStraightSegment() { + return (interpretation == 1); + } + + public boolean isArcSegment() { + return (interpretation == 2); + } + + public boolean isCircle() { + return (interpretation == 4); + } + + public boolean isRect() { + return (interpretation == 3); + } + + public static ElementType parseType(int etype, int interpretation) { + for (ElementType t : values()) { + if (t.etype == etype) { + if (t.isCompound() + || t.getInterpretation() == interpretation) { + return t; + } + } + } + throw new RuntimeException( + "Can't determine ElementType from etype:" + etype + + " and interp.:" + interpretation); + } + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetDimensionFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetDimensionFunction.java new file mode 100644 index 0000000000..e5ee0e3eb4 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetDimensionFunction.java @@ -0,0 +1,56 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import java.util.List; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.Type; + +/** + * Implements OGC function dimension for HQL. + */ +class GetDimensionFunction extends SDOObjectMethod { + + GetDimensionFunction() { + super("Get_Dims", StandardBasicTypes.INTEGER); + } + + public String render(Type firstArgumentType, final List args, + final SessionFactoryImplementor factory) { + StringBuffer buf = new StringBuffer(); + if (args.isEmpty()) { + throw new IllegalArgumentException( + "First Argument in arglist must be object to " + + "which method is applied"); + } + + buf.append(args.get(0)).append(".").append( + getName()).append("()"); + return buf.toString(); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetGeometryTypeFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetGeometryTypeFunction.java new file mode 100644 index 0000000000..43e1bc7e6e --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/GetGeometryTypeFunction.java @@ -0,0 +1,62 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import java.util.List; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.Type; + +/** + * HQL Implementation for the geometry ype function. + */ +class GetGeometryTypeFunction extends SDOObjectMethod { + + GetGeometryTypeFunction() { + super("Get_GType", StandardBasicTypes.STRING); + } + + public String render(Type firstArgumentType, final List args, + final SessionFactoryImplementor factory) { + StringBuffer buf = new StringBuffer(); + if (args.isEmpty()) { + throw new IllegalArgumentException( + "First Argument in arglist must be object to which" + + " method is applied"); + } + + buf.append("CASE ").append(args.get(0)).append(".").append( + getName()).append("()"); + buf.append(" WHEN 1 THEN 'POINT'").append( + " WHEN 2 THEN 'LINESTRING'").append( + " WHEN 3 THEN 'POLYGON'").append( + " WHEN 5 THEN 'MULTIPOINT'").append( + " WHEN 6 THEN 'MULTILINE'").append( + " WHEN 7 THEN 'MULTIPOLYGON'").append(" END"); + return buf.toString(); + } +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleJDBCTypeFactory.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleJDBCTypeFactory.java new file mode 100644 index 0000000000..0594d867de --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleJDBCTypeFactory.java @@ -0,0 +1,213 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.Array; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Struct; + +import org.hibernate.HibernateException; +import org.hibernate.internal.util.ReflectHelper; +import org.hibernate.spatial.helper.FinderException; + +/** + * Factory for Oracle JDBC extension types (ARRAY, STRUCT, ...). + * + * This factory creates the Oracle extension types using reflection in order to + * avoid creating compile-time dependencies on the proprietary Oracle driver. + * + * @author Karel Maesen, Geovise BVBA + * creation-date: Jul 3, 2010 + */ +public class OracleJDBCTypeFactory implements SQLTypeFactory { + + private static Class datumClass; + private static Class numberClass; + private static Class arrayClass; + private static Class structClass; + private static Class arrayDescriptorClass; + private static Class structDescriptorClass; + private static Method structDescriptorCreator; + private static Method arrayDescriptorCreator; + private static Constructor numberConstructor; + private static Constructor arrayConstructor; + private static Constructor structConstructor; + + + static { + Object[] obj = findDescriptorCreator( "oracle.sql.StructDescriptor" ); + structDescriptorClass = (Class) obj[0]; + structDescriptorCreator = (Method) obj[1]; + obj = findDescriptorCreator( "oracle.sql.ArrayDescriptor" ); + arrayDescriptorClass = (Class) obj[0]; + arrayDescriptorCreator = (Method) obj[1]; + datumClass = findClass( "oracle.sql.Datum" ); + numberClass = findClass( "oracle.sql.NUMBER" ); + arrayClass = findClass( "oracle.sql.ARRAY" ); + structClass = findClass( "oracle.sql.STRUCT" ); + + numberConstructor = findConstructor( numberClass, java.lang.Integer.TYPE ); + arrayConstructor = findConstructor( arrayClass, arrayDescriptorClass, Connection.class, Object.class ); + structConstructor = findConstructor( structClass, structDescriptorClass, Connection.class, Object[].class ); + } + + private static ConnectionFinder connectionFinder = new DefaultConnectionFinder(); + + private static Constructor findConstructor(Class clazz, Class... arguments) { + try { + return clazz.getConstructor( arguments ); + } + catch ( NoSuchMethodException e ) { + throw new HibernateException( "Error finding constructor for oracle.sql type.", e ); + } + } + + private static Class findClass(String name) { + try { + return ReflectHelper.classForName( name ); + } + catch ( ClassNotFoundException e ) { + throw new HibernateException( "Class 'oracle.sql.Datum' not found on class path" ); + } + } + + private static Object[] findDescriptorCreator(String className) { + try { + Class clazz = ReflectHelper.classForName( className ); + Method m = clazz.getMethod( + "createDescriptor", + String.class, + Connection.class + ); + return new Object[] { clazz, m }; + } + catch ( ClassNotFoundException e ) { + throw new HibernateException( "Class 'StructDescriptor' not found on classpath" ); + } + catch ( NoSuchMethodException e ) { + throw new HibernateException( "Class 'StructDescriptor' has no method 'createDescriptor(String,Connection)'" ); + } + } + + static ConnectionFinder getConnectionFinder() { + return connectionFinder; + } + + static void setConnectionFinder(ConnectionFinder finder) { + connectionFinder = finder; + } + + + public Struct createStruct(SDOGeometry geom, Connection conn) throws SQLException { + Connection oracleConnection = null; + try { + oracleConnection = connectionFinder.find( conn ); + } + catch ( FinderException e ) { + throw new HibernateException( "Problem finding Oracle Connection", e ); + } + + Object structDescriptor = createStructDescriptor( SDOGeometry.getTypeName(), oracleConnection ); + Object[] attributes = createDatumArray( 5 ); + attributes[0] = createNumber( geom.getGType().intValue() ); + if ( geom.getSRID() > 0 ) { + attributes[1] = createNumber( geom.getSRID() ); + } + else { + attributes[1] = null; + } + attributes[3] = createElemInfoArray( geom.getInfo(), oracleConnection ); + attributes[4] = createOrdinatesArray( geom.getOrdinates(), oracleConnection ); + return createStruct( structDescriptor, oracleConnection, attributes ); + } + + public Array createElemInfoArray(ElemInfo elemInfo, Connection conn) { + Object arrayDescriptor = createArrayDescriptor( ElemInfo.TYPE_NAME, conn ); + return createArray( arrayDescriptor, conn, elemInfo.getElements() ); + } + + + public Array createOrdinatesArray(Ordinates ordinates, Connection conn) throws SQLException { + Object arrayDescriptor = createArrayDescriptor( Ordinates.TYPE_NAME, conn ); + return createArray( arrayDescriptor, conn, ordinates.getOrdinateArray() ); + + } + + + private Array createArray(Object descriptor, Connection conn, Object[] data) { + try { + return (Array) arrayConstructor.newInstance( descriptor, conn, data ); + } + catch ( InstantiationException e ) { + throw new HibernateException( "Problem creating ARRAY.", e ); + } + catch ( IllegalAccessException e ) { + throw new HibernateException( "Problem creating ARRAY.", e ); + } + catch ( InvocationTargetException e ) { + throw new HibernateException( "Problem creating ARRAY.", e ); + } + } + + private Struct createStruct(Object descriptor, Connection conn, Object[] attributes) { + try { + return (Struct) structConstructor.newInstance( descriptor, conn, attributes ); + } + catch ( InstantiationException e ) { + throw new HibernateException( "Problem creating STRUCT.", e ); + } + catch ( IllegalAccessException e ) { + throw new HibernateException( "Problem creating STRUCT.", e ); + } + catch ( InvocationTargetException e ) { + throw new HibernateException( "Problem creating STRUCT.", e ); + } + } + + private Object createStructDescriptor(String sqlType, Connection conn) { + try { + return structDescriptorCreator.invoke( null, sqlType, conn ); + } + catch ( IllegalAccessException e ) { + throw new HibernateException( "Error creating oracle STRUCT", e ); + } + catch ( InvocationTargetException e ) { + throw new HibernateException( "Error creating oracle STRUCT", e ); + } + } + + private Object createArrayDescriptor(String name, Connection conn) { + try { + return arrayDescriptorCreator.invoke( null, name, conn ); + } + catch ( IllegalAccessException e ) { + throw new HibernateException( "Error creating oracle ARRAY", e ); + } + catch ( InvocationTargetException e ) { + throw new HibernateException( "Error creating oracle ARRAY", e ); + } + } + + private Object[] createDatumArray(int size) { + return (Object[]) java.lang.reflect.Array.newInstance( datumClass, size ); + + } + + private Object createNumber(int obj) { + try { + return numberConstructor.newInstance( obj ); + } + catch ( InvocationTargetException e ) { + throw new HibernateException( "Error creating oracle NUMBER", e ); + } + catch ( InstantiationException e ) { + throw new HibernateException( "Error creating oracle NUMBER", e ); + } + catch ( IllegalAccessException e ) { + throw new HibernateException( "Error creating oracle NUMBER", e ); + } + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatial10gDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatial10gDialect.java new file mode 100644 index 0000000000..ca150d129f --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatial10gDialect.java @@ -0,0 +1,591 @@ +/* + * $Id: OracleSpatial10gDialect.java 309 2011-05-18 14:04:23Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.hibernate.QueryException; +import org.hibernate.dialect.Oracle10gDialect; +import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.spatial.GeometryType; +import org.hibernate.spatial.SpatialAnalysis; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.SpatialFunction; +import org.hibernate.spatial.SpatialGeometrySqlTypeDescriptor; +import org.hibernate.spatial.SpatialRelation; +import org.hibernate.spatial.dialect.oracle.criterion.OracleSpatialAggregate; +import org.hibernate.spatial.helper.PropertyFileReader; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.Type; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +/** + * Spatial Dialect for Oracle10g databases. + * + * @author Karel Maesen + */ +public class OracleSpatial10gDialect extends Oracle10gDialect implements + SpatialDialect, Serializable { + + + /** + * Implementation of the OGC astext function for HQL. + */ + private class AsTextFunction extends StandardSQLFunction { + + private AsTextFunction() { + super("astext", StandardBasicTypes.STRING); + } + + public String render(Type firstArgumentType, final List args, + final SessionFactoryImplementor factory) { + + StringBuffer buf = new StringBuffer(); + if (args.isEmpty()) { + throw new IllegalArgumentException( + "First Argument in arglist must be object " + + "to which method is applied"); + } + + buf.append("TO_CHAR(SDO_UTIL.TO_WKTGEOMETRY(").append(args.get(0)) + .append("))"); + return buf.toString(); + } + } + + + /** + * HQL Spatial relation function. + */ + private class SpatialRelateFunction extends StandardSQLFunction { + private final int relation; + + private SpatialRelateFunction(final String name, final int relation) { + super(name, isOGCStrict() ? StandardBasicTypes.BOOLEAN + : new SDOBooleanType()); + this.relation = relation; + } + + public String render(Type firstArgumentType, final List args, + final SessionFactoryImplementor factory) { + + if (args.size() < 2) { + throw new QueryException( + "Spatial relate functions require at least two arguments"); + } + + String srf; + return isOGCStrict() ? + getOGCSpatialRelateSQL((String) args.get(0), + (String) args.get(1), this.relation) : + getNativeSpatialRelateSQL((String) args.get(0), + (String) args.get(1), this.relation); + } + + } + + private class SpatialAnalysisFunction extends StandardSQLFunction { + private final int analysis; + + private SpatialAnalysisFunction(String name, Type returnType, + int analysis) { + super(name, returnType); + this.analysis = analysis; + } + + public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) { + return isOGCStrict() ? getSpatialAnalysisSQL(args, this.analysis, + false) : getNativeSpatialAnalysisSQL(args, analysis); + } + + } + + private class SpatialAggregationFunction extends StandardSQLFunction { + + private final int aggregation; + + private SpatialAggregationFunction(String name, Type returnType, + boolean isProjection, int aggregation) { + super(name, returnType); + this.aggregation = aggregation; + } + + public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) { + return getNativeSpatialAggregateSQL((String) args.get(0), + this.aggregation); + } + } + + public final static String SHORT_NAME = "oraclespatial"; + + private final static String CONNECTION_FINDER_PROPERTY = "CONNECTION-FINDER"; + + private final static Logger log = LoggerFactory + .getLogger(OracleSpatial10gDialect.class); + + private String OGC_STRICT = "OGC_STRICT"; + + private Map features = new HashMap(); + + public OracleSpatial10gDialect() { + super(); + // initialise features to default + features.put(OGC_STRICT, new Boolean(true)); + + // read configuration information from + // classpath + configure(); + + // register geometry type + registerColumnType(java.sql.Types.STRUCT, "MDSYS.SDO_GEOMETRY"); + + // registering OGC functions + // (spec_simplefeatures_sql_99-04.pdf) + + // section 2.1.1.1 + registerFunction("dimension", new GetDimensionFunction()); + registerFunction("geometrytype", new GetGeometryTypeFunction()); + registerFunction("srid", new SDOObjectProperty("SDO_SRID", + StandardBasicTypes.INTEGER)); + registerFunction("envelope", + new StandardSQLFunction("SDO_GEOM.SDO_MBR", GeometryType.INSTANCE)); + registerFunction("astext", new AsTextFunction()); + + registerFunction("asbinary", new StandardSQLFunction( + "SDO_UTIL.TO_WKBGEOMETRY", StandardBasicTypes.BINARY)); + registerFunction("isempty", new WrappedOGCFunction("OGC_ISEMPTY", + StandardBasicTypes.BOOLEAN, new boolean[]{true})); + registerFunction("issimple", new WrappedOGCFunction("OGC_ISSIMPLE", + StandardBasicTypes.BOOLEAN, new boolean[]{true})); + registerFunction("boundary", new WrappedOGCFunction("OGC_BOUNDARY", + GeometryType.INSTANCE, + new boolean[]{true})); + + // registerFunction("area", new AreaFunction()); + + // Register functions for spatial relation constructs + // section 2.1.1.2 + registerFunction("overlaps", new SpatialRelateFunction("overlaps", + SpatialRelation.OVERLAPS)); + registerFunction("intersects", new SpatialRelateFunction("intersects", + SpatialRelation.INTERSECTS)); + registerFunction("contains", new SpatialRelateFunction("contains", + SpatialRelation.CONTAINS)); + registerFunction("crosses", new SpatialRelateFunction("crosses", + SpatialRelation.CROSSES)); + registerFunction("disjoint", new SpatialRelateFunction("disjoint", + SpatialRelation.DISJOINT)); + registerFunction("equals", new SpatialRelateFunction("equals", + SpatialRelation.EQUALS)); + registerFunction("touches", new SpatialRelateFunction("touches", + SpatialRelation.TOUCHES)); + registerFunction("within", new SpatialRelateFunction("within", + SpatialRelation.WITHIN)); + registerFunction("relate", new WrappedOGCFunction("OGC_RELATE", + StandardBasicTypes.BOOLEAN, new boolean[]{true, true, false})); + + // Register spatial analysis functions. + // Section 2.1.1.3 + registerFunction("distance", new SpatialAnalysisFunction("distance", + StandardBasicTypes.DOUBLE, SpatialAnalysis.DISTANCE)); + registerFunction("buffer", new SpatialAnalysisFunction("buffer", + GeometryType.INSTANCE, + SpatialAnalysis.BUFFER)); + registerFunction("convexhull", new SpatialAnalysisFunction( + "convexhull", GeometryType.INSTANCE, + SpatialAnalysis.CONVEXHULL)); + registerFunction("difference", new SpatialAnalysisFunction( + "difference", GeometryType.INSTANCE, + SpatialAnalysis.DIFFERENCE)); + registerFunction("intersection", new SpatialAnalysisFunction( + "intersection", GeometryType.INSTANCE, + SpatialAnalysis.INTERSECTION)); + registerFunction("symdifference", new SpatialAnalysisFunction( + "symdifference", GeometryType.INSTANCE, + SpatialAnalysis.SYMDIFFERENCE)); + registerFunction("geomunion", new SpatialAnalysisFunction("union", + GeometryType.INSTANCE, + SpatialAnalysis.UNION)); + // we rename OGC union to geomunion because union is a reserved SQL + // keyword. (See also postgis documentation). + + // portable spatial aggregate functions + registerFunction("extent", new SpatialAggregationFunction("extent", + GeometryType.INSTANCE, false, + OracleSpatialAggregate.EXTENT)); + + //other common functions + registerFunction("transform", new StandardSQLFunction("SDO_CS.TRANSFORM", + GeometryType.INSTANCE)); + + // Oracle specific Aggregate functions + registerFunction("centroid", new SpatialAggregationFunction("extent", + GeometryType.INSTANCE, false, + OracleSpatialAggregate.CENTROID)); + + registerFunction("concat_lines", new SpatialAggregationFunction( + "extent", GeometryType.INSTANCE, false, + OracleSpatialAggregate.CONCAT_LINES)); + + registerFunction("aggr_convexhull", new SpatialAggregationFunction( + "extent", GeometryType.INSTANCE, false, + OracleSpatialAggregate.CONVEXHULL)); + + registerFunction("aggr_union", new SpatialAggregationFunction("extent", + GeometryType.INSTANCE, false, + OracleSpatialAggregate.UNION)); + + registerFunction("lrs_concat", new SpatialAggregationFunction( + "lrsconcat", GeometryType.INSTANCE, + false, OracleSpatialAggregate.LRS_CONCAT)); + } + + @Override + public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + if ( sqlTypeDescriptor instanceof SpatialGeometrySqlTypeDescriptor ) { + return SDOGeometryTypeDescriptor.INSTANCE; + } + return super.remapSqlTypeDescriptor( sqlTypeDescriptor ); + } + + public String getNativeSpatialRelateSQL(String arg1, String arg2, + int spatialRelation) { + String mask = ""; + boolean negate = false; + switch (spatialRelation) { + case SpatialRelation.INTERSECTS: + mask = "ANYINTERACT"; // OGC Compliance verified + break; + case SpatialRelation.CONTAINS: + mask = "CONTAINS+COVERS"; + break; + case SpatialRelation.CROSSES: + throw new UnsupportedOperationException( + "Oracle Spatial does't have equivalent CROSSES relationship"); + case SpatialRelation.DISJOINT: + mask = "ANYINTERACT"; + negate = true; + break; + case SpatialRelation.EQUALS: + mask = "EQUAL"; + break; + case SpatialRelation.OVERLAPS: + mask = "OVERLAPBDYDISJOINT+OVERLAPBDYINTERSECT"; + break; + case SpatialRelation.TOUCHES: + mask = "TOUCH"; + break; + case SpatialRelation.WITHIN: + mask = "INSIDE+COVEREDBY"; + break; + default: + throw new IllegalArgumentException( + "undefined SpatialRelation passed (" + spatialRelation + + ")"); + } + StringBuffer buffer; + if (negate) { + buffer = new StringBuffer("CASE WHEN SDO_RELATE("); + } else { + buffer = new StringBuffer("SDO_RELATE("); + } + + + buffer.append(arg1); + buffer.append(",").append(arg2).append( ",'mask=" + mask + "') " ); + if (negate) { + buffer.append(" = 'TRUE' THEN 'FALSE' ELSE 'TRUE' END"); + } + return buffer.toString(); + } + + public String getOGCSpatialRelateSQL(String arg1, String arg2, + int spatialRelation) { + + StringBuffer ogcFunction = new StringBuffer("MDSYS."); + switch (spatialRelation) { + case SpatialRelation.INTERSECTS: + ogcFunction.append("OGC_INTERSECTS"); + break; + case SpatialRelation.CONTAINS: + ogcFunction.append("OGC_CONTAINS"); + break; + case SpatialRelation.CROSSES: + ogcFunction.append("OGC_CROSS"); + break; + case SpatialRelation.DISJOINT: + ogcFunction.append("OGC_DISJOINT"); + break; + case SpatialRelation.EQUALS: + ogcFunction.append("OGC_EQUALS"); + break; + case SpatialRelation.OVERLAPS: + ogcFunction.append("OGC_OVERLAP"); + break; + case SpatialRelation.TOUCHES: + ogcFunction.append("OGC_TOUCH"); + break; + case SpatialRelation.WITHIN: + ogcFunction.append("OGC_WITHIN"); + break; + default: + throw new IllegalArgumentException("Unknown SpatialRelation (" + + spatialRelation + ")."); + } + ogcFunction.append("(").append("MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(") + .append(arg1).append("),").append( + "MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(").append(arg2) + .append(")").append(")"); + return ogcFunction.toString(); + + } + + public String getNativeSpatialAggregateSQL(String arg1, int aggregation) { + + StringBuffer aggregateFunction = new StringBuffer(); + + SpatialAggregate sa = new SpatialAggregate(aggregation); + + if (sa._aggregateSyntax == null) { + throw new IllegalArgumentException("Unknown Spatial Aggregation (" + + aggregation + ")."); + } + + aggregateFunction.append(sa._aggregateSyntax); + + aggregateFunction.append("("); + if (sa.isAggregateType()) { + aggregateFunction.append("SDOAGGRTYPE("); + } + aggregateFunction.append(arg1); + // TODO tolerance must by configurable + if (sa.isAggregateType()) { + aggregateFunction.append(", ").append(.001).append(")"); + } + aggregateFunction.append(")"); + + return aggregateFunction.toString(); + } + + private StringBuffer wrapInSTGeometry(String geomColumn, StringBuffer toAdd) { + return toAdd.append("MDSYS.ST_GEOMETRY(").append(geomColumn) + .append(")"); + } + + public String getSpatialFilterExpression(String columnName) { + StringBuffer buffer = new StringBuffer("SDO_FILTER("); + // String pureColumnName = + // columnName.substring(columnName.lastIndexOf(".")+1); + // buffer.append("\"" + pureColumnName.toUpperCase() + "\""); + buffer.append(columnName); + buffer.append(",?) = 'TRUE' "); + return buffer.toString(); + } + + public String getSpatialRelateSQL(String columnName, int spatialRelation) { + + String sql = (isOGCStrict() ? (getOGCSpatialRelateSQL(columnName, "?", + spatialRelation) + " = 1") : (getNativeSpatialRelateSQL( + columnName, "?", spatialRelation) + "= 'TRUE'")); + sql += " and " + columnName + " is not null"; + return sql; + } + + public String getSpatialAnalysisSQL(List args, int spatialAnalysisFunction, + boolean useFilter) { + return isOGCStrict() ? getOGCSpatialAnalysisSQL(args, + spatialAnalysisFunction) : getNativeSpatialAnalysisSQL(args, + spatialAnalysisFunction); + } + + public String getSpatialAggregateSQL(String columnName, + int spatialAggregateFunction) { + return getNativeSpatialAggregateSQL( + columnName, + spatialAggregateFunction + ); + } + + public String getDWithinSQL(String columnName) { + throw new UnsupportedOperationException("No DWithin in this dialect"); + } + + public String getHavingSridSQL(String columnName) { + return String.format( " (MDSYS.ST_GEOMETRY(%s).ST_SRID() = ?)", columnName ); + } + + public String getIsEmptySQL(String columnName, boolean isEmpty) { + return String.format( + "( MDSYS.ST_GEOMETRY(%s).ST_ISEMPTY() = %d )", + columnName, + isEmpty ? 1 : 0 + ); + } + + private String getOGCSpatialAnalysisSQL(List args, + int spatialAnalysisFunction) { + boolean[] geomArgs; + StringBuffer ogcFunction = new StringBuffer("MDSYS."); + boolean isGeomReturn = true; + switch (spatialAnalysisFunction) { + case SpatialAnalysis.BUFFER: + ogcFunction.append("OGC_BUFFER"); + geomArgs = new boolean[]{true, false}; + break; + case SpatialAnalysis.CONVEXHULL: + ogcFunction.append("OGC_CONVEXHULL"); + geomArgs = new boolean[]{true}; + break; + case SpatialAnalysis.DIFFERENCE: + ogcFunction.append("OGC_DIFFERENCE"); + geomArgs = new boolean[]{true, true}; + break; + case SpatialAnalysis.DISTANCE: + ogcFunction.append("OGC_DISTANCE"); + geomArgs = new boolean[]{true, true}; + isGeomReturn = false; + break; + case SpatialAnalysis.INTERSECTION: + ogcFunction.append("OGC_INTERSECTION"); + geomArgs = new boolean[]{true, true}; + break; + case SpatialAnalysis.SYMDIFFERENCE: + ogcFunction.append("OGC_SYMMETRICDIFFERENCE"); + geomArgs = new boolean[]{true, true}; + break; + case SpatialAnalysis.UNION: + ogcFunction.append("OGC_UNION"); + geomArgs = new boolean[]{true, true}; + break; + default: + throw new IllegalArgumentException( + "Unknown SpatialAnalysisFunction (" + + spatialAnalysisFunction + ")."); + } + + if (args.size() < geomArgs.length) + throw new QueryException( + "Insufficient arguments for spatial analysis function (function type: " + + spatialAnalysisFunction + ")."); + + ogcFunction.append("("); + for (int i = 0; i < geomArgs.length; i++) { + if (i > 0) + ogcFunction.append(","); + if (geomArgs[i]) + wrapInSTGeometry((String) args.get(i), ogcFunction); + else + ogcFunction.append(args.get(i)); + } + ogcFunction.append(")"); + if (isGeomReturn) + ogcFunction.append(".geom"); + return ogcFunction.toString(); + } + + private String getNativeSpatialAnalysisSQL(List args, int spatialAnalysis) { + return getOGCSpatialAnalysisSQL( args, spatialAnalysis ); + } + + boolean isOGCStrict() { + return ((Boolean) this.features.get(OGC_STRICT)).booleanValue(); + } + + + + private void configure() { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + String propfileLoc = getClass().getCanonicalName() + ".properties"; + URL propfile = loader.getResource(propfileLoc); + if (propfile != null) { + InputStream is = null; + log.info("properties file found: " + propfile); + try { + loader.getResource(getClass().getCanonicalName()); + is = propfile.openStream(); + PropertyFileReader reader = new PropertyFileReader(is); + Properties props = reader.getProperties(); + + // checking for connectionfinder + String ccn = props.getProperty(CONNECTION_FINDER_PROPERTY); + if (ccn != null) { + try { + Class clazz = Thread.currentThread() + .getContextClassLoader().loadClass(ccn); + ConnectionFinder cf = (ConnectionFinder) clazz + .newInstance(); + OracleJDBCTypeFactory.setConnectionFinder(cf); + log.info("Setting ConnectionFinder to " + ccn); + } catch (ClassNotFoundException e) { + log.warn("Tried to set ConnectionFinder to " + ccn + + ", but class not found."); + } catch (InstantiationException e) { + log.warn("Tried to set ConnectionFinder to " + ccn + + ", but couldn't instantiate."); + } catch (IllegalAccessException e) { + log + .warn("Tried to set ConnectionFinder to " + + ccn + + ", but got IllegalAcessException on instantiation."); + } + } + + } catch (IOException e) { + log.warn("Problem reading properties file " + e); + } finally { + try { + is.close(); + } catch (Exception e) { + } + } + } + } + + + public boolean isTwoPhaseFiltering() { + return false; + } + + public boolean supportsFiltering() { + return true; + } + + public boolean supports(SpatialFunction function) { + return (getFunctions().get(function.toString()) != null); + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/Ordinates.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/Ordinates.java new file mode 100644 index 0000000000..b2276a3e50 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/Ordinates.java @@ -0,0 +1,72 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.Array; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jul 1, 2010 + */ +class Ordinates { + + static final String TYPE_NAME = "MDSYS.SDO_ORDINATE_ARRAY"; + + private Double[] ordinates; + + public Ordinates(Double[] ordinates) { + this.ordinates = ordinates; + } + + public Ordinates(Array array) { + if (array == null) { + this.ordinates = new Double[]{}; + return; + } + try { + Number[] ords = (Number[]) array.getArray(); + this.ordinates = new Double[ords.length]; + for (int i = 0; i < ords.length; i++) { + this.ordinates[i] = ords[i] != null ? ords[i].doubleValue() + : Double.NaN; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public Double[] getOrdinateArray() { + return this.ordinates; + } + + public Double[] getOrdinatesArray(int startPosition, int endPosition) { + Double[] a = new Double[endPosition - startPosition]; + System.arraycopy(this.ordinates, startPosition - 1, a, 0, a.length); + return a; + } + + public Double[] getOrdinatesArray(int startPosition) { + Double[] a = new Double[this.ordinates.length - (startPosition - 1)]; + System.arraycopy(this.ordinates, startPosition - 1, a, 0, a.length); + return a; + } + + public String toString() { + return SDOGeometry.arrayToString(this.ordinates); + } + + public void addOrdinates(Double[] ordinatesToAdd) { + Double[] newOrdinates = new Double[this.ordinates.length + + ordinatesToAdd.length]; + System.arraycopy(this.ordinates, 0, newOrdinates, 0, + this.ordinates.length); + System.arraycopy(ordinatesToAdd, 0, newOrdinates, + this.ordinates.length, ordinatesToAdd.length); + this.ordinates = newOrdinates; + } + +// public ARRAY toOracleArray(Connection conn) throws SQLException { +// ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor( +// TYPE_NAME, conn); +// return new ARRAY(arrayDescriptor, conn, this.ordinates); +// } + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOBooleanType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOBooleanType.java new file mode 100644 index 0000000000..979fd5990b --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOBooleanType.java @@ -0,0 +1,78 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import org.hibernate.dialect.Dialect; +import org.hibernate.type.BooleanType; + +class SDOBooleanType extends BooleanType { + + private static final long serialVersionUID = 1L; + + /** + *

+ * This type's name is sdo_boolean + */ + public String getName() { + return "sdo_boolean"; + } + + public Object get(ResultSet rs, String name) throws SQLException { + String value = rs.getString(name); + if (rs.wasNull()) { + return getDefaultValue(); + } else if ("TRUE".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + } + + public void set(PreparedStatement st, Boolean value, int index) + throws SQLException { + + if (value == null) { + st.setNull(index, Types.VARCHAR); + } else { + boolean bool = value.booleanValue(); + st.setString(index, bool ? "TRUE" : "FALSE"); + } + } + + public String objectToSQLString(Boolean value, Dialect dialect) { + return value.booleanValue() ? "'TRUE'" : "'FALSE'"; + } + +// public int sqlType() { +// return Types.VARCHAR; +// } + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGType.java new file mode 100644 index 0000000000..f6a2c8c18d --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGType.java @@ -0,0 +1,105 @@ +package org.hibernate.spatial.dialect.oracle; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jun 30, 2010 + */ +class SDOGType { + + private int dimension = 2; + + private int lrsDimension = 0; + + private TypeGeometry typeGeometry = TypeGeometry.UNKNOWN_GEOMETRY; + + public SDOGType(int dimension, int lrsDimension, + TypeGeometry typeGeometry) { + setDimension(dimension); + setLrsDimension(lrsDimension); + setTypeGeometry(typeGeometry); + } + + public int getDimension() { + return dimension; + } + + public void setDimension(int dimension) { + if (dimension < 2 || dimension > 4) { + throw new IllegalArgumentException( + "Dimension can only be 2,3 or 4."); + } + this.dimension = dimension; + } + + public TypeGeometry getTypeGeometry() { + return typeGeometry; + } + + public void setTypeGeometry(TypeGeometry typeGeometry) { + + this.typeGeometry = typeGeometry; + } + + public int getLRSDimension() { + if (this.lrsDimension > 0) { + return this.lrsDimension; + } else if (this.lrsDimension == 0 && this.dimension == 4) { + return 4; + } + return 0; + } + + public int getZDimension() { + if (this.dimension > 2) { + if (!isLRSGeometry()) { + return this.dimension; + } else { + return (getLRSDimension() < this.dimension ? 4 : 3); + } + } + return 0; + } + + public boolean isLRSGeometry() { + return (this.lrsDimension > 0 || (this.lrsDimension == 0 && this.dimension == 4)); + } + + public void setLrsDimension(int lrsDimension) { + if (lrsDimension != 0 && lrsDimension > this.dimension) { + throw new IllegalArgumentException( + "lrsDimension must be 0 or lower or equal to dimenstion."); + } + this.lrsDimension = lrsDimension; + } + + public int intValue() { + int v = this.dimension * 1000; + v += lrsDimension * 100; + v += typeGeometry.intValue(); + return v; + } + + public static SDOGType parse(int v) { + int dim = v / 1000; + v -= dim * 1000; + int lrsDim = v / 100; + v -= lrsDim * 100; + TypeGeometry typeGeometry = TypeGeometry.parse(v); + return new SDOGType(dim, lrsDim, typeGeometry); + } + + public static SDOGType parse(Object datum) { + + try { + int v = ((Number) datum).intValue(); + return parse(v); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + public String toString() { + return Integer.toString(this.intValue()); + } +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometry.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometry.java new file mode 100644 index 0000000000..2dc517cc9e --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometry.java @@ -0,0 +1,325 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.Array; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Struct; +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.spatial.helper.FinderException; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jun 30, 2010 + */ + +class SDOGeometry { + + private final static SQLTypeFactory TYPE_FACTORY = new OracleJDBCTypeFactory(); + private static final String SQL_TYPE_NAME = "MDSYS.SDO_GEOMETRY"; + + private SDOGType gtype; + + private int srid; + + private SDOPoint point; + + private ElemInfo info; + + private Ordinates ordinates; + + + public SDOGeometry() { + + } + + public static String getTypeName() { + return SQL_TYPE_NAME; + } + + static String arrayToString(Object array) { + if (array == null || java.lang.reflect.Array.getLength(array) == 0) { + return "()"; + } + int length = java.lang.reflect.Array.getLength(array); + StringBuilder stb = new StringBuilder(); + stb.append("(").append(java.lang.reflect.Array.get(array, 0)); + for (int i = 1; i < length; i++) { + stb.append(",").append(java.lang.reflect.Array.get(array, i)); + } + stb.append(")"); + return stb.toString(); + } + + + /** + * This joins an array of SDO_GEOMETRIES to a SDOGeometry of type + * COLLECTION + * + * @param SDOElements + * @return + */ + public static SDOGeometry join(SDOGeometry[] SDOElements) { + SDOGeometry SDOCollection = new SDOGeometry(); + if (SDOElements == null || SDOElements.length == 0) { + SDOCollection.setGType(new SDOGType(2, 0, + TypeGeometry.COLLECTION)); + } else { + SDOGeometry firstElement = SDOElements[0]; + int dim = firstElement.getGType().getDimension(); + int lrsDim = firstElement.getGType().getLRSDimension(); + SDOCollection.setGType(new SDOGType(dim, lrsDim, + TypeGeometry.COLLECTION)); + int ordinatesOffset = 1; + for (int i = 0; i < SDOElements.length; i++) { + ElemInfo element = SDOElements[i].getInfo(); + Double[] ordinates = SDOElements[i].getOrdinates() + .getOrdinateArray(); + if (element != null && element.getSize() > 0) { + int shift = ordinatesOffset + - element.getOrdinatesOffset(0); + shiftOrdinateOffset(element, shift); + SDOCollection.addElement(element); + SDOCollection.addOrdinates(ordinates); + ordinatesOffset += ordinates.length; + } + } + } + return SDOCollection; + } + + public ElemInfo getInfo() { + return info; + } + + public void setInfo(ElemInfo info) { + this.info = info; + } + + public SDOGType getGType() { + return gtype; + } + + public void setGType(SDOGType gtype) { + this.gtype = gtype; + } + + public Ordinates getOrdinates() { + return ordinates; + } + + public void setOrdinates(Ordinates ordinates) { + this.ordinates = ordinates; + } + + public SDOPoint getPoint() { + return point; + } + + public void setPoint(SDOPoint point) { + this.point = point; + } + + public int getSRID() { + return srid; + } + + public void setSRID(int srid) { + this.srid = srid; + } + + public static SDOGeometry load(Struct struct) { + + Object[] data; + try { + data = struct.getAttributes(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + SDOGeometry geom = new SDOGeometry(); + geom.setGType(SDOGType.parse(data[0])); + geom.setSRID(data[1]); + if (data[2] != null) { + geom.setPoint(new SDOPoint((Struct) data[2])); + } + geom.setInfo(new ElemInfo((Array) data[3])); + geom.setOrdinates(new Ordinates((Array) data[4])); + + return geom; + } + + public static Struct store(SDOGeometry geom, Connection conn) + throws SQLException, FinderException { + return TYPE_FACTORY.createStruct(geom, conn); + } + + + private void setSRID(Object datum) { + if (datum == null) { + this.srid = 0; + return; + } + try { + this.srid = new Integer(((Number) datum).intValue()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public boolean isLRSGeometry() { + return gtype.isLRSGeometry(); + } + + public int getDimension() { + return gtype.getDimension(); + } + + public int getLRSDimension() { + return gtype.getLRSDimension(); + } + + public int getZDimension() { + return gtype.getZDimension(); + } + + /** + * Gets the number of elements or compound elements. + *

+ * Subelements of a compound element are not counted. + * + * @return the number of elements + */ + public int getNumElements() { + int cnt = 0; + int i = 0; + while (i < info.getSize()) { + if (info.getElementType(i).isCompound()) { + int numCompounds = info.getNumCompounds(i); + i += 1 + numCompounds; + } else { + i++; + } + cnt++; + } + return cnt; + } + + public String toString() { + StringBuilder stb = new StringBuilder(); + stb.append("(").append(gtype).append(",").append(srid).append(",") + .append(point).append(",").append(info).append(",").append( + ordinates).append(")"); + return stb.toString(); + } + + public void addOrdinates(Double[] newOrdinates) { + if (this.ordinates == null) { + this.ordinates = new Ordinates(newOrdinates); + } else { + this.ordinates.addOrdinates(newOrdinates); + } + } + + public void addElement(ElemInfo element) { + if (this.info == null) { + this.info = element; + } else { + this.info.addElement(element); + } + } + + /** + * If this SDOGeometry is a COLLECTION, this method returns an array of + * the SDO_GEOMETRIES that make up the collection. If not a Collection, + * an array containing this SDOGeometry is returned. + * + * @return collection elements as individual SDO_GEOMETRIES + */ + public SDOGeometry[] getElementGeometries() { + if (getGType().getTypeGeometry() == TypeGeometry.COLLECTION) { + List elements = new ArrayList(); + int i = 0; + while (i < this.getNumElements()) { + ElementType et = this.getInfo().getElementType(i); + int next = i + 1; + // if the element is an exterior ring, or a compound + // element, then this geometry spans multiple elements. + if (et.isExteriorRing()) { // then next element is the + // first non-interior ring + while (next < this.getNumElements()) { + if (!this.getInfo().getElementType(next) + .isInteriorRing()) { + break; + } + next++; + } + } else if (et.isCompound()) { + next = i + this.getInfo().getNumCompounds(i) + 1; + } + SDOGeometry elemGeom = new SDOGeometry(); + SDOGType elemGtype = deriveGTYPE(this.getInfo() + .getElementType(i), this); + elemGeom.setGType(elemGtype); + elemGeom.setSRID(this.getSRID()); + ElemInfo elemInfo = new ElemInfo(this.getInfo() + .getElement(i)); + shiftOrdinateOffset(elemInfo, -elemInfo + .getOrdinatesOffset(0) + 1); + elemGeom.setInfo(elemInfo); + int startPosition = this.getInfo().getOrdinatesOffset(i); + Ordinates elemOrdinates = null; + if (next < this.getNumElements()) { + int endPosition = this.getInfo().getOrdinatesOffset( + next); + elemOrdinates = new Ordinates(this.getOrdinates() + .getOrdinatesArray(startPosition, endPosition)); + } else { + elemOrdinates = new Ordinates(this.getOrdinates() + .getOrdinatesArray(startPosition)); + } + elemGeom.setOrdinates(elemOrdinates); + elements.add(elemGeom); + i = next; + } + return elements.toArray(new SDOGeometry[elements.size()]); + } else { + return new SDOGeometry[]{this}; + } + } + + private static void shiftOrdinateOffset(ElemInfo elemInfo, int offset) { + for (int i = 0; i < elemInfo.getSize(); i++) { + int newOffset = elemInfo.getOrdinatesOffset(i) + offset; + elemInfo.setOrdinatesOffset(i, newOffset); + } + } + + private static SDOGType deriveGTYPE(ElementType elementType, + SDOGeometry origGeom) { + switch (elementType) { + case POINT: + case ORIENTATION: + return new SDOGType(origGeom.getDimension(), origGeom + .getLRSDimension(), TypeGeometry.POINT); + case POINT_CLUSTER: + return new SDOGType(origGeom.getDimension(), origGeom + .getLRSDimension(), TypeGeometry.MULTIPOINT); + case LINE_ARC_SEGMENTS: + case LINE_STRAITH_SEGMENTS: + case COMPOUND_LINE: + return new SDOGType(origGeom.getDimension(), origGeom + .getLRSDimension(), TypeGeometry.LINE); + case COMPOUND_EXTERIOR_RING: + case EXTERIOR_RING_ARC_SEGMENTS: + case EXTERIOR_RING_CIRCLE: + case EXTERIOR_RING_RECT: + case EXTERIOR_RING_STRAIGHT_SEGMENTS: + return new SDOGType(origGeom.getDimension(), origGeom + .getLRSDimension(), TypeGeometry.POLYGON); + } + return null; + } + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryTypeDescriptor.java new file mode 100644 index 0000000000..539d3bc327 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryTypeDescriptor.java @@ -0,0 +1,39 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.Types; + +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 8/22/11 + */ +public class SDOGeometryTypeDescriptor implements SqlTypeDescriptor { + + public static SDOGeometryTypeDescriptor INSTANCE = new SDOGeometryTypeDescriptor(); + + @Override + public int getSqlType() { + return Types.STRUCT; + } + + @Override + public boolean canBeRemapped() { + return false; + } + + @Override + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return (ValueBinder) new SDOGeometryValueBinder(); + } + + @Override + public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return (ValueExtractor) new SDOGeometryValueExtractor(); + } + + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueBinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueBinder.java new file mode 100644 index 0000000000..b9f99c4c7f --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueBinder.java @@ -0,0 +1,357 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; + +import com.vividsolutions.jts.algorithm.CGAlgorithms; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; + +import org.hibernate.HibernateException; +import org.hibernate.spatial.HBSpatialExtension; +import org.hibernate.spatial.helper.FinderException; +import org.hibernate.spatial.mgeom.MCoordinate; +import org.hibernate.spatial.mgeom.MGeometryFactory; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.WrapperOptions; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 8/22/11 + */ +public class SDOGeometryValueBinder implements ValueBinder { + + @Override + public void bind(PreparedStatement st, Geometry value, int index, WrapperOptions options) throws SQLException { + if ( value == null ) { + st.setNull( index, Types.STRUCT, SDOGeometry.getTypeName()); + } + else { + Geometry jtsGeom = (Geometry) value; + Object dbGeom = toNative( jtsGeom, st.getConnection() ); + st.setObject( index, dbGeom ); + } + } + + public MGeometryFactory getGeometryFactory() { + return HBSpatialExtension.getDefaultGeomFactory(); + } + + private Object toNative(Geometry jtsGeom, Connection connection){ + SDOGeometry geom = convertJTSGeometry(jtsGeom); + if (geom != null) + try { + return SDOGeometry.store(geom, connection); + } catch (SQLException e) { + throw new HibernateException( + "Problem during conversion from JTS to SDOGeometry", e); + } catch (FinderException e) { + throw new HibernateException( + "OracleConnection could not be retrieved for creating SDOGeometry STRUCT", e); + } + else { + throw new UnsupportedOperationException("Conversion of " + + jtsGeom.getClass().getSimpleName() + + " to Oracle STRUCT not supported"); + } + } + + private SDOGeometry convertJTSGeometry(Geometry jtsGeom) { + SDOGeometry geom = null; + if (jtsGeom instanceof Point ) { + geom = convertJTSPoint((Point) jtsGeom); + } else if (jtsGeom instanceof LineString ) { + geom = convertJTSLineString((LineString) jtsGeom); + } else if (jtsGeom instanceof Polygon ) { + geom = convertJTSPolygon((Polygon) jtsGeom); + } else if (jtsGeom instanceof MultiPoint ) { + geom = convertJTSMultiPoint((MultiPoint) jtsGeom); + } else if (jtsGeom instanceof MultiLineString ) { + geom = convertJTSMultiLineString((MultiLineString) jtsGeom); + } else if (jtsGeom instanceof MultiPolygon ) { + geom = convertJTSMultiPolygon((MultiPolygon) jtsGeom); + } else if (jtsGeom instanceof GeometryCollection ) { + geom = convertJTSGeometryCollection((GeometryCollection) jtsGeom); + } + return geom; + } + + private SDOGeometry convertJTSGeometryCollection( + GeometryCollection collection) { + SDOGeometry[] SDOElements = new SDOGeometry[collection + .getNumGeometries()]; + for (int i = 0; i < collection.getNumGeometries(); i++) { + Geometry geom = collection.getGeometryN(i); + SDOElements[i] = convertJTSGeometry(geom); + } + SDOGeometry ccollect = SDOGeometry.join(SDOElements); + ccollect.setSRID(collection.getSRID()); + return ccollect; + } + + private SDOGeometry convertJTSMultiPolygon(MultiPolygon multiPolygon) { + int dim = getCoordDimension(multiPolygon); + int lrsPos = getCoordinateLrsPosition(multiPolygon); + SDOGeometry geom = new SDOGeometry(); + geom.setGType(new SDOGType(dim, lrsPos, TypeGeometry.MULTIPOLYGON)); + geom.setSRID(multiPolygon.getSRID()); + for (int i = 0; i < multiPolygon.getNumGeometries(); i++) { + try { + Polygon pg = (Polygon) multiPolygon.getGeometryN(i); + addPolygon(geom, pg); + } catch (Exception e) { + throw new RuntimeException( + "Found geometry that was not a geometry in MultiPolygon"); + } + } + return geom; + } + + private SDOGeometry convertJTSLineString(LineString lineString) { + int dim = getCoordDimension(lineString); + int lrsPos = getCoordinateLrsPosition(lineString); + boolean isLrs = lrsPos > 0; + Double[] ordinates = convertCoordinates(lineString.getCoordinates(), + dim, isLrs); + SDOGeometry geom = new SDOGeometry(); + geom.setGType(new SDOGType(dim, lrsPos, TypeGeometry.LINE)); + geom.setSRID(lineString.getSRID()); + ElemInfo info = new ElemInfo(1); + info.setElement(0, 1, ElementType.LINE_STRAITH_SEGMENTS, 0); + geom.setInfo(info); + geom.setOrdinates(new Ordinates(ordinates)); + return geom; + + } + + private SDOGeometry convertJTSMultiPoint(MultiPoint multiPoint) { + int dim = getCoordDimension(multiPoint); + int lrsDim = getCoordinateLrsPosition(multiPoint); + boolean isLrs = (lrsDim != 0); + SDOGeometry geom = new SDOGeometry(); + geom.setGType(new SDOGType(dim, lrsDim, TypeGeometry.MULTIPOINT)); + geom.setSRID(multiPoint.getSRID()); + ElemInfo info = new ElemInfo(multiPoint.getNumPoints()); + int oordinatesOffset = 1; + Double[] ordinates = new Double[]{}; + for (int i = 0; i < multiPoint.getNumPoints(); i++) { + info.setElement(i, oordinatesOffset, ElementType.POINT, 0); + ordinates = convertAddCoordinates(ordinates, multiPoint + .getGeometryN(i).getCoordinates(), dim, isLrs); + oordinatesOffset = ordinates.length + 1; + } + geom.setInfo(info); + geom.setOrdinates(new Ordinates(ordinates)); + return geom; + } + + private SDOGeometry convertJTSPoint(Point jtsGeom) { + int dim = getCoordDimension(jtsGeom); + + int lrsDim = getCoordinateLrsPosition(jtsGeom); + boolean isLrs = (lrsDim != 0); + + Double[] coord = convertCoordinates(jtsGeom.getCoordinates(), dim, + isLrs); + SDOGeometry geom = new SDOGeometry(); + geom.setGType(new SDOGType(dim, lrsDim, TypeGeometry.POINT)); + geom.setSRID(jtsGeom.getSRID()); + ElemInfo info = new ElemInfo(1); + info.setElement(0, 1, ElementType.POINT, 1); + geom.setInfo(info); + geom.setOrdinates(new Ordinates(coord)); + return geom; + } + + private SDOGeometry convertJTSPolygon(Polygon polygon) { + int dim = getCoordDimension(polygon); + int lrsPos = getCoordinateLrsPosition(polygon); + SDOGeometry geom = new SDOGeometry(); + geom.setGType(new SDOGType(dim, lrsPos, TypeGeometry.POLYGON)); + geom.setSRID(polygon.getSRID()); + addPolygon(geom, polygon); + return geom; + } + + private void addPolygon(SDOGeometry geom, Polygon polygon) { + int numInteriorRings = polygon.getNumInteriorRing(); + ElemInfo info = new ElemInfo(numInteriorRings + 1); + int ordinatesPreviousOffset = 0; + if (geom.getOrdinates() != null) { + ordinatesPreviousOffset = geom.getOrdinates().getOrdinateArray().length; + } + int ordinatesOffset = ordinatesPreviousOffset + 1; + Double[] ordinates = new Double[]{}; + for (int i = 0; i < info.getSize(); i++) { + ElementType et; + Coordinate[] coords; + if (i == 0) { + et = ElementType.EXTERIOR_RING_STRAIGHT_SEGMENTS; + coords = polygon.getExteriorRing().getCoordinates(); + if (!CGAlgorithms.isCCW( coords )) { + coords = reverseRing(coords); + } + } else { + et = ElementType.INTERIOR_RING_STRAIGHT_SEGMENTS; + coords = polygon.getInteriorRingN(i - 1).getCoordinates(); + if (CGAlgorithms.isCCW(coords)) { + coords = reverseRing(coords); + } + } + info.setElement(i, ordinatesOffset, et, 0); + ordinates = convertAddCoordinates(ordinates, coords, geom + .getDimension(), geom.isLRSGeometry()); + ordinatesOffset = ordinatesPreviousOffset + ordinates.length + 1; + } + geom.addElement(info); + geom.addOrdinates(ordinates); + } + + private SDOGeometry convertJTSMultiLineString( + MultiLineString multiLineString) { + int dim = getCoordDimension(multiLineString); + int lrsDim = getCoordinateLrsPosition(multiLineString); + boolean isLrs = (lrsDim != 0); + SDOGeometry geom = new SDOGeometry(); + geom.setGType(new SDOGType(dim, lrsDim, TypeGeometry.MULTILINE)); + geom.setSRID(multiLineString.getSRID()); + ElemInfo info = new ElemInfo(multiLineString.getNumGeometries()); + int oordinatesOffset = 1; + Double[] ordinates = new Double[]{}; + for (int i = 0; i < multiLineString.getNumGeometries(); i++) { + info.setElement(i, oordinatesOffset, + ElementType.LINE_STRAITH_SEGMENTS, 0); + ordinates = convertAddCoordinates(ordinates, multiLineString + .getGeometryN(i).getCoordinates(), dim, isLrs); + oordinatesOffset = ordinates.length + 1; + } + geom.setInfo(info); + geom.setOrdinates(new Ordinates(ordinates)); + return geom; + } + + private Double[] convertAddCoordinates(Double[] ordinates, + Coordinate[] coordinates, int dim, boolean isLrs) { + Double[] no = convertCoordinates(coordinates, dim, isLrs); + Double[] newordinates = new Double[ordinates.length + no.length]; + System.arraycopy(ordinates, 0, newordinates, 0, ordinates.length); + System.arraycopy(no, 0, newordinates, ordinates.length, no.length); + return newordinates; + } + + /** + * Convert the coordinates to a double array for purposes of persisting them + * to the database. Note that Double.NaN values are to be converted to null + * values in the array. + * + * @param coordinates Coordinates to be converted to the array + * @param dim Coordinate dimension + * @param isLrs true if the coordinates contain measures + * @return + */ + private Double[] convertCoordinates(Coordinate[] coordinates, int dim, + boolean isLrs) { + if (dim > 4) + throw new IllegalArgumentException( + "Dim parameter value cannot be greater than 4"); + Double[] converted = new Double[coordinates.length * dim]; + for (int i = 0; i < coordinates.length; i++) { + MCoordinate c = MCoordinate.convertCoordinate(coordinates[i]); + + // set the X and Y values + converted[i * dim] = toDouble(c.x); + converted[i * dim + 1] = toDouble(c.y); + if (dim == 3) + converted[i * dim + 2] = isLrs ? toDouble(c.m) : toDouble(c.z); + else if (dim == 4) { + converted[i * dim + 2] = toDouble(c.z); + converted[i * dim + 3] = toDouble(c.m); + } + } + return converted; + } + + /** + * This method converts a double primitive to a Double wrapper instance, but + * treats a Double.NaN value as null. + * + * @param d the value to be converted + * @return A Double instance of d, Null if the parameter is Double.NaN + */ + private Double toDouble(double d) { + return Double.isNaN(d) ? null : d; + } + + /** + * Return the dimension required for building the gType in the SDOGeometry + * object. Has support for LRS type geometries. + * + * @param geom and instance of the Geometry class from which the dimension is + * being extracted. + * @return number of dimensions for purposes of creating the + * SDOGeometry.SDOGType + */ + private int getCoordDimension(Geometry geom) { + // This is awkward, I have to create an MCoordinate to discover what the + // dimension is. + // This shall be cleaner if MCoordinate.getOrdinate(int ordinateIndex) + // is moved to the + // Coordinate class + MCoordinate c = MCoordinate.convertCoordinate(geom.getCoordinate()); + int d = 0; + if (c != null) { + if (!Double.isNaN(c.x)) + d++; + if (!Double.isNaN(c.y)) + d++; + if (!Double.isNaN(c.z)) + d++; + if (!Double.isNaN(c.m)) + d++; + } + return d; + } + + /** + * Returns the lrs measure position for purposes of building the gType for + * an oracle geometry. At this point and time, I'll have to assume that the + * measure is always put at the end of the ordinate tuple, even though it + * technically wouldn't have to. This method bases its decision on whether + * the first coordinate has a measure value, as measure are required for the + * very first and last measure in a CoordinateSequence. If there is no + * measure value, 0 is returned. + * + * @param geom and instance of the Geometry class from which the lrs position + * is being extracted. + * @return the lrs position for the SDOGeometry.SDOGType + */ + private int getCoordinateLrsPosition(Geometry geom) { + MCoordinate c = MCoordinate.convertCoordinate( geom.getCoordinate() ); + int measurePos = 0; + if (c != null && !Double.isNaN(c.m)) { + measurePos = (Double.isNaN(c.z)) ? 3 : 4; + } + return measurePos; + } + + // reverses ordinates in a coordinate array in-place + + private Coordinate[] reverseRing(Coordinate[] ar) { + for (int i = 0; i < ar.length / 2; i++) { + Coordinate cs = ar[i]; + ar[i] = ar[ar.length - 1 - i]; + ar[ar.length - 1 - i] = cs; + } + return ar; + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueExtractor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueExtractor.java new file mode 100644 index 0000000000..b7c9133f09 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGeometryValueExtractor.java @@ -0,0 +1,522 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Struct; +import java.util.ArrayList; +import java.util.List; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.MultiLineString; +import com.vividsolutions.jts.geom.MultiPoint; +import com.vividsolutions.jts.geom.MultiPolygon; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; + +import org.hibernate.HibernateException; +import org.hibernate.spatial.Circle; +import org.hibernate.spatial.HBSpatialExtension; +import org.hibernate.spatial.mgeom.MCoordinate; +import org.hibernate.spatial.mgeom.MGeometryFactory; +import org.hibernate.spatial.mgeom.MLineString; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 8/22/11 + */ +public class SDOGeometryValueExtractor implements ValueExtractor { + + @Override + public Geometry extract(ResultSet rs, String name, WrapperOptions options) + throws SQLException { + Object geomObj = rs.getObject( name ); + return toJTS( geomObj ); + } + + public MGeometryFactory getGeometryFactory() { + return HBSpatialExtension.getDefaultGeomFactory(); + } + + public Geometry toJTS(Object struct) { + if ( struct == null ) { + return null; + } + SDOGeometry SDOGeom = SDOGeometry.load( (Struct) struct ); + return convert2JTS( SDOGeom ); + } + + private Geometry convert2JTS(SDOGeometry SDOGeom) { + int dim = SDOGeom.getGType().getDimension(); + int lrsDim = SDOGeom.getGType().getLRSDimension(); + Geometry result = null; + switch ( SDOGeom.getGType().getTypeGeometry() ) { + case POINT: + result = convertSDOPoint( SDOGeom ); + break; + case LINE: + result = convertSDOLine( dim, lrsDim, SDOGeom ); + break; + case POLYGON: + result = convertSDOPolygon( dim, lrsDim, SDOGeom ); + break; + case MULTIPOINT: + result = convertSDOMultiPoint( dim, lrsDim, SDOGeom ); + break; + case MULTILINE: + result = convertSDOMultiLine( dim, lrsDim, SDOGeom ); + break; + case MULTIPOLYGON: + result = convertSDOMultiPolygon( dim, lrsDim, SDOGeom ); + break; + case COLLECTION: + result = convertSDOCollection( dim, lrsDim, SDOGeom ); + break; + default: + throw new IllegalArgumentException( + "Type not supported: " + + SDOGeom.getGType().getTypeGeometry() + ); + } + result.setSRID( SDOGeom.getSRID() ); + return result; + + } + + private Geometry convertSDOCollection(int dim, int lrsDim, + SDOGeometry SDOGeom) { + List geometries = new ArrayList(); + for ( SDOGeometry elemGeom : SDOGeom.getElementGeometries() ) { + geometries.add( convert2JTS( elemGeom ) ); + } + Geometry[] geomArray = new Geometry[geometries.size()]; + return getGeometryFactory().createGeometryCollection( + geometries.toArray( geomArray ) + ); + } + + private Point convertSDOPoint(SDOGeometry SDOGeom) { + Double[] ordinates = SDOGeom.getOrdinates().getOrdinateArray(); + if ( ordinates.length == 0 ) { + if ( SDOGeom.getDimension() == 2 ) { + ordinates = new Double[] { + SDOGeom.getPoint().x, + SDOGeom.getPoint().y + }; + } + else { + ordinates = new Double[] { + SDOGeom.getPoint().x, + SDOGeom.getPoint().y, SDOGeom.getPoint().z + }; + } + } + CoordinateSequence cs = convertOrdinateArray( ordinates, SDOGeom ); + Point point = getGeometryFactory().createPoint( cs ); + return point; + } + + private MultiPoint convertSDOMultiPoint(int dim, int lrsDim, + SDOGeometry SDOGeom) { + Double[] ordinates = SDOGeom.getOrdinates().getOrdinateArray(); + CoordinateSequence cs = convertOrdinateArray( ordinates, SDOGeom ); + MultiPoint multipoint = getGeometryFactory().createMultiPoint( cs ); + return multipoint; + } + + private LineString convertSDOLine(int dim, int lrsDim, SDOGeometry SDOGeom) { + boolean lrs = SDOGeom.isLRSGeometry(); + ElemInfo info = SDOGeom.getInfo(); + CoordinateSequence cs = null; + + int i = 0; + while ( i < info.getSize() ) { + if ( info.getElementType( i ).isCompound() ) { + int numCompounds = info.getNumCompounds( i ); + cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, SDOGeom ) ); + i += 1 + numCompounds; + } + else { + cs = add( cs, getElementCSeq( i, SDOGeom, false ) ); + i++; + } + } + + LineString ls = lrs ? getGeometryFactory().createMLineString( cs ) + : getGeometryFactory().createLineString( cs ); + return ls; + } + + private MultiLineString convertSDOMultiLine(int dim, int lrsDim, + SDOGeometry SDOGeom) { + boolean lrs = SDOGeom.isLRSGeometry(); + ElemInfo info = SDOGeom.getInfo(); + LineString[] lines = lrs ? new MLineString[SDOGeom.getInfo().getSize()] + : new LineString[SDOGeom.getInfo().getSize()]; + int i = 0; + while ( i < info.getSize() ) { + CoordinateSequence cs = null; + if ( info.getElementType( i ).isCompound() ) { + int numCompounds = info.getNumCompounds( i ); + cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, SDOGeom ) ); + LineString line = lrs ? getGeometryFactory().createMLineString( + cs + ) : getGeometryFactory().createLineString( cs ); + lines[i] = line; + i += 1 + numCompounds; + } + else { + cs = add( cs, getElementCSeq( i, SDOGeom, false ) ); + LineString line = lrs ? getGeometryFactory().createMLineString( + cs + ) : getGeometryFactory().createLineString( cs ); + lines[i] = line; + i++; + } + } + + MultiLineString mls = lrs ? getGeometryFactory() + .createMultiMLineString( (MLineString[]) lines ) + : getGeometryFactory().createMultiLineString( lines ); + return mls; + + } + + private Geometry convertSDOPolygon(int dim, int lrsDim, SDOGeometry SDOGeom) { + LinearRing shell = null; + LinearRing[] holes = new LinearRing[SDOGeom.getNumElements() - 1]; + ElemInfo info = SDOGeom.getInfo(); + int i = 0; + int idxInteriorRings = 0; + while ( i < info.getSize() ) { + CoordinateSequence cs = null; + int numCompounds = 0; + if ( info.getElementType( i ).isCompound() ) { + numCompounds = info.getNumCompounds( i ); + cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, SDOGeom ) ); + } + else { + cs = add( cs, getElementCSeq( i, SDOGeom, false ) ); + } + if ( info.getElementType( i ).isInteriorRing() ) { + holes[idxInteriorRings] = getGeometryFactory() + .createLinearRing( cs ); + idxInteriorRings++; + } + else { + shell = getGeometryFactory().createLinearRing( cs ); + } + i += 1 + numCompounds; + } + return getGeometryFactory().createPolygon( shell, holes ); + } + + private MultiPolygon convertSDOMultiPolygon(int dim, int lrsDim, + SDOGeometry SDOGeom) { + List holes = new ArrayList(); + List polygons = new ArrayList(); + ElemInfo info = SDOGeom.getInfo(); + LinearRing shell = null; + int i = 0; + while ( i < info.getSize() ) { + CoordinateSequence cs = null; + int numCompounds = 0; + if ( info.getElementType( i ).isCompound() ) { + numCompounds = info.getNumCompounds( i ); + cs = add( cs, getCompoundCSeq( i + 1, i + numCompounds, SDOGeom ) ); + } + else { + cs = add( cs, getElementCSeq( i, SDOGeom, false ) ); + } + if ( info.getElementType( i ).isInteriorRing() ) { + LinearRing lr = getGeometryFactory().createLinearRing( cs ); + holes.add( lr ); + } + else { + if ( shell != null ) { + Polygon polygon = getGeometryFactory().createPolygon( + shell, + holes.toArray( new LinearRing[holes.size()] ) + ); + polygons.add( polygon ); + shell = null; + } + shell = getGeometryFactory().createLinearRing( cs ); + holes = new ArrayList(); + } + i += 1 + numCompounds; + } + if ( shell != null ) { + Polygon polygon = getGeometryFactory().createPolygon( + shell, + holes.toArray( new LinearRing[holes.size()] ) + ); + polygons.add( polygon ); + } + MultiPolygon multiPolygon = getGeometryFactory().createMultiPolygon( + polygons.toArray( new Polygon[polygons.size()] ) + ); + return multiPolygon; + } + + /** + * Gets the CoordinateSequence corresponding to a compound element. + * + * @param idxFirst the first sub-element of the compound element + * @param idxLast the last sub-element of the compound element + * @param SDOGeom the SDOGeometry that holds the compound element. + * + * @return + */ + private CoordinateSequence getCompoundCSeq(int idxFirst, int idxLast, + SDOGeometry SDOGeom) { + CoordinateSequence cs = null; + for ( int i = idxFirst; i <= idxLast; i++ ) { + // pop off the last element as it is added with the next + // coordinate sequence + if ( cs != null && cs.size() > 0 ) { + Coordinate[] coordinates = cs.toCoordinateArray(); + Coordinate[] newCoordinates = new Coordinate[coordinates.length - 1]; + System.arraycopy( + coordinates, 0, newCoordinates, 0, + coordinates.length - 1 + ); + cs = getGeometryFactory().getCoordinateSequenceFactory() + .create( newCoordinates ); + } + cs = add( cs, getElementCSeq( i, SDOGeom, ( i < idxLast ) ) ); + } + return cs; + } + + /** + * Gets the CoordinateSequence corresponding to an element. + * + * @param i + * @param SDOGeom + * + * @return + */ + private CoordinateSequence getElementCSeq(int i, SDOGeometry SDOGeom, + boolean hasNextSE) { + ElementType type = SDOGeom.getInfo().getElementType( i ); + Double[] elemOrdinates = extractOrdinatesOfElement( + i, SDOGeom, + hasNextSE + ); + CoordinateSequence cs; + if ( type.isStraightSegment() ) { + cs = convertOrdinateArray( elemOrdinates, SDOGeom ); + } + else if ( type.isArcSegment() || type.isCircle() ) { + Coordinate[] linearized = linearize( + elemOrdinates, SDOGeom + .getDimension(), SDOGeom.isLRSGeometry(), type.isCircle() + ); + cs = getGeometryFactory().getCoordinateSequenceFactory().create( + linearized + ); + } + else if ( type.isRect() ) { + cs = convertOrdinateArray( elemOrdinates, SDOGeom ); + Coordinate ll = cs.getCoordinate( 0 ); + Coordinate ur = cs.getCoordinate( 1 ); + Coordinate lr = new Coordinate( ur.x, ll.y ); + Coordinate ul = new Coordinate( ll.x, ur.y ); + if ( type.isExteriorRing() ) { + cs = getGeometryFactory().getCoordinateSequenceFactory() + .create( new Coordinate[] { ll, lr, ur, ul, ll } ); + } + else { + cs = getGeometryFactory().getCoordinateSequenceFactory() + .create( new Coordinate[] { ll, ul, ur, lr, ll } ); + } + } + else { + throw new RuntimeException( + "Unexpected Element type in compound: " + + type + ); + } + return cs; + } + + private CoordinateSequence add(CoordinateSequence seq1, + CoordinateSequence seq2) { + if ( seq1 == null ) { + return seq2; + } + if ( seq2 == null ) { + return seq1; + } + Coordinate[] c1 = seq1.toCoordinateArray(); + Coordinate[] c2 = seq2.toCoordinateArray(); + Coordinate[] c3 = new Coordinate[c1.length + c2.length]; + System.arraycopy( c1, 0, c3, 0, c1.length ); + System.arraycopy( c2, 0, c3, c1.length, c2.length ); + return getGeometryFactory().getCoordinateSequenceFactory().create( c3 ); + } + + private Double[] extractOrdinatesOfElement(int element, + SDOGeometry SDOGeom, boolean hasNextSE) { + int start = SDOGeom.getInfo().getOrdinatesOffset( element ); + if ( element < SDOGeom.getInfo().getSize() - 1 ) { + int end = SDOGeom.getInfo().getOrdinatesOffset( element + 1 ); + // if this is a subelement of a compound geometry, + // the last point is the first point of + // the next subelement. + if ( hasNextSE ) { + end += SDOGeom.getDimension(); + } + return SDOGeom.getOrdinates().getOrdinatesArray( start, end ); + } + else { + return SDOGeom.getOrdinates().getOrdinatesArray( start ); + } + } + + private CoordinateSequence convertOrdinateArray(Double[] oordinates, + SDOGeometry SDOGeom) { + int dim = SDOGeom.getDimension(); + Coordinate[] coordinates = new Coordinate[oordinates.length / dim]; + int zDim = SDOGeom.getZDimension() - 1; + int lrsDim = SDOGeom.getLRSDimension() - 1; + for ( int i = 0; i < coordinates.length; i++ ) { + if ( dim == 2 ) { + coordinates[i] = new Coordinate( + oordinates[i * dim], + oordinates[i * dim + 1] + ); + } + else if ( dim == 3 ) { + if ( SDOGeom.isLRSGeometry() ) { + coordinates[i] = MCoordinate.create2dWithMeasure( + oordinates[i * dim], // X + oordinates[i * dim + 1], // Y + oordinates[i * dim + lrsDim] + ); // M + } + else { + coordinates[i] = new Coordinate( + oordinates[i * dim], // X + oordinates[i * dim + 1], // Y + oordinates[i * dim + zDim] + ); // Z + } + } + else if ( dim == 4 ) { + // This must be an LRS Geometry + if ( !SDOGeom.isLRSGeometry() ) { + throw new HibernateException( + "4 dimensional Geometries must be LRS geometry" + ); + } + coordinates[i] = MCoordinate.create3dWithMeasure( + oordinates[i + * dim], // X + oordinates[i * dim + 1], // Y + oordinates[i * dim + zDim], // Z + oordinates[i * dim + lrsDim] + ); // M + } + } + return getGeometryFactory().getCoordinateSequenceFactory().create( + coordinates + ); + } + + + /** + * Linearizes arcs and circles. + * + * @param arcOrdinates arc or circle coordinates + * @param dim coordinate dimension + * @param lrs whether this is an lrs geometry + * @param entireCirlce whether the whole arc should be linearized + * + * @return linearized interpolation of arcs or circle + */ + private Coordinate[] linearize(Double[] arcOrdinates, int dim, boolean lrs, + boolean entireCirlce) { + Coordinate[] linearizedCoords = new Coordinate[0]; + // CoordDim is the dimension that includes only non-measure (X,Y,Z) + // ordinates in its value + int coordDim = lrs ? dim - 1 : dim; + // this only works with 2-Dimensional geometries, since we use + // JGeometry linearization; + if ( coordDim != 2 ) { + throw new IllegalArgumentException( + "Can only linearize 2D arc segments, but geometry is " + + dim + "D." + ); + } + int numOrd = dim; + while ( numOrd < arcOrdinates.length ) { + numOrd = numOrd - dim; + double x1 = arcOrdinates[numOrd++]; + double y1 = arcOrdinates[numOrd++]; + double m1 = lrs ? arcOrdinates[numOrd++] : Double.NaN; + double x2 = arcOrdinates[numOrd++]; + double y2 = arcOrdinates[numOrd++]; + double m2 = lrs ? arcOrdinates[numOrd++] : Double.NaN; + double x3 = arcOrdinates[numOrd++]; + double y3 = arcOrdinates[numOrd++]; + double m3 = lrs ? arcOrdinates[numOrd++] : Double.NaN; + + Coordinate[] coords; + if ( entireCirlce ) { + coords = Circle.linearizeCircle( x1, y1, x2, y2, x3, y3 ); + } + else { + coords = Circle.linearizeArc( x1, y1, x2, y2, x3, y3 ); + } + + // if this is an LRS geometry, fill the measure values into + // the linearized array + if ( lrs ) { + MCoordinate[] mcoord = new MCoordinate[coords.length]; + int lastIndex = coords.length - 1; + mcoord[0] = MCoordinate.create2dWithMeasure( x1, y1, m1 ); + mcoord[lastIndex] = MCoordinate.create2dWithMeasure( x3, y3, m3 ); + // convert the middle coordinates to MCoordinate + for ( int i = 1; i < lastIndex; i++ ) { + mcoord[i] = MCoordinate.convertCoordinate( coords[i] ); + // if we happen to split on the middle measure, then + // assign it + if ( Double.compare( mcoord[i].x, x2 ) == 0 + && Double.compare( mcoord[i].y, y2 ) == 0 ) { + mcoord[i].m = m2; + } + } + coords = mcoord; + } + + // if this is not the first arcsegment, the first linearized + // point is already in linearizedArc, so disregard this. + int resultBegin = 1; + if ( linearizedCoords.length == 0 ) { + resultBegin = 0; + } + + int destPos = linearizedCoords.length; + Coordinate[] tmpCoords = new Coordinate[linearizedCoords.length + + coords.length - resultBegin]; + System.arraycopy( + linearizedCoords, 0, tmpCoords, 0, + linearizedCoords.length + ); + System.arraycopy( + coords, resultBegin, tmpCoords, destPos, + coords.length - resultBegin + ); + + linearizedCoords = tmpCoords; + } + return linearizedCoords; + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectMethod.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectMethod.java new file mode 100644 index 0000000000..1f3946164c --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectMethod.java @@ -0,0 +1,109 @@ +/* + * $Id: SDOObjectMethod.java 268 2010-10-28 19:16:54Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle; + +import java.util.List; + +import org.hibernate.QueryException; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.type.Type; + +/** + * Special SQLFunction implementation for Oracle object methods + * + * @author Karel Maesen + */ +class SDOObjectMethod implements SQLFunction { + + private final Type type; + + private final String name; + + public SDOObjectMethod(String name, Type type) { + this.type = type; + this.name = name; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#getReturnType(org.hibernate.type.Type, + * org.hibernate.engine.Mapping) + */ + + public Type getReturnType(Type columnType, Mapping mapping) + throws QueryException { + return type == null ? columnType : type; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#hasArguments() + */ + + public boolean hasArguments() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#hasParenthesesIfNoArguments() + */ + + public boolean hasParenthesesIfNoArguments() { + return true; + } + + public String getName() { + return this.name; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#render(java.util.List, + * org.hibernate.engine.SessionFactoryImplementor) + */ + + public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) throws QueryException { + StringBuffer buf = new StringBuffer(); + if (args.isEmpty()) + throw new QueryException( + "First Argument in arglist must be object to which method is applied"); + buf.append(args.get(0)).append(".").append(name).append('('); + for (int i = 1; i < args.size(); i++) { + buf.append(args.get(i)); + if (i < args.size() - 1) { + buf.append(", "); + } + } + return buf.append(')').toString(); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java new file mode 100644 index 0000000000..696c7b6ee0 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOObjectProperty.java @@ -0,0 +1,104 @@ +/* + * $Id: SDOObjectProperty.java 268 2010-10-28 19:16:54Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle; + +import java.util.List; + +import org.hibernate.QueryException; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.type.Type; + +/** + * Special function for accessing a member variable of an Oracle Object + * + * @author Karel Maesen + */ +class SDOObjectProperty implements SQLFunction { + + private final Type type; + + private final String name; + + public SDOObjectProperty(String name, Type type) { + this.type = type; + this.name = name; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#getReturnType(org.hibernate.type.Type, + * org.hibernate.engine.Mapping) + */ + + public Type getReturnType(Type columnType, Mapping mapping) + throws QueryException { + return type == null ? columnType : type; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#hasArguments() + */ + + public boolean hasArguments() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#hasParenthesesIfNoArguments() + */ + + public boolean hasParenthesesIfNoArguments() { + return false; + } + + public String getName() { + return this.name; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.dialect.function.SQLFunction#render(java.util.List, + * org.hibernate.engine.SessionFactoryImplementor) + */ + + public String render(Type firstArgtype, List args, SessionFactoryImplementor factory) + throws QueryException { + StringBuffer buf = new StringBuffer(); + if (args.isEmpty()) + throw new QueryException( + "First Argument in arglist must be object of which property is queried"); + buf.append(args.get(0)).append(".").append(name); + return buf.toString(); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOPoint.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOPoint.java new file mode 100644 index 0000000000..7c7042cb29 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOPoint.java @@ -0,0 +1,37 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.SQLException; +import java.sql.Struct; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jul 1, 2010 + */ +class SDOPoint { + public double x = 0.0; + + public double y = 0.0; + + public double z = Double.NaN; + + public SDOPoint(Struct struct) { + try { + Object[] data = struct.getAttributes(); + this.x = ((Number) data[0]).doubleValue(); + this.y = ((Number) data[1]).doubleValue(); + if (data[2] != null) { + this.z = ((Number) data[1]).doubleValue(); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public String toString() { + StringBuilder stb = new StringBuilder(); + stb.append("(").append(x).append(",").append(y).append(",").append( + z).append(")"); + return stb.toString(); + } + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SpatialAggregate.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SpatialAggregate.java new file mode 100644 index 0000000000..3e8996de17 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SpatialAggregate.java @@ -0,0 +1,91 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + + +import org.hibernate.spatial.dialect.oracle.criterion.OracleSpatialAggregate; + +/** + * Provides Aggregate type spatial function interpretation + */ +class SpatialAggregate { + + boolean _aggregateType; + + String _aggregateSyntax; + + private final String SDO_AGGR = "SDO_AGGR_"; + + SpatialAggregate() { + } + + SpatialAggregate(int aggregation) { + + String specificAggrSyntax; + + switch (aggregation) { + case org.hibernate.spatial.SpatialAggregate.EXTENT: + specificAggrSyntax = "MBR"; + _aggregateType = false; + break; + case OracleSpatialAggregate.LRS_CONCAT: + specificAggrSyntax = "LRS_CONCAT"; + _aggregateType = true; + break; + case OracleSpatialAggregate.CENTROID: + specificAggrSyntax = "CENTROID"; + _aggregateType = true; + break; + case OracleSpatialAggregate.CONCAT_LINES: + specificAggrSyntax = "CONCAT_LINES"; + _aggregateType = false; + break; + case OracleSpatialAggregate.UNION: + specificAggrSyntax = "UNION"; + _aggregateType = true; + break; + case OracleSpatialAggregate.CONVEXHULL: + specificAggrSyntax = "CONVEXHULL"; + _aggregateType = true; + break; + default: + specificAggrSyntax = null; + break; + } + if (specificAggrSyntax != null) { + _aggregateSyntax = SDO_AGGR + specificAggrSyntax; + } + } + + public boolean isAggregateType() { + return _aggregateType; + } + + public String getAggregateSyntax() { + return _aggregateSyntax; + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/StructLoader.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/StructLoader.java new file mode 100644 index 0000000000..cbc25d879d --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/StructLoader.java @@ -0,0 +1,20 @@ +package org.hibernate.spatial.dialect.oracle; + +import java.sql.Array; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Struct; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jul 3, 2010 + */ +interface SQLTypeFactory { + + Struct createStruct(SDOGeometry geom, Connection conn) throws SQLException; + + Array createElemInfoArray(ElemInfo elemInfo, Connection conn) throws SQLException; + + Array createOrdinatesArray(Ordinates ordinates, Connection conn) throws SQLException; + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/TypeGeometry.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/TypeGeometry.java new file mode 100644 index 0000000000..c4278dd3c2 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/TypeGeometry.java @@ -0,0 +1,32 @@ +package org.hibernate.spatial.dialect.oracle; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Jul 1, 2010 + */ +enum TypeGeometry { + + UNKNOWN_GEOMETRY(0), POINT(1), LINE(2), POLYGON(3), COLLECTION(4), MULTIPOINT( + 5), MULTILINE(6), MULTIPOLYGON(7), SOLID(8), MULTISOLID(9); + + private int gtype = 0; + + TypeGeometry(int gtype) { + this.gtype = gtype; + } + + int intValue() { + return this.gtype; + } + + static TypeGeometry parse(int v) { + for (TypeGeometry gt : values()) { + if (gt.intValue() == v) { + return gt; + } + } + throw new RuntimeException("Value " + v + + " isn't a valid TypeGeometry value"); + } + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/WrappedOGCFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/WrappedOGCFunction.java new file mode 100644 index 0000000000..0e60ed1d20 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/WrappedOGCFunction.java @@ -0,0 +1,77 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import java.util.List; + +import com.vividsolutions.jts.geom.Geometry; + +import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.type.Type; + +/** + * An HQL function that is implemented using Oracle's OGC compliance + * package. + */ +class WrappedOGCFunction extends StandardSQLFunction { + private final boolean[] geomArrays; + + /** + * @param name function name + * @param type return type of the function + * @param geomArrays indicates which argument places are occupied by + * sdo_geometries + */ + WrappedOGCFunction(final String name, final Type type, + final boolean[] geomArrays) { + super(name, type); + this.geomArrays = geomArrays; + } + + public String render(Type firstArgumentType, final List args, + final SessionFactoryImplementor factory) { + + StringBuffer buf = new StringBuffer(); + buf.append("MDSYS.").append(getName()).append("("); + for (int i = 0; i < args.size(); i++) { + if (i > 0) { + buf.append(","); + } + if (geomArrays[i]) { + buf.append("MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(").append( + args.get(i)).append(")"); + } else { + buf.append(args.get(i)); + } + + } + buf.append(")"); + return (getType().getReturnedClass() == Geometry.class) ? buf + .append(".geom").toString() : buf.toString(); + } + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialAggregate.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialAggregate.java new file mode 100644 index 0000000000..7395c6b2aa --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialAggregate.java @@ -0,0 +1,48 @@ +/** + * $Id: OracleSpatialAggregate.java 103 2008-08-15 10:45:29Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle.criterion; + + +import org.hibernate.spatial.SpatialAggregate; + +/** + * Defines types of OracleSpatialAggregate + */ +public interface OracleSpatialAggregate extends SpatialAggregate { + + public static int LRS_CONCAT = 100; + + public static int CENTROID = 101; + + public static int CONCAT_LINES = 102; + + public static int UNION = 103; + + public static int CONVEXHULL = 104; +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjection.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjection.java new file mode 100644 index 0000000000..9907fa82df --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjection.java @@ -0,0 +1,86 @@ +/** + * $Id: OracleSpatialProjection.java 268 2010-10-28 19:16:54Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle.criterion; + +import org.hibernate.Criteria; +import org.hibernate.HibernateException; +import org.hibernate.criterion.CriteriaQuery; +import org.hibernate.criterion.SimpleProjection; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.type.Type; + +/** + * Template class for Spatial Projections + * + * @author Tom Acree + */ +public class OracleSpatialProjection extends SimpleProjection { + + private static final long serialVersionUID = 1L; + + private final String propertyName; + + private final int aggregate; + + public OracleSpatialProjection(int aggregate, String propertyName) { + this.propertyName = propertyName; + this.aggregate = aggregate; + } + + public String toSqlString(Criteria criteria, int position, + CriteriaQuery criteriaQuery) throws HibernateException { + + SessionFactoryImplementor factory = criteriaQuery.getFactory(); + String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, + this.propertyName); + Dialect dialect = factory.getDialect(); + if (dialect instanceof SpatialDialect) { + SpatialDialect seDialect = (SpatialDialect) dialect; + + return new StringBuffer(seDialect.getSpatialAggregateSQL( + columns[0], this.aggregate)).append(" y").append(position) + .append("_").toString(); + } else { + throw new IllegalStateException( + "Dialect must be spatially enabled dialect"); + } + + } + + public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) + throws HibernateException { + return new Type[]{criteriaQuery.getType(criteria, this.propertyName)}; + } + + public String toString() { + return aggregate + "(" + propertyName + ")"; + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjections.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjections.java new file mode 100644 index 0000000000..ab879358b4 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialProjections.java @@ -0,0 +1,60 @@ +/** + * $Id: OracleSpatialProjections.java 67 2007-12-16 16:41:55Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle.criterion; + +/** + * Factory class for SpationProjection functions * + * + * @author Tom Acree + */ +public final class OracleSpatialProjections { + + private OracleSpatialProjections() { + } + + public static OracleSpatialProjection concatLrs(String propertyName) { + return new OracleSpatialProjection(OracleSpatialAggregate.LRS_CONCAT, + propertyName); + } + + public static OracleSpatialProjection centroid(String propertyName) { + return new OracleSpatialProjection(OracleSpatialAggregate.CENTROID, + propertyName); + } + + public static OracleSpatialProjection concatLines(String propertyName) { + return new OracleSpatialProjection(OracleSpatialAggregate.CONCAT_LINES, + propertyName); + } + + public static OracleSpatialProjection projection(int projection, + String propertyName) { + return new OracleSpatialProjection(projection, propertyName); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialRestrictions.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialRestrictions.java new file mode 100644 index 0000000000..b70abaf3e5 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/OracleSpatialRestrictions.java @@ -0,0 +1,204 @@ +/** + * $Id: OracleSpatialRestrictions.java 268 2010-10-28 19:16:54Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle.criterion; + +import com.vividsolutions.jts.geom.Geometry; + +import org.hibernate.Criteria; +import org.hibernate.HibernateException; +import org.hibernate.criterion.CriteriaQuery; +import org.hibernate.criterion.Criterion; +import org.hibernate.engine.spi.TypedValue; + +/** + * A static factory class for creating Criterion instances that + * correspond to Oracle Spatial "native" spatial operators. + * + * @author Karel Maesen + */ +public class OracleSpatialRestrictions { + + @SuppressWarnings("serial") + public static Criterion SDOFilter(String propertyName, Geometry geom, + SDOParameterMap param) { + return new OracleSpatialCriterion(propertyName, geom, param) { + @Override + public String toSqlString(Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException { + String[] columns = criteriaQuery.getColumnsUsingProjection( + criteria, this.propertyName); + StringBuilder sql = new StringBuilder("SDO_FILTER("); + sql.append(columns[0]).append(",").append("?"); + if (param != null && !param.isEmpty()) { + sql.append(",").append(param.toQuotedString()); + } + sql.append(") = 'TRUE'"); + return sql.toString(); + } + }; + } + + @SuppressWarnings("serial") + public static Criterion SDOFilter(String propertyName, Geometry geom, + Double minResolution, Double maxResolution) { + if (minResolution == null && maxResolution == null) { + return SDOFilter(propertyName, geom, null); + } else { + SDOParameterMap param = new SDOParameterMap(); + param.setMinResolution(minResolution); + param.setMaxResolution(maxResolution); + return SDOFilter(propertyName, geom, param); + } + } + + @SuppressWarnings("serial") + public static Criterion SDONN(String propertyName, Geometry geom, + Double distance, Integer numResults, String unit) { + if (distance == null && numResults == null && unit == null) { + return SDONN(propertyName, geom, null); + } else { + SDOParameterMap param = new SDOParameterMap(); + param.setDistance(distance); + param.setSdoNumRes(numResults); + param.setUnit(unit); + return SDONN(propertyName, geom, param); + } + } + + @SuppressWarnings("serial") + public static Criterion SDONN(String propertyName, Geometry geom, + SDOParameterMap param) { + return new OracleSpatialCriterion(propertyName, geom, param) { + @Override + public String toSqlString(Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException { + String[] columns = criteriaQuery.getColumnsUsingProjection( + criteria, this.propertyName); + StringBuilder sql = new StringBuilder("SDO_NN("); + sql.append(columns[0]).append(",").append("?"); + if (param != null && !param.isEmpty()) { + sql.append(",").append(param.toQuotedString()); + } + sql.append(") = 'TRUE'"); + return sql.toString(); + } + }; + } + + @SuppressWarnings("serial") + public static Criterion SDORelate(String propertyName, Geometry geom, + SDOParameterMap param) { + return new OracleSpatialCriterion(propertyName, geom, param) { + @Override + public String toSqlString(Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException { + String[] columns = criteriaQuery.getColumnsUsingProjection( + criteria, this.propertyName); + StringBuilder sql = new StringBuilder("SDO_RELATE("); + sql.append(columns[0]).append(",").append("?"); + if (param != null && !param.isEmpty()) { + sql.append(",").append(param.toQuotedString()); + } + sql.append(") = 'TRUE'"); + return sql.toString(); + } + }; + } + + @SuppressWarnings("serial") + public static Criterion SDORelate(String propertyName, Geometry geom, + RelationshipMask[] mask, Double minResolution, Double maxResolution) { + SDOParameterMap param = new SDOParameterMap(); + param.setMask(RelationshipMask.booleanCombination(mask)); + param.setMinResolution(minResolution); + param.setMaxResolution(maxResolution); + return SDORelate(propertyName, geom, param); + } + + @SuppressWarnings("serial") + public static Criterion SDOWithinDistance(String propertyName, + Geometry geom, SDOParameterMap param) { + return new OracleSpatialCriterion(propertyName, geom, param) { + + @Override + public String toSqlString(Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException { + String[] columns = criteriaQuery.getColumnsUsingProjection( + criteria, this.propertyName); + StringBuilder sql = new StringBuilder("SDO_WITHIN_DISTANCE("); + sql.append(columns[0]).append(",").append("?"); + if (param != null && !param.isEmpty()) { + sql.append(",").append(param.toQuotedString()); + } + sql.append(") = 'TRUE'"); + return sql.toString(); + } + }; + } + + public static Criterion SDOWithinDistance(String propertyName, + Geometry geom, Double distance, SDOParameterMap param) { + if (param == null) { + param = new SDOParameterMap(); + } + param.setDistance(distance); + return SDOWithinDistance(propertyName, geom, param); + } +} + +abstract class OracleSpatialCriterion implements Criterion { + protected String propertyName; + + protected Geometry value; + + protected SDOParameterMap param; + + public OracleSpatialCriterion(String propertyName, Geometry value, + SDOParameterMap param) { + this.propertyName = propertyName; + this.value = value; + this.param = param; + } + + /* + * (non-Javadoc) + * + * @see org.hibernate.criterion.Criterion#getTypedValues(org.hibernate.Criteria, + * org.hibernate.criterion.CriteriaQuery) + */ + + public TypedValue[] getTypedValues(Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException { + return new TypedValue[]{criteriaQuery.getTypedValue(criteria, + propertyName, value)}; + } + + abstract public String toSqlString(Criteria criteria, + CriteriaQuery criteriaQuery) throws HibernateException; + +} \ No newline at end of file diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/RelationshipMask.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/RelationshipMask.java new file mode 100644 index 0000000000..77b0bdd811 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/RelationshipMask.java @@ -0,0 +1,45 @@ +/** + * $Id: RelationshipMask.java 103 2008-08-15 10:45:29Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * Copyright © 2007 K.U. Leuven LRD, Spatial Applications Division, Belgium + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle.criterion; + +public enum RelationshipMask { + TOUCH, OVERLAPBYDISJOINT, OVERLAPBYINTERSECT, EQUAL, INSIDE, COVEREDBY, CONTAINS, COVERS, ANYINTERACT, ON; + + public static String booleanCombination(RelationshipMask[] masks) { + String strMask = null; + for (RelationshipMask relationshipMask : masks) { + if (strMask == null) { + strMask = relationshipMask.toString(); + } else { + strMask += "+" + relationshipMask.toString(); + } + } + return strMask; + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/SDOParameterMap.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/SDOParameterMap.java new file mode 100644 index 0000000000..97540537b8 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/criterion/SDOParameterMap.java @@ -0,0 +1,192 @@ +/** + * $Id: SDOParameterMap.java 67 2007-12-16 16:41:55Z maesenka $ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007 Geovise BVBA + * + * This work was partially supported by the European Commission, + * under the 6th Framework Programme, contract IST-2-004688-STP. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ +package org.hibernate.spatial.dialect.oracle.criterion; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class represents the parameters that can be passed into Oracle's Spatial + * Operators + * + * @author Karel Maesen + * + */ +public class SDOParameterMap { + + public static final String DISTANCE = "distance"; + + public static final String SDO_BATCH_SIZE = "sdo_batch_size"; + + public static final String SDO_NUM_RES = "sdo_num_res"; + + public static final String UNIT = "unit"; + + public static final String MIN_RESOLUTION = "min_resolution"; + + public static final String MAX_RESOLUTION = "max_resolution"; + + public static final String MASK = "mask"; + + public static final String QUERYTYPE = "querytype"; + + private Map params = new HashMap(); + + public SDOParameterMap() { + } + + public boolean isEmpty() { + return this.params.isEmpty(); + } + + public void setDistance(Double distance) { + if (distance != null) + params.put(DISTANCE, distance); + } + + public Double getDistance() { + return (Double) params.get(DISTANCE); + } + + public void removeDistance() { + params.remove(DISTANCE); + } + + public void setSdoBatchSize(Integer size) { + if (size != null) + params.put(SDO_BATCH_SIZE, size); + } + + public Integer getSdoBatchSize() { + return (Integer) params.get(SDO_BATCH_SIZE); + } + + public void removeSdoBatchSize() { + params.remove(SDO_BATCH_SIZE); + } + + public void setSdoNumRes(Integer size) { + if (size != null) + params.put(SDO_NUM_RES, size); + } + + public Integer getSdoNumRes() { + return (Integer) params.get(SDO_NUM_RES); + } + + public void removeSdoNumRes() { + params.remove(SDO_NUM_RES); + } + + public void setUnit(String unit) { + if (unit != null) + this.params.put(UNIT, unit); + } + + public String getUnit() { + return (String) this.params.get(UNIT); + } + + public void removeUnit() { + this.params.remove(UNIT); + } + + public void setMaxResolution(Double res) { + if (res != null) + params.put(MAX_RESOLUTION, res); + } + + public Double getMaxResolution() { + return (Double) params.get(MAX_RESOLUTION); + } + + public void removeMaxResolution() { + params.remove(MAX_RESOLUTION); + } + + public void setMinResolution(Double res) { + if (res != null) + params.put(MIN_RESOLUTION, res); + } + + public Double getMinResolution() { + return (Double) params.get(MIN_RESOLUTION); + } + + public void removeMinResolution() { + params.remove(MIN_RESOLUTION); + } + + public void setMask(String mask) { + if (mask != null) + this.params.put(MASK, mask); + } + + public String getMask() { + return (String) this.params.get(MASK); + } + + public void removeMask() { + this.params.remove(MASK); + } + + public void setQueryType(String queryType) { + if (queryType != null) + this.params.put(QUERYTYPE, queryType); + } + + public void setQueryTypeToFilter() { + this.params.put(QUERYTYPE, "FILTER"); + } + + public String getQueryType() { + return (String) this.params.get(QUERYTYPE); + } + + public void removeQueryType() { + this.params.remove(QUERYTYPE); + } + + public String toQuotedString() { + StringBuilder stb = new StringBuilder(); + if (params.isEmpty()) { + return ""; + } + stb.append('\''); + for (String paramName : params.keySet()) { + if (params.get(paramName) == null) + continue; + stb.append(paramName).append("=").append(params.get(paramName)) + .append(" "); + } + stb.deleteCharAt(stb.length() - 1); + stb.append('\''); + return stb.toString(); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java new file mode 100644 index 0000000000..424bdb01a4 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueBinder.java @@ -0,0 +1,8 @@ +package org.hibernate.spatial.dialect.sqlserver; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 8/23/11 + */ +public class SqlServer2008GeometryValueBinder { +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java new file mode 100644 index 0000000000..1342c54995 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServer2008GeometryValueExtractor.java @@ -0,0 +1,8 @@ +package org.hibernate.spatial.dialect.sqlserver; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: 8/23/11 + */ +public class SqlServer2008GeometryValueExtractor { +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java index c2debdff3f..c74de81413 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/integration/SpatialIntegrator.java @@ -3,6 +3,7 @@ package org.hibernate.spatial.integration; import org.hibernate.cfg.Configuration; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.integrator.spi.Integrator; +import org.hibernate.metamodel.source.MetadataImplementor; import org.hibernate.service.spi.SessionFactoryServiceRegistry; import org.hibernate.spatial.GeometryType; @@ -17,6 +18,11 @@ public class SpatialIntegrator implements Integrator { sessionFactory.getTypeResolver().registerTypeOverride( GeometryType.INSTANCE ); } + @Override + public void integrate(MetadataImplementor metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { + metadata.getTypeResolver().registerTypeOverride( GeometryType.INSTANCE ); + } + @Override public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { //do nothing. diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/SpatialFunctionalTestCase.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/SpatialFunctionalTestCase.java index 4c0458112d..f293e8db73 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/SpatialFunctionalTestCase.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/SpatialFunctionalTestCase.java @@ -91,7 +91,6 @@ public abstract class SpatialFunctionalTestCase extends BaseCoreFunctionalTestCa } public String getBaseForMappings() { -// return "org/hibernatespatial/test/"; return ""; } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java index d54bb11640..358f3c6310 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/TestSupportFactories.java @@ -56,9 +56,9 @@ public class TestSupportFactories { // "org.hibernatespatial.mysql.MySQLSpatialInnoDBDialect".equals(canonicalName)) { // return "org.hibernatespatial.mysql.MySQLTestSupport"; // } -// if ("org.hibernatespatial.oracle.OracleSpatial10gDialect".equals(canonicalName)) { -// return "org.hibernatespatial.oracle.OracleSDOTestSupport"; -// } + if ( "org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect".equals( canonicalName ) ) { + return "org.hibernate.spatial.dialect.oracle.OracleSDOTestSupport"; + } throw new IllegalArgumentException( "Dialect not known in test suite" ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/JDBCConnectionProxy.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/JDBCConnectionProxy.java new file mode 100644 index 0000000000..6e59bca8ae --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/JDBCConnectionProxy.java @@ -0,0 +1,234 @@ +package org.hibernatespatial.oracle; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.Map; +import java.util.Properties; + +/** + * This class hides the actual Connection implementation class. + * + * @author Karel Maesen, Geovise BVBA + * creation-date: Jun 30, 2010 + */ +public class JDBCConnectionProxy implements Connection { + + private final Connection delegate; + + public JDBCConnectionProxy(Connection conn) { + this.delegate = conn; + } + + public T unwrap(Class iface) throws SQLException { + return delegate.unwrap( iface ); + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return delegate.isWrapperFor( iface ); + } + + public Statement createStatement() throws SQLException { + return delegate.createStatement(); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + return delegate.prepareStatement( sql ); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + return delegate.prepareCall( sql ); + } + + public String nativeSQL(String sql) throws SQLException { + return delegate.nativeSQL( sql ); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + delegate.setAutoCommit( autoCommit ); + } + + public boolean getAutoCommit() throws SQLException { + return delegate.getAutoCommit(); + } + + public void commit() throws SQLException { + delegate.commit(); + } + + public void rollback() throws SQLException { + delegate.rollback(); + } + + public void close() throws SQLException { + delegate.close(); + } + + public boolean isClosed() throws SQLException { + return delegate.isClosed(); + } + + public DatabaseMetaData getMetaData() throws SQLException { + return delegate.getMetaData(); + } + + public void setReadOnly(boolean readOnly) throws SQLException { + delegate.setReadOnly( readOnly ); + } + + public boolean isReadOnly() throws SQLException { + return delegate.isReadOnly(); + } + + public void setCatalog(String catalog) throws SQLException { + delegate.setCatalog( catalog ); + } + + public String getCatalog() throws SQLException { + return delegate.getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + delegate.setTransactionIsolation( level ); + } + + public int getTransactionIsolation() throws SQLException { + return delegate.getTransactionIsolation(); + } + + public SQLWarning getWarnings() throws SQLException { + return delegate.getWarnings(); + } + + public void clearWarnings() throws SQLException { + delegate.clearWarnings(); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return delegate.createStatement( resultSetType, resultSetConcurrency ); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + return delegate.prepareStatement( sql, resultSetType, resultSetConcurrency ); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return delegate.prepareCall( sql, resultSetType, resultSetConcurrency ); + } + + public Map> getTypeMap() throws SQLException { + return delegate.getTypeMap(); + } + + public void setTypeMap(Map> map) throws SQLException { + delegate.setTypeMap( map ); + } + + public void setHoldability(int holdability) throws SQLException { + delegate.setHoldability( holdability ); + } + + public int getHoldability() throws SQLException { + return delegate.getHoldability(); + } + + public Savepoint setSavepoint() throws SQLException { + return delegate.setSavepoint(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + return delegate.setSavepoint( name ); + } + + public void rollback(Savepoint savepoint) throws SQLException { + delegate.rollback( savepoint ); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + delegate.releaseSavepoint( savepoint ); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) + throws SQLException { + return delegate.createStatement( resultSetType, resultSetConcurrency, resultSetHoldability ); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) + throws SQLException { + return delegate.prepareStatement( sql, resultSetType, resultSetConcurrency, resultSetHoldability ); + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) + throws SQLException { + return delegate.prepareCall( sql, resultSetType, resultSetConcurrency, resultSetHoldability ); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + return delegate.prepareStatement( sql, autoGeneratedKeys ); + } + + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + return delegate.prepareStatement( sql, columnIndexes ); + } + + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + return delegate.prepareStatement( sql, columnNames ); + } + + public Clob createClob() throws SQLException { + return delegate.createClob(); + } + + public Blob createBlob() throws SQLException { + return delegate.createBlob(); + } + + public NClob createNClob() throws SQLException { + return delegate.createNClob(); + } + + public SQLXML createSQLXML() throws SQLException { + return delegate.createSQLXML(); + } + + public boolean isValid(int timeout) throws SQLException { + return delegate.isValid( timeout ); + } + + public void setClientInfo(String name, String value) throws SQLClientInfoException { + delegate.setClientInfo( name, value ); + } + + public void setClientInfo(Properties properties) throws SQLClientInfoException { + delegate.setClientInfo( properties ); + } + + public String getClientInfo(String name) throws SQLException { + return delegate.getClientInfo( name ); + } + + public Properties getClientInfo() throws SQLException { + return delegate.getClientInfo(); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return delegate.createArrayOf( typeName, elements ); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return delegate.createStruct( typeName, attributes ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/OracleSDOTestSupport.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/OracleSDOTestSupport.java new file mode 100644 index 0000000000..e9ded59fd0 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/OracleSDOTestSupport.java @@ -0,0 +1,37 @@ +package org.hibernate.spatial.dialect.oracle; + +import org.hibernate.cfg.Configuration; +import org.hibernate.spatial.test.AbstractExpectationsFactory; +import org.hibernate.spatial.test.DataSourceUtils; +import org.hibernate.spatial.test.SQLExpressionTemplate; +import org.hibernate.spatial.test.TestData; +import org.hibernate.spatial.test.TestSupport; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; + +/** + * @author Karel Maesen, Geovise BVBA + * creation-date: Oct 22, 2010 + */ +public class OracleSDOTestSupport extends TestSupport { + + @Override + public TestData createTestData(BaseCoreFunctionalTestCase testcase) { + return TestData.fromFile( "test-sdo-geometry-data-set-2D.xml", new SDOTestDataReader() ); + } + + @Override + public AbstractExpectationsFactory createExpectationsFactory(DataSourceUtils dataSourceUtils) { + return new SDOGeometryExpectationsFactory( dataSourceUtils ); + } + + @Override + public SQLExpressionTemplate getSQLExpressionTemplate() { + return new SDOGeometryExpressionTemplate(); + } + + @Override + public DataSourceUtils createDataSourceUtil(Configuration configuration) { + this.configuration = configuration; + return new SDODataSourceUtils( driver(), url(), user(), passwd(), getSQLExpressionTemplate() ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDODataSourceUtils.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDODataSourceUtils.java new file mode 100644 index 0000000000..382415cd78 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDODataSourceUtils.java @@ -0,0 +1,74 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import java.sql.SQLException; + +import org.hibernate.spatial.test.DataSourceUtils; +import org.hibernate.spatial.test.SQLExpressionTemplate; + + +public class SDODataSourceUtils extends DataSourceUtils { + + public SDODataSourceUtils(String jdbcDriver, String jdbcUrl, String jdbcUser, String jdbcPass, SQLExpressionTemplate sqlExpressionTemplate) { + super( jdbcDriver, jdbcUrl, jdbcUser, jdbcPass, sqlExpressionTemplate ); + } + + @Override + public void afterCreateSchema() { + super.afterCreateSchema(); + try { + setGeomMetaDataTo2D(); + createIndex(); + } + catch ( SQLException e ) { + throw new RuntimeException( e ); + } + + } + + private void createIndex() throws SQLException { + String sql = "create index idx_spatial_geomtest on geomtest (geom) indextype is mdsys.spatial_index"; + executeStatement( sql ); + } + + private void setGeomMetaDataTo2D() throws SQLException { + String sql1 = "delete from user_sdo_geom_metadata where TABLE_NAME = 'GEOMTEST'"; + String sql2 = "insert into user_sdo_geom_metadata values (" + + " 'GEOMTEST'," + + " 'geom'," + + " SDO_DIM_ARRAY(" + + " SDO_DIM_ELEMENT('X', -180, 180, 0.00001)," + + " SDO_DIM_ELEMENT('Y', -90, 90, 0.00001)" + + " )," + + " 4326)"; + executeStatement( sql1 ); + executeStatement( sql2 ); + + } + + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpectationsFactory.java new file mode 100644 index 0000000000..639ce98156 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpectationsFactory.java @@ -0,0 +1,270 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Point; + +import org.hibernate.spatial.test.AbstractExpectationsFactory; +import org.hibernate.spatial.test.DataSourceUtils; +import org.hibernate.spatial.test.NativeSQLStatement; + +/** + * Expectations factory for Oracle 10g (SDOGeometry). + * + * @Author Karel Maesen, Geovise BVBA + */ +public class SDOGeometryExpectationsFactory extends AbstractExpectationsFactory { + + private final SDOGeometryValueExtractor decoder = new SDOGeometryValueExtractor(); + + public SDOGeometryExpectationsFactory(DataSourceUtils dataSourceUtils) { + super( dataSourceUtils ); + } + + @Override + protected NativeSQLStatement createNativeTouchesStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Touch(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Touch(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeOverlapsStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Overlap(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Overlap(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeRelateStatement(Geometry geom, String matrix) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Relate(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326), '" + matrix + "') from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Relate(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326), '" + matrix + "') = 1 and t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeDwithinStatement(Point geom, double distance) { + throw new UnsupportedOperationException(); + } + + @Override + protected NativeSQLStatement createNativeIntersectsStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Intersects(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Intersects(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeFilterStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, 1 from GEOMTEST t where SDO_FILTER(t.GEOM, MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326).GEOM) = 'TRUE' ", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeDistanceStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Distance(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeDimensionSQL() { + return createNativeSQLStatement( + "select ID, MDSYS.OGC_DIMENSION(MDSYS.ST_GEOMETRY.FROM_SDO_GEOM( T.GEOM)) FROM GEOMTEST T" + ); + } + + @Override + protected NativeSQLStatement createNativeBufferStatement(Double distance) { + return createNativeSQLStatement( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Buffer(?).GEOM from GEOMTEST T where t.GEOM.SDO_SRID = 4326", + new Double[] { distance } + ); + } + + @Override + protected NativeSQLStatement createNativeConvexHullStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Union(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)).ST_ConvexHull().GEOM from GEOMTEST T where t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeIntersectionStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Intersection(MDSYS.ST_GEOMETRY.FROM_WKT(?,4326)).GEOM FROM GEOMTEST t where t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeDifferenceStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Difference(MDSYS.ST_GEOMETRY.FROM_WKT(?,4326)).GEOM FROM GEOMTEST t where t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeSymDifferenceStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_SymmetricDifference(MDSYS.ST_GEOMETRY.FROM_WKT(?,4326)).GEOM FROM GEOMTEST t where t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeGeomUnionStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Union(MDSYS.ST_GEOMETRY.FROM_WKT(?,4326)).GEOM FROM GEOMTEST t where t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeAsTextStatement() { + return createNativeSQLStatement( "select t.ID, t.GEOM.GET_WKT() FROM GEOMTEST T" ); + } + + @Override + protected NativeSQLStatement createNativeSridStatement() { + return createNativeSQLStatement( "SELECT t.ID, t.GEOM.SDO_SRID FROM GEOMTEST t" ); + } + + @Override + protected NativeSQLStatement createNativeIsSimpleStatement() { + return createNativeSQLStatement( + "SELECT t.ID, MDSYS.OGC_ISSIMPLE(MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM)) FROM GEOMTEST t where MDSYS.OGC_ISSIMPLE(MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM)) = 1" + ); + + } + + @Override + protected NativeSQLStatement createNativeIsEmptyStatement() { + return createNativeSQLStatement( + "SELECT t.ID, MDSYS.OGC_ISEMPTY(MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM)) FROM GEOMTEST t" + ); + } + + @Override + protected NativeSQLStatement createNativeIsNotEmptyStatement() { + return createNativeSQLStatement( + "SELECT t.ID, CASE MDSYS.OGC_ISEMPTY(MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM)) WHEN 0 THEN 1 ELSE 0 END FROM GEOMTEST t" + ); + } + + @Override + protected NativeSQLStatement createNativeBoundaryStatement() { + return createNativeSQLStatement( + "SELECT t.ID, MDSYS.OGC_BOUNDARY(MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM)).GEOM FROM GEOMTEST t" + ); + } + + @Override + protected NativeSQLStatement createNativeEnvelopeStatement() { + return createNativeSQLStatement( + "SELECT t.ID, MDSYS.OGC_ENVELOPE(MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM)).GEOM FROM GEOMTEST t" + ); + } + + @Override + protected NativeSQLStatement createNativeAsBinaryStatement() { + return createNativeSQLStatement( "select t.ID, t.GEOM.GET_WKB() FROM GEOMTEST T" ); + } + + @Override + protected NativeSQLStatement createNativeGeometryTypeStatement() { + return createNativeSQLStatement( + "select t.id, CASE t.geom.Get_GType() WHEN 1 THEN 'POINT' WHEN 2 THEN 'LINESTRING' WHEN 3 THEN 'POLYGON' WHEN 5 THEN 'MULTIPOINT' WHEN 6 THEN 'MULTILINE' WHEN 7 THEN 'MULTIPOLYGON' END from GEOMTEST t" + ); + } + + @Override + protected NativeSQLStatement createNativeWithinStatement(Geometry testPolygon) { + return createNativeSQLStatementAllWKTParams( + "select t.id, mdsys.OGC_WITHIN( MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM), MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where mdsys.OGC_WITHIN( MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM), MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + testPolygon.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeEqualsStatement(Geometry testPolygon) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Equals(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Equals(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + testPolygon.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeCrossesStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Cross(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Cross(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeContainsStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Contains(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Contains(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Disjoint(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) from GEOMTEST T where MDSYS.ST_GEOMETRY.FROM_SDO_GEOM(t.GEOM).ST_Disjoint(MDSYS.ST_GEOMETRY.FROM_WKT(?, 4326)) = 1 and t.GEOM.SDO_SRID = 4326", + geom.toText() + ); + } + + @Override + protected NativeSQLStatement createNativeTransformStatement(int epsg) { + return createNativeSQLStatement( + "select t.id, MDSYS.SDO_CS.transform(t.geom," + epsg + ") from GeomTest t where t.geom.SDO_SRID = 4326" + ); + } + + @Override + protected NativeSQLStatement createNativeHavingSRIDStatement(int srid) { + return createNativeSQLStatement( "select t.id, 1 from GeomTest t where t.geom.SDO_SRID = " + srid ); + } + + @Override + protected Geometry decode(Object o) { + return decoder.toJTS( o ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpressionTemplate.java new file mode 100644 index 0000000000..2604b37842 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOGeometryExpressionTemplate.java @@ -0,0 +1,39 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import org.hibernate.spatial.test.SQLExpressionTemplate; +import org.hibernate.spatial.test.TestDataElement; + +public class SDOGeometryExpressionTemplate implements SQLExpressionTemplate { + + final String SQL_TEMPLATE = "insert into geomtest values (%d, '%s', %s)"; + + public String toInsertSql(TestDataElement testDataElement) { + SDOTestDataElement sdoTestDataElement = (SDOTestDataElement) testDataElement; + return String.format( SQL_TEMPLATE, sdoTestDataElement.id, sdoTestDataElement.type, sdoTestDataElement.sdo ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataElement.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataElement.java new file mode 100644 index 0000000000..dbead63dcb --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataElement.java @@ -0,0 +1,47 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + + +import org.hibernate.spatial.test.TestDataElement; + +/** + * A specialised subclass for SDOGeometry test objects + *

+ * Oracle 10g WKT support is limited to 2D geometries, and there is + * no method of specifying SRID. That is why we here add the equivalent SDO expression + * that can be used by the TestData + */ +public class SDOTestDataElement extends TestDataElement { + + public final String sdo; + + public SDOTestDataElement(int id, String type, String wkt, int srid, String sdo) { + super( id, type, wkt, srid ); + this.sdo = sdo; + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataReader.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataReader.java new file mode 100644 index 0000000000..e0a4eabe62 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/oracle/SDOTestDataReader.java @@ -0,0 +1,50 @@ +/* + * $Id:$ + * + * This file is part of Hibernate Spatial, an extension to the + * hibernate ORM solution for geographic data. + * + * Copyright © 2007-2010 Geovise BVBA + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For more information, visit: http://www.hibernatespatial.org/ + */ + +package org.hibernate.spatial.dialect.oracle; + +import java.util.List; + +import org.dom4j.Element; + +import org.hibernate.spatial.test.TestDataElement; +import org.hibernate.spatial.test.TestDataReader; + + +public class SDOTestDataReader extends TestDataReader { + + + @Override + protected void addDataElement(Element element, List testDataElements) { + int id = Integer.valueOf( element.selectSingleNode( "id" ).getText() ); + String type = element.selectSingleNode( "type" ).getText(); + String wkt = element.selectSingleNode( "wkt" ).getText(); + int srid = Integer.valueOf( element.selectSingleNode( "srid" ).getText() ); + String sdo = element.selectSingleNode( "sdo" ).getText(); + TestDataElement testDataElement = new SDOTestDataElement( id, type, wkt, srid, sdo ); + testDataElements.add( testDataElement ); + } + +} diff --git a/hibernate-spatial/src/test/resources/hibernate.properties b/hibernate-spatial/src/test/resources/hibernate.properties index cd7f5dc5ea..732b4758fb 100644 --- a/hibernate-spatial/src/test/resources/hibernate.properties +++ b/hibernate-spatial/src/test/resources/hibernate.properties @@ -21,11 +21,19 @@ # 51 Franklin Street, Fifth Floor # Boston, MA 02110-1301 USA # -hibernate.dialect org.hibernate.spatial.dialect.postgis.PostgisDialect -hibernate.connection.driver_class org.postgresql.Driver -hibernate.connection.url jdbc:postgresql://localhost:5432:hibbrtru -hibernate.connection.username hibbrtru -hibernate.connection.password hibbrtru + +#hibernate.dialect org.hibernate.spatial.dialect.postgis.PostgisDialect +#hibernate.connection.driver_class org.postgresql.Driver +#hibernate.connection.url jdbc:postgresql://localhost:5432:hibbrtru +#hibernate.connection.username hibbrtru +#hibernate.connection.password hibbrtru + +hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect +hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver +hibernate.connection.url jdbc:oracle:thin:@oracle.geovise.com/ORCL +hibernate.connection.username hbs +hibernate.connection.password hbs + hibernate.connection.pool_size 5 diff --git a/hibernate-spatial/src/test/resources/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties b/hibernate-spatial/src/test/resources/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties new file mode 100644 index 0000000000..79b4a9acea --- /dev/null +++ b/hibernate-spatial/src/test/resources/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties @@ -0,0 +1,27 @@ +# +# $Id: org.hibernatespatial.oracle.OracleSpatial10gDialect.properties 268 2010-10-28 19:16:54Z maesenka $ +# +# This file is part of Hibernate Spatial, an extension to the +# hibernate ORM solution for geographic data. +# +# Copyright © 2007-2010 Geovise BVBA +# +# 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; either +# version 2.1 of the License, or (at your option) any later version. +# +# 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. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# For more information, visit: http://www.hibernatespatial.org/ +# + +OGC_STRICT=true +CONNECTION-FINDER=org.hibernate.spatial.dialect.oracle.DefaultConnectionFinder \ No newline at end of file diff --git a/hibernate-spatial/src/test/resources/test-sdo-geometry-data-set-2D.xml b/hibernate-spatial/src/test/resources/test-sdo-geometry-data-set-2D.xml new file mode 100644 index 0000000000..e10a59934c --- /dev/null +++ b/hibernate-spatial/src/test/resources/test-sdo-geometry-data-set-2D.xml @@ -0,0 +1,282 @@ + + + + + + + 1 + POINT + SDO_GEOMETRY(2001, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(10.0, 5.0)) + POINT(10 5) + 4326 + + + 2 + POINT + SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(52.25, 2.53, NULL), NULL, NULL) + POINT(52.25 2.53) + 4326 + + + + + 5 + LINESTRING + LINESTRING(10.0 5.0, 20.0 15.0) + 4326 + SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0)) + + + + 6 + LINESTRING + LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) + 4326 + SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0, 30.3, + 22.4, 10.0, 30.0 )) + + + + + + 11 + MULTILINESTRING + MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) + 4326 + SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,5,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, + 15.0,25.0,30.0, 30.0,20.0)) + + + + + 12 + MULTILINESTRING + MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + + 4326 + SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,9,2,1), + SDO_ORDINATE_ARRAY(10.0,5.0,20.0,15.0,30.3,22.4,10,30.0,40.0,20.0,42.0,18.0,43.0,16.0,40,14.0)) + + + + + 16 + POLYGON + POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) + 4326 + SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), + SDO_ORDINATE_ARRAY(0,0,0,10,10,10,10,0,0,0)) + + + + + 18 + POLYGON + POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) + SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1), SDO_ORDINATE_ARRAY(0, 0, 0, + 10, 10, 10, 10, 0, 0, 0, 2, 2, 2, 5, 5, 5, 5, 2, 2, 2)) + + 4326 + + + 19 + POLYGON + POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) + 4326 + SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), + SDO_ORDINATE_ARRAY(110,110,110,120,120,120,120,110,110,110)) + + + + + 20 + MULTIPOLYGON + MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) + 4326 + SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 9, 1003, 1), SDO_ORDINATE_ARRAY(10, 20, 30, + 40, 44, 50, 10, 20, 105, 100, 120, 140, 130, 134, 105, 100)) + + + + + 22 + MULTIPOLYGON + MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + 134, 105 100))) + + SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1, 21, 1003, 1), + SDO_ORDINATE_ARRAY(0, 0, 0, 50, 50, 50, 50, 0, 0, 0, 10, 10, 10, 20, 20, 20, 20, 10, 10, 10, 105, 100, 120, + 140, 130, 134, 105, 100)) + + 4326 + + + + + 25 + MULTIPOINT + MULTIPOINT(21 2, 25 5, 30 3) + 4326 + SDO_GEOMETRY(2005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2,25,5,30,3)) + + + 26 + MULTIPOINT + MULTIPOINT(21 2) + 4326 + SDO_GEOMETRY(2005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2)) + + + + + + + + + + diff --git a/hibernate-spatial/src/test/resources/test-sdo-geometry-data-set.xml b/hibernate-spatial/src/test/resources/test-sdo-geometry-data-set.xml new file mode 100644 index 0000000000..92b5e3277b --- /dev/null +++ b/hibernate-spatial/src/test/resources/test-sdo-geometry-data-set.xml @@ -0,0 +1,401 @@ + + + + + + + 1 + POINT + SDO_GEOMETRY(2001, 0, SDO_POINT_TYPE(10, 5, NULL), NULL, NULL) + POINT(10 5) + 4326 + + + 2 + POINT + SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(52.25, 2.53, NULL), NULL, NULL) + POINT(52.25 2.53) + 4326 + + + + 3 + POINT + SDO_GEOMETRY(3001, 31370, SDO_POINT_TYPE(150000, 200000, 500), NULL, NULL) + POINT(150000 200000 500) + 4326 + + + 4 + POINT + SDO_GEOMETRY(4401, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(10.0, 2.0, 1.0, 3.0)) + POINT(10.0 2.0 1.0 3.0) + 4326 + + + + 5 + LINESTRING + LINESTRING(10.0 5.0, 20.0 15.0) + 4326 + SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0)) + + + + 6 + LINESTRING + LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) + 4326 + SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, 15.0, 30.3, + 22.4, 10.0, 30.0 )) + + + + + 7 + LINESTRING + LINESTRING(10.0 5.0 0.0, 20.0 15.0 3.0) + SDO_GEOMETRY(3002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 0.0, 20.0, 15, 3.0 + )) + + 4326 + + + + 8 + LINESTRING + LINESTRING(10.0 5.0 0.0 0.0, 20.0 15.0 3.0 1.0) + 4326 + SDO_GEOMETRY(4402, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 0.0, 0.0, 20.0, + 15, 3.0, 1.0)) + + + + + 9 + LINESTRING + LINESTRING(10.0 5.0 1, 20.0 15.0 2, 30.3 22.4 5, 10 30.0 2) + 4326 + SDO_GEOMETRY(3002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 1.0,20.0, 15, 2.0, + 30.3, 22.4, 5.0, 10.0, 30.0, 2.0)) + + + + + 10 + LINESTRING + LINESTRING(10.0 5.0 1 1, 20.0 15.0 2 3, 30.3 22.4 5 10, 10 30.0 2 12) + 4326 + SDO_GEOMETRY(4402, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,1,1, 20.0, 15.0, 2, + 3, 30.3, 22.4, 5, 10, 10, 30.0, 2, 12)) + + + + + 11 + MULTILINESTRING + MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) + 4326 + SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,5,2,1), SDO_ORDINATE_ARRAY(10.0, 5.0, 20.0, + 15.0,25.0,30.0, 30.0,20.0)) + + + + + 12 + MULTILINESTRING + MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + + 4326 + SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,9,2,1), + SDO_ORDINATE_ARRAY(10.0,5.0,20.0,15.0,30.3,22.4,10,30.0,40.0,20.0,42.0,18.0,43.0,16.0,40,14.0)) + + + + + 13 + MULTILINESTRING + MULTILINESTRING((10.0 5.0 1.0, 20.0 15.0 2.0, 30.3 22.4 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 1.0, + 43.0 16.0 2.0, 40 14.0 3.0)) + + 4326 + SDO_GEOMETRY(3006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,13,2,1), + SDO_ORDINATE_ARRAY(10.0,5.0,1.0,20.0,15.0,2.0,30.3,22.4,1.0,10,30.0,1.0,40.0,20.0,0.0,42.0,18.0,1.0,43.0,16.0,2.0,40,14.0,3.0)) + + + + + 14 + MULTILINESTRING + MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 + 3.0, 42.0 18.0 1.0 4.0, 43.0 16.0 2.0 5.0, 40 14.0 3.0 6.0)) + + 4326 + SDO_GEOMETRY(4406, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,17,2,1), + SDO_ORDINATE_ARRAY(10.0,5.0,1.0,0.0,20.0,15.0,2.0,0.0,30.3,22.4,1.0,1.0,10,30.0,1.0,2.0,40.0,20.0,0.0,3.0,42.0,18.0,1.0,4.0,43.0,16.0,2.0,5.0,40,14.0,3.0,6.0)) + + + + + 15 + MULTILINESTRING + MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0)) + 4326 + SDO_GEOMETRY(4406, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1), + SDO_ORDINATE_ARRAY(10.0,5.0,1.0,0.0,20.0,15.0,2.0,0.0,30.3,22.4,1.0,1.0,10,30.0,1.0,2.0)) + + + + + + 16 + POLYGON + POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) + 4326 + SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), + SDO_ORDINATE_ARRAY(0,0,0,10,10,10,10,0,0,0)) + + + + + + 17 + POLYGON + POLYGON( (0 0 0, 0 10 1, 10 10 1, 10 0 1, 0 0 0) ) + 4326 + SDO_GEOMETRY(3003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), + SDO_ORDINATE_ARRAY(0,0,0,0,10,1,10,10,1,10,0,1,0,0,0)) + + + + 18 + POLYGON + POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) + SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1), SDO_ORDINATE_ARRAY(0, 0, 0, + 10, 10, 10, 10, 0, 0, 0, 2, 2, 2, 5, 5, 5, 5, 2, 2, 2)) + + 4326 + + + 19 + POLYGON + POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) + 4326 + SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), + SDO_ORDINATE_ARRAY(110,110,110,120,120,120,120,110,110,110)) + + + + + 20 + MULTIPOLYGON + MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) + 4326 + SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 9, 1003, 1), SDO_ORDINATE_ARRAY(10, 20, 30, + 40, 44, 50, 10, 20, 105, 100, 120, 140, 130, 134, 105, 100)) + + + + 21 + MULTIPOLYGON + MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) ) + + 4326 + SDO_GEOMETRY(3007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 13, 1003, 1), + SDO_ORDINATE_ARRAY(10,20,1,30,40,2,44,50,2,10,20,1,105,100,0,120,140,10,130,134,20,105,100,0)) + + + + 22 + MULTIPOLYGON + MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + 134, 105 100))) + + SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1, 21, 1003, 1), + SDO_ORDINATE_ARRAY(0, 0, 0, 50, 50, 50, 50, 0, 0, 0, 10, 10, 10, 20, 20, 20, 20, 10, 10, 10, 105, 100, 120, + 140, 130, 134, 105, 100)) + + 4326 + + + + + 25 + MULTIPOINT + MULTIPOINT(21 2, 25 5, 30 3) + 4326 + SDO_GEOMETRY(2005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2,25,5,30,3)) + + + 26 + MULTIPOINT + MULTIPOINT(21 2) + 4326 + SDO_GEOMETRY(2005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2)) + + + 27 + MULTIPOINT + MULTIPOINT(21 2 1, 25 5 2, 30 3 5) + 4326 + SDO_GEOMETRY(3005, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), SDO_ORDINATE_ARRAY(21,2,1,25,5,2,30,3,5)) + + + 28 + MULTIPOINT + MULTIPOINT(21 2 1 0, 25 5 2 4, 30 3 5 2) + 4326 + SDO_GEOMETRY(4405, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,1,1), + SDO_ORDINATE_ARRAY(21,2,1,0,25,5,2,4,30,3,5,2)) + + + + + + + + + +