/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.spatial.dialect.oracle; import java.util.List; import org.hibernate.QueryException; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.spatial.SpatialAnalysis; import org.hibernate.spatial.SpatialRelation; import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; import org.hibernate.spatial.dialect.oracle.criterion.OracleSpatialAggregate; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.Type; /** * Helper class to register functions in the Oracle Spatial Dialects * Created by Karel Maesen, Geovise BVBA on 02/03/16. */ class OracleSpatialFunctions extends SpatialFunctionsRegistry { OracleSpatialFunctions(boolean strictOgc, OracleSDOSupport sdoSupport) { put( "dimension", new GetDimensionFunction() ); put( "geometrytype", new GetGeometryTypeFunction() ); put( "srid", new SDOObjectProperty( "SDO_SRID", StandardBasicTypes.INTEGER ) ); put( "envelope", new StandardSQLFunction( "SDO_GEOM.SDO_MBR" ) ); put( "astext", new AsTextFunction() ); put( "asbinary", new StandardSQLFunction( "SDO_UTIL.TO_WKBGEOMETRY", StandardBasicTypes.BINARY ) ); put( "isempty", new WrappedOGCFunction( "OGC_ISEMPTY", StandardBasicTypes.BOOLEAN, new boolean[] {true} ) ); put( "issimple", new WrappedOGCFunction( "OGC_ISSIMPLE", StandardBasicTypes.BOOLEAN, new boolean[] {true} ) ); put( "boundary", new WrappedOGCFunction( "OGC_BOUNDARY", new boolean[] {true} ) ); // put("area", new AreaFunction()); // Register functions for spatial relation constructs // section 2.1.1.2 put( "overlaps", new SpatialRelateFunction( "overlaps", SpatialRelation.OVERLAPS, strictOgc, sdoSupport ) ); put( "intersects", new SpatialRelateFunction( "intersects", SpatialRelation.INTERSECTS, strictOgc, sdoSupport ) ); put( "contains", new SpatialRelateFunction( "contains", SpatialRelation.CONTAINS, strictOgc, sdoSupport ) ); put( "crosses", new SpatialRelateFunction( "crosses", SpatialRelation.CROSSES, strictOgc, sdoSupport ) ); put( "disjoint", new SpatialRelateFunction( "disjoint", SpatialRelation.DISJOINT, strictOgc, sdoSupport ) ); put( "equals", new SpatialRelateFunction( "equals", SpatialRelation.EQUALS, strictOgc, sdoSupport ) ); put( "touches", new SpatialRelateFunction( "touches", SpatialRelation.TOUCHES, strictOgc, sdoSupport ) ); put( "within", new SpatialRelateFunction( "within", SpatialRelation.WITHIN, strictOgc, sdoSupport ) ); put( "relate", new WrappedOGCFunction( "OGC_RELATE", StandardBasicTypes.BOOLEAN, new boolean[] {true, true, false} ) ); // Register spatial analysis functions. // Section 2.1.1.3 put( "distance", new SpatialAnalysisFunction( "distance", StandardBasicTypes.DOUBLE, SpatialAnalysis.DISTANCE, strictOgc ) ); put( "buffer", new SpatialAnalysisFunction( "buffer", SpatialAnalysis.BUFFER, strictOgc ) ); put( "convexhull", new SpatialAnalysisFunction( "convexhull", SpatialAnalysis.CONVEXHULL, strictOgc ) ); put( "difference", new SpatialAnalysisFunction( "difference", SpatialAnalysis.DIFFERENCE, strictOgc ) ); put( "intersection", new SpatialAnalysisFunction( "intersection", SpatialAnalysis.INTERSECTION, strictOgc ) ); put( "symdifference", new SpatialAnalysisFunction( "symdifference", SpatialAnalysis.SYMDIFFERENCE, strictOgc ) ); put( "geomunion", new SpatialAnalysisFunction( "union", SpatialAnalysis.UNION, strictOgc ) ); // we rename OGC union to geomunion because union is a reserved SQL // keyword. (See also postgis documentation). // portable spatial aggregate functions put( "extent", new SpatialAggregationFunction( "extent", OracleSpatialAggregate.EXTENT, sdoSupport ) ); //other common functions put( "transform", new StandardSQLFunction( "SDO_CS.TRANSFORM" ) ); // Oracle specific Aggregate functions put( "centroid", new SpatialAggregationFunction( "extent", OracleSpatialAggregate.CENTROID, sdoSupport ) ); put( "concat_lines", new SpatialAggregationFunction( "extent", OracleSpatialAggregate.CONCAT_LINES, sdoSupport ) ); put( "aggr_convexhull", new SpatialAggregationFunction( "extent", OracleSpatialAggregate.CONVEXHULL, sdoSupport ) ); put( "aggr_union", new SpatialAggregationFunction( "extent", OracleSpatialAggregate.UNION, sdoSupport ) ); put( "lrs_concat", new SpatialAggregationFunction( "lrsconcat", OracleSpatialAggregate.LRS_CONCAT, sdoSupport ) ); } /** * Implementation of the OGC astext function for HQL. */ private static class AsTextFunction extends StandardSQLFunction { private AsTextFunction() { super( "astext", StandardBasicTypes.STRING ); } public String render(Type firstArgumentType, final List args, final SessionFactoryImplementor factory) { final StringBuilder buf = new StringBuilder(); 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(); } } static String getOGCSpatialAnalysisSQL(List args, int spatialAnalysisFunction) { boolean[] geomArgs; final 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 static StringBuffer wrapInSTGeometry(String geomColumn, StringBuffer toAdd) { return toAdd.append( "MDSYS.ST_GEOMETRY(" ).append( geomColumn ) .append( ")" ); } static String getNativeSpatialAnalysisSQL(List args, int spatialAnalysis) { return getOGCSpatialAnalysisSQL( args, spatialAnalysis ); } static String getSpatialAnalysisSQL(List args, int spatialAnalysisFunction) { return getOGCSpatialAnalysisSQL( args, spatialAnalysisFunction ); } /** * HQL Spatial relation function. */ private static class SpatialRelateFunction extends StandardSQLFunction { private final int relation; private final boolean isOGCStrict; private OracleSDOSupport sdo; private SpatialRelateFunction( final String name, final int relation, final boolean isOGCStrict, OracleSDOSupport sdo) { super( name, StandardBasicTypes.BOOLEAN ); this.relation = relation; this.isOGCStrict = isOGCStrict; this.sdo = sdo; } 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" ); } return isOGCStrict ? sdo.getOGCSpatialRelateSQL( (String) args.get( 0 ), (String) args.get( 1 ), this.relation ) : sdo.getNativeSpatialRelateSQL( (String) args.get( 0 ), (String) args.get( 1 ), this.relation ); } } private static class SpatialAnalysisFunction extends StandardSQLFunction { private final int analysis; private final boolean isOGCStrict; private SpatialAnalysisFunction(String name, Type returnType, int analysis, boolean isOGCStrict) { super( name, returnType ); this.analysis = analysis; this.isOGCStrict = isOGCStrict; } private SpatialAnalysisFunction(String name, int analysis, boolean isOGCStrict) { this( name, null, analysis, isOGCStrict ); } public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) { return isOGCStrict ? getSpatialAnalysisSQL( args, this.analysis ) : getNativeSpatialAnalysisSQL( args, analysis ); } } static class SpatialAggregationFunction extends StandardSQLFunction { private final int aggregation; private final OracleSDOSupport sdo; private SpatialAggregationFunction(String name, int aggregation, OracleSDOSupport dialect) { super( name ); this.aggregation = aggregation; this.sdo = dialect; } public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) { return sdo.getSpatialAggregateSQL( (String) args.get( 0 ), this.aggregation ); } } }