From dfe0bcbbca4f3c6363f092a9436a3c71a82477fb Mon Sep 17 00:00:00 2001 From: Jonathan Bregler Date: Thu, 12 Jul 2018 12:32:16 +0200 Subject: [PATCH] HHH-12798: Fix for nested spatial functions on SAP HANA --- .../dialect/hana/HANASpatialFunction.java | 88 ++++++++++--------- .../hana/TestHANASpatialFunctions.java | 25 ++++++ .../hana/HANAExpectationsFactory.java | 55 +++++++++--- 3 files changed, 115 insertions(+), 53 deletions(-) diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialFunction.java index 5fbab410fb..5d6911deae 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialFunction.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialFunction.java @@ -57,50 +57,44 @@ public class HANASpatialFunction extends StandardSQLFunction { if ( arguments.size() == 0 ) { return getName() + "()"; } - else { - final StringBuilder buf = new StringBuilder(); - int firstArgumentIndex; - if ( staticFunction ) { - // Add function call - buf.append( getName() ); - firstArgumentIndex = 0; - } - else { - // If the first argument is an expression, e.g. a nested function, strip the .ST_AsEWKB() suffix - buf.append( stripEWKBSuffix( arguments.get( 0 ) ) ); - // Add function call - buf.append( "." ).append( getName() ); - - firstArgumentIndex = 1; - } - - buf.append( '(' ); - - // Add function arguments - for ( int i = firstArgumentIndex; i < arguments.size(); i++ ) { - final Object argument = arguments.get( i ); - // Check if first argument needs to be parsed from EWKB. This is the case if the first argument is a - // parameter that is set as EWKB or if it's a nested function call. - final boolean parseFromWKB = ( isGeometryArgument( i ) && "?".equals( argument ) ); - if ( parseFromWKB ) { - buf.append( "ST_GeomFromEWKB(" ); - } - buf.append( stripEWKBSuffix( argument ) ); - if ( parseFromWKB ) { - buf.append( ")" ); - } - if ( i < arguments.size() - 1 ) { - buf.append( ", " ); - } - } - buf.append( ')' ); - // If it doesn't specify an explicit type, assume it's a geometry - if ( this.getType() == null ) { - buf.append( AS_EWKB_SUFFIX ); - } - return buf.toString(); + final StringBuilder buf = new StringBuilder(); + int firstArgumentIndex; + if ( this.staticFunction ) { + // Add function call + buf.append( getName() ); + firstArgumentIndex = 0; } + else { + // If the first argument is an expression, e.g. a nested function, strip the .ST_AsEWKB() suffix + Object argument = arguments.get( 0 ); + final boolean parseFromWKB = ( "?".equals( argument ) ); + appendArgument( argument, parseFromWKB, buf ); + // Add function call + buf.append( "." ).append( getName() ); + + firstArgumentIndex = 1; + } + + buf.append( '(' ); + + // Add function arguments + for ( int i = firstArgumentIndex; i < arguments.size(); i++ ) { + final Object argument = arguments.get( i ); + // Check if first argument needs to be parsed from EWKB. This is the case if the first argument is a + // parameter that is set as EWKB or if it's a nested function call. + final boolean parseFromWKB = ( isGeometryArgument( i ) && "?".equals( argument ) ); + appendArgument( argument, parseFromWKB, buf ); + if ( i < arguments.size() - 1 ) { + buf.append( ", " ); + } + } + buf.append( ')' ); + // If it doesn't specify an explicit type, assume it's a geometry + if ( this.getType() == null ) { + buf.append( AS_EWKB_SUFFIX ); + } + return buf.toString(); } private Object stripEWKBSuffix(Object argument) { @@ -115,4 +109,14 @@ public class HANASpatialFunction extends StandardSQLFunction { private boolean isGeometryArgument(int idx) { return this.argumentIsGeometryTypeMask.size() > idx && this.argumentIsGeometryTypeMask.get( idx ); } + + private void appendArgument(Object argument, boolean parseFromWKB, StringBuilder buf) { + if ( parseFromWKB ) { + buf.append( "ST_GeomFromEWKB(" ); + } + buf.append( stripEWKBSuffix( argument ) ); + if ( parseFromWKB ) { + buf.append( ")" ); + } + } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java index 5d1e8befde..f1d9c9270b 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java @@ -1018,6 +1018,31 @@ public class TestHANASpatialFunctions extends TestSpatialFunctions { retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } + @Test + public void test_nestedfunction_on_jts() throws SQLException { + nestedfunction( JTS ); + } + + @Test + public void test_nestedfunction_on_geolatte() throws SQLException { + nestedfunction( GEOLATTE ); + } + + public void nestedfunction(String pckg) throws SQLException { + Map dbexpected = hanaExpectationsFactory.getNestedFunctionInner( expectationsFactory.getTestPolygon() ); + String hql = format( + "SELECT id, geom FROM org.hibernate.spatial.integration.%s.GeomEntity g where dwithin(geom, srid(:filter, 0), 1) = true", + pckg ); + Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); + retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); + + dbexpected = hanaExpectationsFactory.getNestedFunctionOuter( expectationsFactory.getTestPolygon() ); + hql = format( + "SELECT id, geom FROM org.hibernate.spatial.integration.%s.GeomEntity g where dwithin(:filter, srid(geom, 0), 1) = true", + pckg ); + retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); + } + private String getGeometryTypeFromPackage(String pckg) { switch ( pckg ) { case GEOLATTE: diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java index 4601a5a7e3..5b7a26ab5e 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java @@ -925,7 +925,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_SnapToGrid() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the expected startpoint of all testsuite-suite geometries. * @@ -939,7 +939,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { private NativeSQLStatement createNativeStartPointStatement() { return createNativeSQLStatement( "select id, t.geom.ST_StartPoint() from GeomTest t where t.geom.ST_GeometryType() = 'ST_LineString'" ); } - + /** * Returns the expected aggregated union of all testsuite-suite geometries. * @@ -953,7 +953,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { private NativeSQLStatement createNativeUnionAggrStatement() { return createNativeSQLStatement( "select cast(count(*) as int), ST_UnionAggr(t.geom) from GeomTest t" ); } - + /** * Returns the x coordinate of all testsuite-suite geometries. * @@ -969,7 +969,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_X() from GeomTest t where t.geom.ST_GeometryType() in ('ST_Point') and t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the maximum x coordinate of all testsuite-suite geometries. * @@ -985,7 +985,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_XMax() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the minimum x coordinate of all testsuite-suite geometries. * @@ -1001,7 +1001,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_XMin() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the y coordinate of all testsuite-suite geometries. * @@ -1017,7 +1017,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_Y() from GeomTest t where t.geom.ST_GeometryType() in ('ST_Point') and t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the maximum y coordinate of all testsuite-suite geometries. * @@ -1033,7 +1033,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_YMax() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the minimum y coordinate of all testsuite-suite geometries. * @@ -1049,7 +1049,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_YMin() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the z coordinate of all testsuite-suite geometries. * @@ -1065,7 +1065,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_Z() from GeomTest t where t.geom.ST_GeometryType() in ('ST_Point') and t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the maximum z coordinate of all testsuite-suite geometries. * @@ -1081,7 +1081,7 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_ZMax() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid() ); } - + /** * Returns the minimum z coordinate of all testsuite-suite geometries. * @@ -1097,4 +1097,37 @@ public class HANAExpectationsFactory extends AbstractExpectationsFactory { "select t.id, t.geom.ST_ZMin() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid() ); } + + /** + * Returns the result of a nested function call with a parameter inside the inner function + * + * @return map of identifier, geometry + * @throws SQLException + */ + public Map getNestedFunctionInner(Geometry geom) throws SQLException { + return retrieveExpected( createNativeNestedFunctionInnerStatement( geom ), GEOMETRY ); + } + + private NativeSQLStatement createNativeNestedFunctionInnerStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom from GeomTest t where t.geom.ST_WithinDistance(ST_GeomFromText(?, " + getTestSrid() + + ").ST_SRID(0), 1) = 1", + geom.toText() ); + } + + /** + * Returns the result of a nested function call with a parameter inside the outer function + * + * @return map of identifier, geometry + * @throws SQLException + */ + public Map getNestedFunctionOuter(Geometry geom) throws SQLException { + return retrieveExpected( createNativeNestedFunctionOuterStatement( geom ), GEOMETRY ); + } + + private NativeSQLStatement createNativeNestedFunctionOuterStatement(Geometry geom) { + return createNativeSQLStatementAllWKTParams( + "select t.id, t.geom from GeomTest t where ST_GeomFromText(?, " + getTestSrid() + ").ST_WithinDistance(geom.ST_SRID(0), 1) = 1", + geom.toText() ); + } }