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 f2be98ac64..cc9fda66d4 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 @@ -21,20 +21,7 @@ import org.hibernate.QueryTimeoutException; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.cfg.Environment; -import org.hibernate.dialect.BooleanDecoder; -import org.hibernate.dialect.DmlTargetColumnQualifierSupport; -import org.hibernate.dialect.DatabaseVersion; -import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.OracleBooleanJdbcType; -import org.hibernate.dialect.OracleJdbcHelper; -import org.hibernate.dialect.OracleJsonJdbcType; -import org.hibernate.dialect.OracleReflectionStructJdbcType; -import org.hibernate.dialect.OracleTypes; -import org.hibernate.dialect.OracleUserDefinedTypeExporter; -import org.hibernate.dialect.OracleXmlJdbcType; -import org.hibernate.dialect.Replacer; -import org.hibernate.dialect.RowLockStrategy; -import org.hibernate.dialect.TimeZoneSupport; +import org.hibernate.dialect.*; import org.hibernate.dialect.aggregate.AggregateSupport; import org.hibernate.dialect.aggregate.OracleAggregateSupport; import org.hibernate.dialect.function.CommonFunctionFactory; @@ -102,9 +89,10 @@ import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; -import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType; +import org.hibernate.type.descriptor.jdbc.OracleJsonArrayBlobJdbcType; +import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl; @@ -913,9 +901,11 @@ public class OracleLegacyDialect extends Dialect { if ( getVersion().isSameOrAfter( 21 ) ) { typeContributions.contributeJdbcType( OracleJsonJdbcType.INSTANCE ); + typeContributions.contributeJdbcType( OracleJsonArrayJdbcType.INSTANCE ); } else { typeContributions.contributeJdbcType( OracleJsonBlobJdbcType.INSTANCE ); + typeContributions.contributeJdbcType( OracleJsonArrayBlobJdbcType.INSTANCE ); } } 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 6c582c9109..623d20fc55 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -89,6 +89,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.NullJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType; +import org.hibernate.type.descriptor.jdbc.OracleJsonArrayBlobJdbcType; import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; @@ -976,9 +977,11 @@ public class OracleDialect extends Dialect { if ( getVersion().isSameOrAfter( 21 ) ) { typeContributions.contributeJdbcType( OracleJsonJdbcType.INSTANCE ); + typeContributions.contributeJdbcType( OracleJsonArrayJdbcType.INSTANCE ); } else { typeContributions.contributeJdbcType( OracleJsonBlobJdbcType.INSTANCE ); + typeContributions.contributeJdbcType( OracleJsonArrayBlobJdbcType.INSTANCE ); } if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonArrayJdbcType.java new file mode 100644 index 0000000000..c4652262aa --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonArrayJdbcType.java @@ -0,0 +1,37 @@ +/* + * 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.dialect; + +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.OracleJsonArrayBlobJdbcType; + +/** + * Specialized type mapping for {@code JSON} and the JSON SQL data type for Oracle. + * + * @author Christian Beikov + */ +public class OracleJsonArrayJdbcType extends OracleJsonArrayBlobJdbcType { + /** + * Singleton access + */ + public static final OracleJsonArrayJdbcType INSTANCE = new OracleJsonArrayJdbcType(); + + private OracleJsonArrayJdbcType() { + } + + @Override + public String toString() { + return "OracleJsonJdbcType"; + } + + @Override + public String getCheckCondition(String columnName, JavaType javaType, BasicValueConverter converter, Dialect dialect) { + // No check constraint necessary, because the JSON DDL type is already OSON encoded + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/aggregate/OracleAggregateSupport.java b/hibernate-core/src/main/java/org/hibernate/dialect/aggregate/OracleAggregateSupport.java index 8659659520..78c6a6f319 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/aggregate/OracleAggregateSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/aggregate/OracleAggregateSupport.java @@ -41,6 +41,7 @@ import org.hibernate.type.spi.TypeConfiguration; import static org.hibernate.type.SqlTypes.ARRAY; import static org.hibernate.type.SqlTypes.BIGINT; import static org.hibernate.type.SqlTypes.BINARY; +import static org.hibernate.type.SqlTypes.BIT; import static org.hibernate.type.SqlTypes.BLOB; import static org.hibernate.type.SqlTypes.BOOLEAN; import static org.hibernate.type.SqlTypes.CLOB; @@ -132,6 +133,11 @@ public class OracleAggregateSupport extends AggregateSupportImpl { parentPartExpression = aggregateParentReadExpression + ",'$."; } switch ( column.getTypeCode() ) { + case BIT: + return template.replace( + placeholder, + "decode(json_value(" + parentPartExpression + columnExpression + "'),'true',1,'false',0,null)" + ); case BOOLEAN: if ( column.getTypeName().toLowerCase( Locale.ROOT ).trim().startsWith( "number" ) ) { return template.replace( @@ -266,6 +272,8 @@ public class OracleAggregateSupport extends AggregateSupportImpl { switch ( jdbcType.getElementJdbcType().getDefaultSqlTypeCode() ) { case CLOB: return "(select json_arrayagg(to_clob(t.column_value)) from table(" + customWriteExpression + ") t)"; + case BIT: + return "decode(" + customWriteExpression + ",1,'true',0,'false',null)"; case BOOLEAN: final String elementTypeName = determineElementTypeName( column.toSize(), pluralType, typeConfiguration ); if ( elementTypeName.toLowerCase( Locale.ROOT ).trim().startsWith( "number" ) ) { @@ -274,6 +282,9 @@ public class OracleAggregateSupport extends AggregateSupportImpl { default: break; } + return customWriteExpression; + case BIT: + return "decode(" + customWriteExpression + ",1,'true',0,'false',null)"; case BOOLEAN: final String sqlTypeName = AbstractSqlAstTranslator.getSqlTypeName( column, typeConfiguration ); if ( sqlTypeName.toLowerCase( Locale.ROOT ).trim().startsWith( "number" ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonArrayBlobJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonArrayBlobJdbcType.java new file mode 100644 index 0000000000..12fe9aaff6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonArrayBlobJdbcType.java @@ -0,0 +1,109 @@ +/* + * 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.type.descriptor.jdbc; + +import org.hibernate.dialect.Dialect; +import org.hibernate.type.SqlTypes; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; +import org.hibernate.type.descriptor.java.JavaType; + +import java.nio.charset.StandardCharsets; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Specialized type mapping for {@code JSON} and the BLOB SQL data type for Oracle. + * + * @author Christian Beikov + */ +public class OracleJsonArrayBlobJdbcType extends JsonArrayJdbcType { + /** + * Singleton access + */ + public static final OracleJsonArrayBlobJdbcType INSTANCE = new OracleJsonArrayBlobJdbcType(); + + protected OracleJsonArrayBlobJdbcType() { + } + + @Override + public int getJdbcTypeCode() { + return SqlTypes.BLOB; + } + + @Override + public String toString() { + return "JsonArrayBlobJdbcType"; + } + + @Override + public String getCheckCondition(String columnName, JavaType javaType, BasicValueConverter converter, Dialect dialect) { + return columnName + " is json"; + } + + @Override + public ValueBinder getBinder(JavaType javaType) { + return new BasicBinder<>( javaType, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + final String json = OracleJsonArrayBlobJdbcType.this.toString( + value, + getJavaType(), + options + ); + st.setBytes( index, json.getBytes( StandardCharsets.UTF_8 ) ); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + final String json = OracleJsonArrayBlobJdbcType.this.toString( + value, + getJavaType(), + options + ); + st.setBytes( name, json.getBytes( StandardCharsets.UTF_8 ) ); + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaType javaType) { + return new BasicExtractor<>( javaType, this ) { + @Override + protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { + return fromString( rs.getBytes( paramIndex ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return fromString( statement.getBytes( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { + return fromString( statement.getBytes( name ), options ); + } + + private X fromString(byte[] json, WrapperOptions options) throws SQLException { + if ( json == null ) { + return null; + } + return OracleJsonArrayBlobJdbcType.this.fromString( + new String( json, StandardCharsets.UTF_8 ), + getJavaType(), + options + ); + } + }; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java index 3e34b24809..f4be54c890 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/OracleJsonBlobJdbcType.java @@ -26,16 +26,14 @@ import org.hibernate.type.descriptor.java.JavaType; * * @author Christian Beikov */ -public class OracleJsonBlobJdbcType implements AggregateJdbcType { +public class OracleJsonBlobJdbcType extends JsonJdbcType { /** * Singleton access */ public static final OracleJsonBlobJdbcType INSTANCE = new OracleJsonBlobJdbcType( null ); - private final EmbeddableMappingType embeddableMappingType; - protected OracleJsonBlobJdbcType(EmbeddableMappingType embeddableMappingType) { - this.embeddableMappingType = embeddableMappingType; + super( embeddableMappingType ); } @Override @@ -43,22 +41,11 @@ public class OracleJsonBlobJdbcType implements AggregateJdbcType { return SqlTypes.BLOB; } - @Override - public int getDefaultSqlTypeCode() { - return SqlTypes.JSON; - } - @Override public String toString() { return "JsonBlobJdbcType"; } - @Override - public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { - // No literal support for now - return null; - } - @Override public String getCheckCondition(String columnName, JavaType javaType, BasicValueConverter converter, Dialect dialect) { return columnName + " is json"; @@ -72,50 +59,6 @@ public class OracleJsonBlobJdbcType implements AggregateJdbcType { return new OracleJsonBlobJdbcType( mappingType ); } - @Override - public EmbeddableMappingType getEmbeddableMappingType() { - return embeddableMappingType; - } - - protected X fromString(String string, JavaType javaType, WrapperOptions options) throws SQLException { - if ( embeddableMappingType != null ) { - return JsonHelper.fromString( - embeddableMappingType, - string, - javaType.getJavaTypeClass() != Object[].class, - options - ); - } - return options.getSessionFactory().getFastSessionServices().getJsonFormatMapper().fromString( - string, - javaType, - options - ); - } - - @Override - public Object createJdbcValue(Object domainValue, WrapperOptions options) throws SQLException { - assert embeddableMappingType != null; - return JsonHelper.toString( embeddableMappingType, domainValue, options ); - } - - @Override - public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException { - assert embeddableMappingType != null; - return JsonHelper.fromString( embeddableMappingType, (String) rawJdbcValue, false, options ); - } - - protected String toString(X value, JavaType javaType, WrapperOptions options) { - if ( embeddableMappingType != null ) { - return JsonHelper.toString( embeddableMappingType, value, options ); - } - return options.getSessionFactory().getFastSessionServices().getJsonFormatMapper().toString( - value, - javaType, - options - ); - } - @Override public ValueBinder getBinder(JavaType javaType) { return new BasicBinder<>( javaType, this ) {