HHH-14804 Upgrade MySQL spatial support (WIP)

This commit is contained in:
Karel Maesen 2021-11-01 18:06:18 +01:00
parent 0636f1de14
commit 9f70a6b100
18 changed files with 136 additions and 38 deletions

View File

@ -41,7 +41,7 @@ sourceSets.test.resources {
} }
tasks.test { tasks.test {
enabled = ['pgsql', 'cockroachdb', 'mariadb'].contains( project.db ) enabled = ['pgsql', 'cockroachdb', 'mariadb', 'mysql_docker', 'mysql_docker'].contains( project.db )
} }
tasks.test.include '**/*' tasks.test.include '**/*'

View File

@ -31,17 +31,23 @@ public class GeometryLiteralFormatter<T> implements JdbcLiteralFormatter<T> {
} }
@Override @Override
//todo -- clean this up
public void appendJdbcLiteral( public void appendJdbcLiteral(
SqlAppender appender, T value, Dialect dialect, WrapperOptions wrapperOptions) { SqlAppender appender, T value, Dialect dialect, WrapperOptions wrapperOptions) {
appender.appendSql( geomFromTextName ); appender.appendSql( geomFromTextName );
int srid = 0;
appender.appendSql( "('" ); appender.appendSql( "('" );
if ( javaType instanceof GeolatteGeometryJavaTypeDescriptor ) { if ( javaType instanceof GeolatteGeometryJavaTypeDescriptor ) {
appender.appendSql( Wkt.toWkt( (Geometry<?>) value, wktDialect ) ); appender.appendSql( Wkt.toWkt( (Geometry<?>) value, wktDialect ) );
srid = ( (Geometry<?>) value ).getSRID();
} }
else { else {
appender.appendSql( Wkt.toWkt( jts2Gl( value ), wktDialect ) ); appender.appendSql( Wkt.toWkt( jts2Gl( value ), wktDialect ) );
srid = ( (org.locationtech.jts.geom.Geometry) value ).getSRID();
} }
appender.appendSql( "')" ); appender.appendSql( "', " );
appender.appendSql( srid );
appender.appendSql(")");
} }
private <T> Geometry<?> jts2Gl(T value) { private <T> Geometry<?> jts2Gl(T value) {

View File

@ -14,11 +14,13 @@ import java.util.function.Function;
import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MariaDBDialect; import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.spatial.dialect.cockroachdb.CockroachDbContributor; import org.hibernate.spatial.dialect.cockroachdb.CockroachDbContributor;
import org.hibernate.spatial.dialect.mariadb.MariaDBDialectContributor; import org.hibernate.spatial.dialect.mariadb.MariaDBDialectContributor;
import org.hibernate.spatial.dialect.mysql.MySQLDialectContributor;
import org.hibernate.spatial.dialect.postgis.PostgisDialectContributor; import org.hibernate.spatial.dialect.postgis.PostgisDialectContributor;
class ContributorResolver { class ContributorResolver {
@ -32,6 +34,7 @@ class ContributorResolver {
CONTRIBUTOR_MAP.put( PostgreSQLDialect.class, PostgisDialectContributor::new ); CONTRIBUTOR_MAP.put( PostgreSQLDialect.class, PostgisDialectContributor::new );
CONTRIBUTOR_MAP.put( CockroachDialect.class, CockroachDbContributor::new ); CONTRIBUTOR_MAP.put( CockroachDialect.class, CockroachDbContributor::new );
CONTRIBUTOR_MAP.put( MariaDBDialect.class, MariaDBDialectContributor::new ); CONTRIBUTOR_MAP.put( MariaDBDialect.class, MariaDBDialectContributor::new );
CONTRIBUTOR_MAP.put( MySQLDialect.class, MySQLDialectContributor::new );
} }
private ContributorResolver() { private ContributorResolver() {

View File

@ -23,6 +23,7 @@ import org.hibernate.spatial.SpatialDialect;
* *
* @author Karel Maesen * @author Karel Maesen
*/ */
@Deprecated
public class MySQL56SpatialDialect extends MySQL55Dialect implements SpatialDialect { public class MySQL56SpatialDialect extends MySQL55Dialect implements SpatialDialect {
} }

View File

@ -14,5 +14,6 @@ import org.hibernate.spatial.SpatialDialect;
* *
* @author Karel Maesen, Geovise BVBA * @author Karel Maesen, Geovise BVBA
*/ */
@Deprecated
public class MySQL5SpatialDialect extends MySQL5Dialect implements SpatialDialect { public class MySQL5SpatialDialect extends MySQL5Dialect implements SpatialDialect {
} }

View File

@ -7,5 +7,45 @@
package org.hibernate.spatial.dialect.mysql; package org.hibernate.spatial.dialect.mysql;
public class MySQLDialectContributor { import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.spatial.GeolatteGeometryType;
import org.hibernate.spatial.HSMessageLogger;
import org.hibernate.spatial.JTSGeometryType;
import org.hibernate.spatial.KeyedSqmFunctionDescriptors;
import org.hibernate.spatial.contributor.ContributorImplementor;
import org.hibernate.spatial.dialect.mariadb.MariaDBSqmFunctionDescriptors;
public class MySQLDialectContributor implements ContributorImplementor {
private final ServiceRegistry serviceRegistry;
public MySQLDialectContributor(ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
@Override
public void contributeTypes(TypeContributions typeContributions) {
HSMessageLogger.LOGGER.typeContributions( this.getClass().getCanonicalName() );
typeContributions.contributeType( new GeolatteGeometryType( MySQLGeometryType.INSTANCE ) );
typeContributions.contributeType( new JTSGeometryType( MySQLGeometryType.INSTANCE ) );
}
@Override
public void contributeFunctions(FunctionContributions functionContributions) {
HSMessageLogger.LOGGER.functionContributions( this.getClass().getCanonicalName() );
final KeyedSqmFunctionDescriptors mysqlFunctions = new MySqlSqmFunctionDescriptors( functionContributions );
final SqmFunctionRegistry functionRegistry = functionContributions.getFunctionRegistry();
mysqlFunctions.asMap().forEach( (key, desc) -> {
functionRegistry.register( key.getName(), desc );
key.getAltName().ifPresent( altName -> functionRegistry.registerAlternateKey( altName, key.getName() ) );
} );
}
@Override
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
} }

View File

@ -13,6 +13,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import org.hibernate.spatial.GeometryLiteralFormatter;
import org.hibernate.type.SqlTypes; import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.ValueExtractor;
@ -20,6 +21,7 @@ import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.BasicBinder; import org.hibernate.type.descriptor.jdbc.BasicBinder;
import org.hibernate.type.descriptor.jdbc.BasicExtractor; import org.hibernate.type.descriptor.jdbc.BasicExtractor;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.geolatte.geom.ByteBuffer; import org.geolatte.geom.ByteBuffer;
@ -28,6 +30,7 @@ import org.geolatte.geom.Geometry;
import org.geolatte.geom.codec.Wkb; import org.geolatte.geom.codec.Wkb;
import org.geolatte.geom.codec.WkbDecoder; import org.geolatte.geom.codec.WkbDecoder;
import org.geolatte.geom.codec.WkbEncoder; import org.geolatte.geom.codec.WkbEncoder;
import org.geolatte.geom.codec.Wkt;
/** /**
* Descriptor for MySQL Geometries. * Descriptor for MySQL Geometries.
@ -51,6 +54,11 @@ public class MySQLGeometryType implements JdbcType {
return SqlTypes.GEOMETRY; return SqlTypes.GEOMETRY;
} }
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {
return new GeometryLiteralFormatter<T>( javaTypeDescriptor, Wkt.Dialect.SFA_1_1_0, "ST_GeomFromText" );
}
@Override @Override
public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) { public <X> ValueBinder<X> getBinder(final JavaType<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) { return new BasicBinder<X>( javaTypeDescriptor, this ) {
@ -98,7 +106,7 @@ public class MySQLGeometryType implements JdbcType {
}; };
} }
private Geometry toGeometry(byte[] bytes) { public Geometry toGeometry(byte[] bytes) {
if ( bytes == null ) { if ( bytes == null ) {
return null; return null;
} }

View File

@ -14,6 +14,7 @@ import org.hibernate.spatial.SpatialDialect;
* *
* @author Karel Maesen, Boni Gopalan * @author Karel Maesen, Boni Gopalan
*/ */
@Deprecated
public class MySQLSpatialDialect extends MySQLDialect implements SpatialDialect { public class MySQLSpatialDialect extends MySQLDialect implements SpatialDialect {
} }

View File

@ -0,0 +1,17 @@
/*
* 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.mysql;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.spatial.BaseSqmFunctionDescriptors;
public class MySqlSqmFunctionDescriptors extends BaseSqmFunctionDescriptors {
public MySqlSqmFunctionDescriptors(FunctionContributions functionContributions) {
super( functionContributions );
}
}

View File

@ -53,7 +53,7 @@ public class PGGeometryType implements JdbcType {
@Override @Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) { public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {
return new GeometryLiteralFormatter<T>( javaTypeDescriptor, Wkt.Dialect.POSTGIS_EWKT_1, "ST_GeomFromEwkt" ); return new GeometryLiteralFormatter<T>( javaTypeDescriptor, Wkt.Dialect.SFA_1_1_0, "ST_GeomFromText" );
} }
private PGGeometryType(Wkb.Dialect dialect) { private PGGeometryType(Wkb.Dialect dialect) {

View File

@ -11,8 +11,12 @@ import org.geolatte.geom.Geometry;
public interface GeomCodec { public interface GeomCodec {
/**
* Decode value returned by JDBC Driver for Geometry as Geolatte Geometry
* @param in value returned by JDBC Driver
* @return the decoded Geoemtry
*/
Geometry<?> toGeometry(Object in); Geometry<?> toGeometry(Object in);
Object fromGeometry(Geometry<?> in);
} }

View File

@ -10,6 +10,7 @@ package org.hibernate.spatial.testing;
import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MariaDBDialect; import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.testing.orm.junit.DialectFeatureCheck; import org.hibernate.testing.orm.junit.DialectFeatureCheck;
@ -26,6 +27,7 @@ public class IsSupportedBySpatial implements DialectFeatureCheck {
public boolean apply(Dialect dialect) { public boolean apply(Dialect dialect) {
return dialect instanceof PostgreSQLDialect return dialect instanceof PostgreSQLDialect
|| dialect instanceof CockroachDialect || dialect instanceof CockroachDialect
|| dialect instanceof MySQLDialect
|| dialect instanceof MariaDBDialect; || dialect instanceof MariaDBDialect;
} }
} }

View File

@ -10,6 +10,7 @@ package org.hibernate.spatial.testing;
import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MariaDBDialect; import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.spatial.SpatialDialect; import org.hibernate.spatial.SpatialDialect;
import org.hibernate.spatial.testing.datareader.TestSupport; import org.hibernate.spatial.testing.datareader.TestSupport;
@ -57,6 +58,10 @@ public class TestSupportFactories {
return CockroachDBTestSupport.class; return CockroachDBTestSupport.class;
} }
if ( MySQLDialect.class.isAssignableFrom( dialect.getClass() ) ) {
return dialect.getVersion() >= 800 ? MySQL8TestSupport.class : MySQL56TestSupport.class;
}
if ( "org.hibernate.spatial.dialect.h2geodb.GeoDBDialect".equals( canonicalName ) ) { if ( "org.hibernate.spatial.dialect.h2geodb.GeoDBDialect".equals( canonicalName ) ) {
return GeoDBTestSupport.class; return GeoDBTestSupport.class;
} }
@ -66,19 +71,7 @@ public class TestSupportFactories {
if ( "org.hibernate.spatial.dialect.sqlserver.SqlServer2012SpatialDialect".equals( canonicalName ) ) { if ( "org.hibernate.spatial.dialect.sqlserver.SqlServer2012SpatialDialect".equals( canonicalName ) ) {
return SQLServerTestSupport.class; return SQLServerTestSupport.class;
} }
if ( "org.hibernate.spatial.dialect.mysql.MySQLSpatialDialect".equals( canonicalName ) ||
"org.hibernate.spatial.dialect.mysql.MySQL5InnoDBSpatialDialect".equals( canonicalName ) ) {
return MySQLTestSupport.class;
}
if ( "org.hibernate.spatial.dialect.mysql.MySQL8SpatialDialect".equals( canonicalName ) ) {
return MySQL8TestSupport.class;
}
if ( "org.hibernate.spatial.dialect.mysql.MySQL56SpatialDialect".equals( canonicalName ) ||
"org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect".equals( canonicalName ) ) {
return MySQL56TestSupport.class;
}
if ( "org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect".equals( canonicalName ) || if ( "org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect".equals( canonicalName ) ||
"org.hibernate.spatial.dialect.oracle.OracleSpatialSDO10gDialect".equals( canonicalName ) ) { "org.hibernate.spatial.dialect.oracle.OracleSpatialSDO10gDialect".equals( canonicalName ) ) {
return OracleSDOTestSupport.class; return OracleSDOTestSupport.class;

View File

@ -46,11 +46,6 @@ public class CockroachDBTestSupport extends TestSupport {
public Geometry<?> toGeometry(Object in) { public Geometry<?> toGeometry(Object in) {
return PGGeometryType.INSTANCE_WKB_2.toGeometry( in ); return PGGeometryType.INSTANCE_WKB_2.toGeometry( in );
} }
@Override
public Object fromGeometry(Geometry<?> in) {
return Wkt.toWkt( in, Wkt.Dialect.POSTGIS_EWKT_1 );
}
}; };
} }

View File

@ -53,10 +53,6 @@ public class MariaDBTestSupport extends TestSupport {
return MariaDBGeometryType.INSTANCE.toGeometry( (byte[])in ); return MariaDBGeometryType.INSTANCE.toGeometry( (byte[])in );
} }
@Override
public Object fromGeometry(Geometry<?> in) {
return Wkt.toWkt( in, Wkt.Dialect.MYSQL_WKT );
}
}; };
} }
} }

