From 5bab35eb96deecef01810add17744cc39cddde8d Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 10 Oct 2023 08:43:11 +0200 Subject: [PATCH] HHH-17176 Map SDO_ORDINATE_ARRAY to BigDecimal[] for Oracle --- .../dialect/OracleLegacyDialect.java | 15 ++++ .../org/hibernate/dialect/OracleDialect.java | 16 ++++ .../test/type/OracleBigDecimalArrayTest.java | 89 +++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/OracleBigDecimalArrayTest.java diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java index 007c2efea9..c9e7a69192 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java @@ -90,6 +90,7 @@ import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl; +import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.type.JavaObjectType; import org.hibernate.type.NullType; @@ -99,6 +100,7 @@ import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor; import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType; @@ -720,6 +722,19 @@ public JdbcType resolveSqlTypeDescriptor( } } break; + case ARRAY: + if ( "MDSYS.SDO_ORDINATE_ARRAY".equals( columnTypeName ) ) { + final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); + if ( jdbcTypeConstructor != null ) { + return jdbcTypeConstructor.resolveType( + jdbcTypeRegistry.getTypeConfiguration(), + this, + jdbcTypeRegistry.getDescriptor( NUMERIC ), + ColumnTypeInformation.EMPTY + ); + } + } + break; case Types.NUMERIC: if ( scale == -127 ) { // For some reason, the Oracle JDBC driver reports FLOAT diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index cbfc967ca9..4feb919515 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -13,6 +13,7 @@ import java.sql.Types; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.util.Locale; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -75,6 +76,7 @@ import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.internal.OptionalTableUpdate; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl; +import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.type.JavaObjectType; import org.hibernate.type.NullType; @@ -83,6 +85,7 @@ import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor; import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType; import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; @@ -765,6 +768,19 @@ public JdbcType resolveSqlTypeDescriptor( } } break; + case ARRAY: + if ( "MDSYS.SDO_ORDINATE_ARRAY".equals( columnTypeName ) ) { + final JdbcTypeConstructor jdbcTypeConstructor = jdbcTypeRegistry.getConstructor( jdbcTypeCode ); + if ( jdbcTypeConstructor != null ) { + return jdbcTypeConstructor.resolveType( + jdbcTypeRegistry.getTypeConfiguration(), + this, + jdbcTypeRegistry.getDescriptor( NUMERIC ), + ColumnTypeInformation.EMPTY + ); + } + } + break; case NUMERIC: if ( precision > 8 // precision of 0 means something funny // For some reason, the Oracle JDBC driver reports diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/OracleBigDecimalArrayTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/OracleBigDecimalArrayTest.java new file mode 100644 index 0000000000..7d8df150a9 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/OracleBigDecimalArrayTest.java @@ -0,0 +1,89 @@ +/* + * 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.orm.test.type; + +import java.math.BigDecimal; +import java.util.List; + +import org.hibernate.dialect.OracleDialect; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import static org.assertj.core.api.Assertions.assertThat; + +@SessionFactory +@DomainModel(annotatedClasses = { OracleBigDecimalArrayTest.EntityWithBigDecimalArray.class }) +@RequiresDialect(OracleDialect.class) +@JiraKey("HHH-17176") +public class OracleBigDecimalArrayTest { + + private final BigDecimal[] array = new BigDecimal[] { BigDecimal.ONE, BigDecimal.TEN }; + + @BeforeEach + public void prepareData(SessionFactoryScope scope) { + scope.inTransaction( session -> { + session.persist( new OracleBigDecimalArrayTest.EntityWithBigDecimalArray( 1, array ) ); + } ); + } + + @AfterEach + public void cleanupData(SessionFactoryScope scope) { + scope.inTransaction( session -> { + session.createMutationQuery( "delete from EntityWithBigDecimalArray" ).executeUpdate(); + } ); + } + + @Test + public void testFind(SessionFactoryScope scope) { + scope.inTransaction( session -> { + EntityWithBigDecimalArray arrayHolder = session.find( EntityWithBigDecimalArray.class, 1 ); + assertThat( arrayHolder.bigDecimals ).isEqualTo( array ); + } ); + } + + @Test + public void testNative(SessionFactoryScope scope) { + scope.inTransaction( session -> { + List list = session.createNativeQuery( "select * from EntityWithBigDecimalArray" ) + .getResultList(); + assertThat( list.size() ).isEqualTo( 1 ); + assertThat( list.get( 0 )[0] ).isEqualTo( 1 ); + assertThat( list.get( 0 )[1] ).isEqualTo( array ); + } ); + } + + @Entity(name = "EntityWithBigDecimalArray") + @Table(name = "EntityWithBigDecimalArray") + public static class EntityWithBigDecimalArray { + @Id + private Integer id; + + @Column(columnDefinition = "MDSYS.SDO_ORDINATE_ARRAY") + private BigDecimal[] bigDecimals; + + public EntityWithBigDecimalArray() { + } + + public EntityWithBigDecimalArray(Integer id, BigDecimal[] bigDecimals) { + this.id = id; + this.bigDecimals = bigDecimals; + } + } + +}