From ffc43aadc44cc81d4802983e8684eb5fb230c99e Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Tue, 16 Mar 2021 23:18:08 +0100 Subject: [PATCH] HHH-14454 Add SpatialDialect for CockroachDB --- .../chapters/query/spatial/Spatial.adoc | 78 ++++--- gradle/databases.gradle | 9 + gradle/libraries.gradle | 2 +- .../CockroachDB202SpatialDialect.java | 45 ++++ .../CockroachDBSpatialSupport.java | 46 ++++ .../CockroachSpatialDialectTrait.java | 77 +++++++ .../dialect/cockroachdb/package-info.java | 13 ++ .../postgis/PGGeometryTypeDescriptor.java | 19 +- .../dialect/postgis/PostgisFunctions.java | 4 +- .../dialect/postgis/PostgisNoSQLMM.java | 2 +- .../dialect/postgis/PostgisPG82Dialect.java | 2 +- .../dialect/postgis/PostgisPG91Dialect.java | 2 +- .../dialect/postgis/PostgisPG92Dialect.java | 2 +- .../dialect/postgis/PostgisPG93Dialect.java | 2 +- .../dialect/postgis/PostgisPG94Dialect.java | 2 +- .../dialect/postgis/PostgisPG95Dialect.java | 2 +- .../dialect/postgis/PostgisPG9Dialect.java | 2 +- .../dialect/postgis/PostgisSupport.java | 18 +- .../dialect/postgis/PostgisUnmarshalTest.java | 2 +- .../integration/TestSpatialFunctions.java | 2 +- .../spatial/testing/TestSupportFactories.java | 7 + .../CockroachDBExpectationsFactory.java | 28 +++ .../cockroachdb/CockroachDBTestSupport.java | 45 ++++ .../postgis/PostgisExpectationsFactory.java | 3 +- .../resources/cockroachdb/functions-test.xml | 64 ++++++ .../resources/cockroachdb/test-data-set.xml | 213 ++++++++++++++++++ 26 files changed, 629 insertions(+), 62 deletions(-) create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java create mode 100644 hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml create mode 100644 hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc index e348fec902..578048ac4d 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc @@ -86,42 +86,42 @@ relevant section. :no: icon:times[role="red"] [[spatial-configuration-dialect-features]] .Hibernate Spatial dialect function support -[cols=",,,,,,," |options="header",] +[cols=",,,,,,,," |options="header",] |================================ -|Function | Description | PostgresSQL | Oracle 10g/11g | MySQL | SQLServer | GeoDB (H2) | DB2 -|Basic functions on Geometry | | | | | | | -|`int dimension(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`String geometrytype(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`int srid(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`Geometry envelope(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`String astext(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`byte[] asbinary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean isempty(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean issimple(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`Geometry boundary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|Functions for testing Spatial Relations between geometric objects | | | | | | | -|`boolean equals(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean disjoint(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean intersects(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean touches(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean crosses(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean within(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean contains(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean overlaps(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean relate(Geometry, Geometry, String)` | SFS §2.1.1.2 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|Functions that support Spatial Analysis | | | | | | | -|`double distance(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|`Geometry buffer(Geometry, double)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|`Geometry convexhull(Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry intersection(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry geomunion(Geometry, Geometry)` | SFS §2.1.1.3 (renamed from union) | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry difference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry symdifference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|Common non-SFS functions | | | | | | | -|`boolean dwithin(Geometry, Geometry, double)` | Returns true if the geometries are within the specified distance of one another | {yes} | {yes} | {no} | {no} | {yes} | {yes} -|`Geometry transform(Geometry, int)` | Returns a new geometry with its coordinates transformed to the SRID referenced by the integer parameter | {yes} | {yes} | {no} | {no} | {no} | {no} -|Spatial aggregate Functions | | | | | | | -|`Geometry extent(Geometry)` | Returns a bounding box that bounds the set of returned geometries | {yes} | {yes} | {no} | {no} | {no} | {no} +|Function | Description | PostgresSQL | Oracle 10g/11g | MySQL | SQLServer | GeoDB (H2) | DB2 | CockroachDB +|Basic functions on Geometry | | | | | | | | +|`int dimension(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`String geometrytype(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`int srid(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`Geometry envelope(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`String astext(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`byte[] asbinary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean isempty(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean issimple(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`Geometry boundary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|Functions for testing Spatial Relations between geometric objects | | | | | | | | +|`boolean equals(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean disjoint(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean intersects(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean touches(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean crosses(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean within(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean contains(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean overlaps(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean relate(Geometry, Geometry, String)` | SFS §2.1.1.2 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|Functions that support Spatial Analysis | | | | | | | | +|`double distance(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|`Geometry buffer(Geometry, double)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|`Geometry convexhull(Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {no} +|`Geometry intersection(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|`Geometry geomunion(Geometry, Geometry)` | SFS §2.1.1.3 (renamed from union) | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|`Geometry difference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|`Geometry symdifference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|Common non-SFS functions | | | | | | | | +|`boolean dwithin(Geometry, Geometry, double)` | Returns true if the geometries are within the specified distance of one another | {yes} | {yes} | {no} | {no} | {yes} | {yes} | {yes} +|`Geometry transform(Geometry, int)` | Returns a new geometry with its coordinates transformed to the SRID referenced by the integer parameter | {yes} | {yes} | {no} | {no} | {no} | {no} | {yes} +|Spatial aggregate Functions | | | | | | | | +|`Geometry extent(Geometry)` | Returns a bounding box that bounds the set of returned geometries | {yes} | {yes} | {no} | {no} | {no} | {no} | {yes} |================================ ^(1)^ Argument Geometries need to have the same dimensionality. @@ -191,6 +191,14 @@ The dialect `SqlServer2008Dialect` supports the `GEOMETRY` type in SQL Server 20 The `GEOGRAPHY` type is not currently supported. ==== +CockroachDB:: +The dialect `CockroachDB202SpatialDialect` support the `GEOMETRY` type in CockroachDB v20.2 and later. + +[NOTE] +==== +The `GEOGRAPHY` type is not currently supported. +==== + GeoDB (H2):: The `GeoDBDialect` supports the GeoDB a spatial extension of the H2 in-memory database. [NOTE] diff --git a/gradle/databases.gradle b/gradle/databases.gradle index 1dbf3471d9..d8367c89a0 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -189,5 +189,14 @@ ext { // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com 'jdbc.url' : 'jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' ], + cockroachdb_spatial : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.cockroachdb.CockroachDB202SpatialDialect', + // CockroachDB uses the same pgwire protocol as PostgreSQL, so the driver is the same. + 'jdbc.driver': 'org.postgresql.Driver', + 'jdbc.user' : 'root', + 'jdbc.pass' : '', + // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com + 'jdbc.url' : 'jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' + ] ] } diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index f8e03e908b..730a6193e7 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -29,7 +29,7 @@ ext { assertjVersion = '3.14.0' - geolatteVersion = '1.6.1' + geolatteVersion = '1.8.0' // Wildfly version targeted by module ZIP; Arquillian/Shrinkwrap versions used for CDI testing and testing the module ZIP wildflyVersion = '17.0.1.Final' diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java new file mode 100644 index 0000000000..d5ba27617a --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java @@ -0,0 +1,45 @@ +/* + * 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 . + */ + +package org.hibernate.spatial.dialect.cockroachdb; + +import java.util.Map; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.dialect.CockroachDB201Dialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.dialect.postgis.PGGeometryTypeDescriptor; + +/** + * An @{code SpatialDialect} for CockroachDB 20.2 and later. CockroachDB's spatial features where introduced in + * that version. + */ +public class CockroachDB202SpatialDialect extends CockroachDB201Dialect implements CockroachSpatialDialectTrait { + + + public CockroachDB202SpatialDialect() { + super(); + registerColumnType( + PGGeometryTypeDescriptor.INSTANCE_WKB_2.getSqlType(), + "GEOMETRY" + ); + for ( Map.Entry entry : functionsToRegister() ) { + registerFunction( entry.getKey(), entry.getValue() ); + } + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + super.contributeTypes( + typeContributions, + serviceRegistry + ); + delegateContributeTypes( typeContributions, serviceRegistry ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java new file mode 100644 index 0000000000..7389598d5e --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java @@ -0,0 +1,46 @@ +/* + * 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 . + */ + +package org.hibernate.spatial.dialect.cockroachdb; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.GeolatteGeometryJavaTypeDescriptor; +import org.hibernate.spatial.GeolatteGeometryType; +import org.hibernate.spatial.JTSGeometryJavaTypeDescriptor; +import org.hibernate.spatial.JTSGeometryType; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.dialect.postgis.PGGeometryTypeDescriptor; +import org.hibernate.spatial.dialect.postgis.PostgisFunctions; +import org.hibernate.spatial.dialect.postgis.PostgisSupport; + +public class CockroachDBSpatialSupport extends PostgisSupport implements SpatialDialect { + + CockroachDBSpatialSupport() { + super( new CockroachDBSpatialFunctions() ); + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + typeContributions.contributeType( new GeolatteGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_2 ) ); + typeContributions.contributeType( new JTSGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_2 ) ); + + typeContributions.contributeJavaTypeDescriptor( GeolatteGeometryJavaTypeDescriptor.INSTANCE ); + typeContributions.contributeJavaTypeDescriptor( JTSGeometryJavaTypeDescriptor.INSTANCE ); + } + +} + +class CockroachDBSpatialFunctions extends PostgisFunctions { + + CockroachDBSpatialFunctions() { + super(); + this.functionMap.remove( "geomunion" ); + } + +} + diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java new file mode 100644 index 0000000000..17ffb69b7e --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java @@ -0,0 +1,77 @@ +/* + * 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 . + */ + +package org.hibernate.spatial.dialect.cockroachdb; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.SpatialFunction; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; + +public interface CockroachSpatialDialectTrait extends SpatialDialect { + + CockroachDBSpatialSupport DELEGATE = new CockroachDBSpatialSupport(); + + default SpatialFunctionsRegistry functionsToRegister() { + return DELEGATE.functionsToRegister(); + + } + + default String getSpatialRelateSQL(String columnName, int spatialRelation) { + return DELEGATE.getSpatialRelateSQL( columnName, spatialRelation ); + } + + default void delegateContributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + DELEGATE.contributeTypes( typeContributions, serviceRegistry ); + } + + /** + * Returns the SQL fragment for the SQL WHERE-expression when parsing + * org.hibernate.spatial.criterion.SpatialFilterExpressions + * into prepared statements. + * + * @param columnName The name of the geometry-typed column to which the filter is + * be applied + * + * @return Rhe SQL fragment for the {@code SpatialFilterExpression} + */ + default String getSpatialFilterExpression(String columnName) { + return DELEGATE.getSpatialFilterExpression( columnName ); + } + + @Override + default String getSpatialAggregateSQL(String columnName, int aggregation) { + return DELEGATE.getSpatialAggregateSQL( columnName, aggregation ); + } + + @Override + default String getDWithinSQL(String columnName) { + return DELEGATE.getDWithinSQL( columnName ); + } + + @Override + default String getHavingSridSQL(String columnName) { + return DELEGATE.getHavingSridSQL( columnName ); + } + + @Override + default String getIsEmptySQL(String columnName, boolean isEmpty) { + return DELEGATE.getIsEmptySQL( columnName, isEmpty ); + } + + @Override + default boolean supportsFiltering() { + return DELEGATE.supportsFiltering(); + } + + @Override + default boolean supports(SpatialFunction function) { + return DELEGATE.supports( function ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java new file mode 100644 index 0000000000..94f58799a8 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java @@ -0,0 +1,13 @@ +/* + * 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 . + */ + +/** + * {@code SpatialDialect}s for CockroachDB + */ +package org.hibernate.spatial.dialect.cockroachdb; + + diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java index b221c5c314..af4ebc86b3 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java @@ -39,12 +39,18 @@ import org.postgresql.util.PGobject; public class PGGeometryTypeDescriptor implements SqlTypeDescriptor { - /** - * An instance of this class - */ - public static final PGGeometryTypeDescriptor INSTANCE = new PGGeometryTypeDescriptor(); + final private Wkb.Dialect wkbDialect; - public static Geometry toGeometry(Object object) { + // Type descriptor instance using EWKB v1 (postgis versions < 2.2.2) + public static final PGGeometryTypeDescriptor INSTANCE_WKB_1 = new PGGeometryTypeDescriptor( Wkb.Dialect.POSTGIS_EWKB_1); + // Type descriptor instance using EWKB v2 (postgis versions >= 2.2.2, see: https://trac.osgeo.org/postgis/ticket/3181) + public static final PGGeometryTypeDescriptor INSTANCE_WKB_2 = new PGGeometryTypeDescriptor(Wkb.Dialect.POSTGIS_EWKB_2); + + private PGGeometryTypeDescriptor(Wkb.Dialect dialect) { + wkbDialect = dialect; + } + + public Geometry toGeometry(Object object) { if ( object == null ) { return null; } @@ -55,9 +61,8 @@ public class PGGeometryTypeDescriptor implements SqlTypeDescriptor { if ( pgValue.startsWith( "00" ) || pgValue.startsWith( "01" ) ) { //we have a WKB because this pgValue starts with the bit-order byte buffer = ByteBuffer.from( pgValue ); - final WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.POSTGIS_EWKB_1 ); + final WkbDecoder decoder = Wkb.newDecoder( wkbDialect ); return decoder.decode( buffer ); - } else { return parseWkt( pgValue ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java index 77d3c79f86..baec7a21f9 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java @@ -24,9 +24,9 @@ import org.hibernate.type.Type; *

* Created by Karel Maesen, Geovise BVBA on 29/10/16. */ -class PostgisFunctions extends SpatialFunctionsRegistry { +public class PostgisFunctions extends SpatialFunctionsRegistry { - PostgisFunctions() { + public PostgisFunctions() { put( "dimension", new StandardSQLFunction( diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java index 339177756b..ab3cf5ce60 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java @@ -23,7 +23,7 @@ public class PostgisNoSQLMM extends PostgisDialect { public PostgisNoSQLMM() { registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java index 2189f53017..f1fa67c919 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG82Dialect extends PostgreSQL82Dialect implements SpatialDi public PostgisPG82Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java index 25eccc44e9..ca871af1df 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG91Dialect extends PostgreSQL91Dialect implements SpatialDi public PostgisPG91Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java index 0006fc2876..c94d2e9021 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG92Dialect extends PostgreSQL92Dialect implements SpatialDi public PostgisPG92Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java index 30a8c2b8ee..f8ac29a1a0 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG93Dialect extends PostgreSQL93Dialect implements SpatialDi public PostgisPG93Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java index 2fe8ff00cf..c267cf6d8c 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG94Dialect extends PostgreSQL94Dialect implements SpatialDi public PostgisPG94Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java index 84f3c04fb0..a99bd40d83 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java @@ -30,7 +30,7 @@ public class PostgisPG95Dialect extends PostgreSQL95Dialect implements SpatialDi public PostgisPG95Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java index daceb78ecf..9182f947f0 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG9Dialect extends PostgreSQL9Dialect implements SpatialDial public PostgisPG9Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java index 1b34d0346a..126a86e072 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java @@ -18,24 +18,32 @@ import org.hibernate.spatial.SpatialAggregate; import org.hibernate.spatial.SpatialDialect; import org.hibernate.spatial.SpatialFunction; import org.hibernate.spatial.SpatialRelation; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; /** * Created by Karel Maesen, Geovise BVBA on 29/10/16. */ public class PostgisSupport implements SpatialDialect, Serializable { + private final SpatialFunctionsRegistry postgisFunctions; - private PostgisFunctions postgisFunctions = new PostgisFunctions(); + public PostgisSupport(SpatialFunctionsRegistry functions) { + postgisFunctions = functions; + } - void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { - typeContributions.contributeType( new GeolatteGeometryType( PGGeometryTypeDescriptor.INSTANCE ) ); - typeContributions.contributeType( new JTSGeometryType( PGGeometryTypeDescriptor.INSTANCE ) ); + public PostgisSupport() { + postgisFunctions = new PostgisFunctions(); + } + + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + typeContributions.contributeType( new GeolatteGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_1 ) ); + typeContributions.contributeType( new JTSGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_1 ) ); typeContributions.contributeJavaTypeDescriptor( GeolatteGeometryJavaTypeDescriptor.INSTANCE ); typeContributions.contributeJavaTypeDescriptor( JTSGeometryJavaTypeDescriptor.INSTANCE ); } - public PostgisFunctions functionsToRegister() { + public SpatialFunctionsRegistry functionsToRegister() { return postgisFunctions; } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java index 811ef756d9..06536eaf3e 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java @@ -69,7 +69,7 @@ public class PostgisUnmarshalTest { public void testCase(String pgValue, Geometry expected) throws SQLException { PGobject pgo = new PGobject(); pgo.setValue( pgValue ); - Geometry received = PGGeometryTypeDescriptor.toGeometry( pgo ); + Geometry received = PGGeometryTypeDescriptor.INSTANCE_WKB_1.toGeometry( pgo ); assertEquals( String.format( "Failure on %s", pgValue ), expected, received ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java index cccabd0419..aea9561b48 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java @@ -522,7 +522,7 @@ public class TestSpatialFunctions extends SpatialFunctionalTestCase { } public void convexhull(String pckg) throws SQLException { - if ( !isSupportedByDialect( SpatialFunction.convexhull ) ) { + if ( !isSupportedByDialect( SpatialFunction.convexhull ) || !isSupportedByDialect( SpatialFunction.geomunion )) { return; } Map dbexpected = expectationsFactory.getConvexHull( expectationsFactory.getTestPolygon() ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java index 7ed693440b..d71e78b4f2 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java @@ -7,9 +7,11 @@ package org.hibernate.spatial.testing; +import org.hibernate.dialect.CockroachDB192Dialect; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.PostgreSQL82Dialect; import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.testing.dialects.cockroachdb.CockroachDBTestSupport; import org.hibernate.spatial.testing.dialects.db2.DB2TestSupport; import org.hibernate.spatial.testing.dialects.h2geodb.GeoDBTestSupport; import org.hibernate.spatial.testing.dialects.hana.HANATestSupport; @@ -42,6 +44,11 @@ public class TestSupportFactories { //this test works because all postgis dialects ultimately derive of the Postgresql82Dialect return PostgisTestSupport.class; } + + if ( ( dialect instanceof SpatialDialect ) && CockroachDB192Dialect.class.isAssignableFrom( dialect.getClass() ) ){ + return CockroachDBTestSupport.class; + } + if ( "org.hibernate.spatial.dialect.h2geodb.GeoDBDialect".equals( canonicalName ) ) { return GeoDBTestSupport.class; } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java new file mode 100644 index 0000000000..c09f31dc04 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java @@ -0,0 +1,28 @@ +/* + * 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 . + */ + +package org.hibernate.spatial.testing.dialects.cockroachdb; + +import org.hibernate.spatial.dialect.postgis.PGGeometryTypeDescriptor; +import org.hibernate.spatial.testing.DataSourceUtils; +import org.hibernate.spatial.testing.dialects.postgis.PostgisExpectationsFactory; + +import org.geolatte.geom.jts.JTS; +import org.locationtech.jts.geom.Geometry; + +public class CockroachDBExpectationsFactory extends PostgisExpectationsFactory { + + public CockroachDBExpectationsFactory(DataSourceUtils utils) { + super( utils ); + } + + @Override + protected Geometry decode(Object object) { + org.geolatte.geom.Geometry geometry = PGGeometryTypeDescriptor.INSTANCE_WKB_2.toGeometry( object ); + return JTS.to( geometry ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java new file mode 100644 index 0000000000..629b668efb --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java @@ -0,0 +1,45 @@ +/* + * 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 . + */ + +package org.hibernate.spatial.testing.dialects.cockroachdb; + +import org.hibernate.spatial.integration.TestGeolatteSpatialPredicates; +import org.hibernate.spatial.integration.TestJTSSpatialPredicates; +import org.hibernate.spatial.integration.TestSpatialFunctions; +import org.hibernate.spatial.integration.TestSpatialRestrictions; +import org.hibernate.spatial.testing.AbstractExpectationsFactory; +import org.hibernate.spatial.testing.DataSourceUtils; +import org.hibernate.spatial.testing.SQLExpressionTemplate; +import org.hibernate.spatial.testing.TestData; +import org.hibernate.spatial.testing.TestSupport; +import org.hibernate.spatial.testing.dialects.postgis.PostgisExpressionTemplate; + +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; + +public class CockroachDBTestSupport extends TestSupport { + @Override + public TestData createTestData(BaseCoreFunctionalTestCase testcase) { + Class testcaseClass = testcase.getClass(); + if ( ( testcaseClass == TestSpatialFunctions.class ) || + ( testcaseClass == TestSpatialRestrictions.class ) || + ( testcaseClass == TestJTSSpatialPredicates.class ) || + ( testcaseClass == TestGeolatteSpatialPredicates.class ) ) { + return TestData.fromFile( "cockroachdb/functions-test.xml" ); + } + return TestData.fromFile( "cockroachdb/test-data-set.xml" ); + } + + @Override + public AbstractExpectationsFactory createExpectationsFactory(DataSourceUtils dataSourceUtils) { + return new CockroachDBExpectationsFactory( dataSourceUtils ); + } + + @Override + public SQLExpressionTemplate getSQLExpressionTemplate() { + return new PostgisExpressionTemplate(); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java index 21b4b9b8d0..1df480fb99 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java @@ -238,10 +238,9 @@ public class PostgisExpectationsFactory extends AbstractExpectationsFactory { ); } - //remove redundancy with toGeometry function in PGGeometryTypeDescriptor @Override protected Geometry decode(Object object) { - org.geolatte.geom.Geometry geometry = PGGeometryTypeDescriptor.toGeometry( object ); + org.geolatte.geom.Geometry geometry = PGGeometryTypeDescriptor.INSTANCE_WKB_1.toGeometry( object ); return JTS.to( geometry ); } diff --git a/hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml b/hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml new file mode 100644 index 0000000000..407cd75b8b --- /dev/null +++ b/hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml @@ -0,0 +1,64 @@ + + + + + 1 + POINT + SRID=4326;POINT(10 5) + + + 2 + POINT + SRID=4326;POINT(79 79) + + + 3 + POINT + SRID=4326;POINT(50 50) + + + 4 + POINT + SRID=4326;POINT(10 20) + + + 5 + POINT + SRID=4326;POINT(-4 -5) + + + + 6 + LINESTRING + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) + + + + + + 9 + MULTILINESTRING + SRID=4326;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)) + + + + + 10 + POLYGON + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) + + + + 11 + MULTIPOLYGON + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((15 10, 12 14, 13 13, 15 10)) ) + + + + diff --git a/hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml b/hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml new file mode 100644 index 0000000000..7f928daf9e --- /dev/null +++ b/hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml @@ -0,0 +1,213 @@ + + + + 1 + POINT + POINT(10 5) + + + 2 + POINT + SRID=4326;POINT(52.25 2.53) + + + + 3 + POINT + SRID=31370;POINT(150000 200000) + + + + 4 + LINESTRING + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) + + + + 5 + LINESTRING + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) + + + + + 6 + MULTILINESTRING + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) + + + + 7 + MULTILINESTRING + SRID=4326;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)) + + + + + 8 + POLYGON + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) + + + + 9 + POLYGON + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) + + + + 10 + POLYGON + SRID=4326;POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) + + + + 11 + MULTIPOLYGON + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) + + + + + 12 + MULTIPOLYGON + SRID=4326;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)) ) + + + + + + 13 + MULTIPOINT + SRID=4326;MULTIPOINT(21 2, 25 5, 30 3) + + + + 14 + MULTIPOINT + SRID=4326;MULTIPOINT(21 2) + + + + 15 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3)) + + + + 16 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0))) + + + + 17 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, + 2 2, 1 2, + 1 1))) + + + + + 18 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), + ((105 100, + 120 140, 130 134, 105 100)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) + + + + + 19 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), POINT EMPTY, LINESTRING(4 2, 5 3)) + + + + 20 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING EMPTY, LINESTRING(4 2, 5 3)) + + + + 21 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), GEOMETRYCOLLECTION EMPTY, LINESTRING(4 2, 5 3)) + + + + 22 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), POLYGON EMPTY, LINESTRING(4 2, 5 3)) + + + + 23 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTILINESTRING EMPTY, LINESTRING(4 2, 5 3)) + + + + 24 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTIPOINT EMPTY, LINESTRING(4 2, 5 3)) + + + + 25 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTIPOLYGON EMPTY, LINESTRING(4 2, 5 3)) + + + + 26 + POINT + POINT EMPTY + + + + 27 + LINESTRING + LINESTRING EMPTY + + + + 28 + POLYGON + POLYGON EMPTY + + + + 29 + MULTIPOINT + MULTIPOINT EMPTY + + + + 30 + MULTILINESTRING + MULTILINESTRING EMPTY + + + + 31 + MULTIPOLYGON + MULTIPOLYGON EMPTY + + + + 32 + GEOMETRYCOLLECTION + GEOMETRYCOLLECTION EMPTY + + +