View File

@ -8,10 +8,20 @@
package org.hibernate.spatial.testing.dialects.mysql; package org.hibernate.spatial.testing.dialects.mysql;
import java.util.Map;
import org.hibernate.spatial.CommonSpatialFunction;
import org.hibernate.spatial.GeomCodec;
import org.hibernate.spatial.dialect.mariadb.MariaDBGeometryType;
import org.hibernate.spatial.dialect.mysql.MySQLGeometryType;
import org.hibernate.spatial.testing.AbstractExpectationsFactory; import org.hibernate.spatial.testing.AbstractExpectationsFactory;
import org.hibernate.spatial.testing.JTSGeometryEquality; import org.hibernate.spatial.testing.JTSGeometryEquality;
import org.hibernate.spatial.testing.datareader.TestData; import org.hibernate.spatial.testing.datareader.TestData;
import org.hibernate.spatial.testing.datareader.TestSupport; import org.hibernate.spatial.testing.datareader.TestSupport;
import org.hibernate.spatial.testing.dialects.NativeSQLTemplates;
import org.hibernate.spatial.testing.dialects.PredicateRegexes;
import org.geolatte.geom.Geometry;
/** /**
* @author Karel Maesen, Geovise BVBA * @author Karel Maesen, Geovise BVBA
@ -24,4 +34,30 @@ public class MySQLTestSupport extends TestSupport {
return TestData.fromFile( "mysql/test-mysql-functions-data-set.xml" ); return TestData.fromFile( "mysql/test-mysql-functions-data-set.xml" );
} }
@Override
public NativeSQLTemplates templates() {
return new MySqlNativeSqlTemplates();
}
@Override
public PredicateRegexes predicateRegexes() {
return new PredicateRegexes( "st_geomfromtext" );
}
@Override
public Map<CommonSpatialFunction, String> hqlOverrides() {
return super.hqlOverrides();
}
@Override
public GeomCodec codec() {
return new GeomCodec() {
@Override
public Geometry<?> toGeometry(Object in) {
return MySQLGeometryType.INSTANCE.toGeometry( (byte[])in );
}
};
}
} }

View File

@ -36,7 +36,7 @@ public class PostgisTestSupport extends TestSupport {
} }
@Override @Override
public PredicateRegexes predicateRegexes(){ return new PredicateRegexes("st_geomfromewkt");} public PredicateRegexes predicateRegexes(){ return new PredicateRegexes("st_geomfromtext");}
//TODO put this in its own class (analogous to NativeSQLTemplates) //TODO put this in its own class (analogous to NativeSQLTemplates)
@Override @Override
@ -62,11 +62,6 @@ public class PostgisTestSupport extends TestSupport {
public Geometry<?> toGeometry(Object in) { public Geometry<?> toGeometry(Object in) {
return PGGeometryType.INSTANCE_WKB_2.toGeometry( in ); return PGGeometryType.INSTANCE_WKB_2.toGeometry( in );
} }
@Override
public Object fromGeometry(Geometry<?> in) {
return Wkt.toWkt( in, Wkt.Dialect.POSTGIS_EWKT_1 );
}
}; };
} }

View File

@ -72,13 +72,13 @@ hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFa
#hibernate.connection.username hibern8 #hibernate.connection.username hibern8
#hibernate.connection.password hibern8Pass #hibernate.connection.password hibern8Pass
## ##
## MySQL 5 dialects ## MySQL
## ##
#hibernate.dialect org.hibernate.spatial.dialect.mysql.MySQLSpatialDialect #hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.connection.driver_class com.mysql.jdbc.Driver #hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql://hibernate-spatial-integration.cctaez8ywvn2.eu-west-1.rds.amazonaws.com/test #hibernate.connection.url jdbc:mysql://localhost/hibernate_orm_test?allowPublicKeyRetrieval=true
#hibernate.connection.username hbs #hibernate.connection.username hibernate_orm_test
#hibernate.connection.password #hibernate.connection.password hibernate_orm_test
## ##
## MySQL 5 InnoDDB dialect ## MySQL 5 InnoDDB dialect
## ##