HHH-18799 Add XML aggregate support for Oracle
This commit is contained in:
parent
6d1b9c475a
commit
eeba7edf32
|
@ -53,7 +53,9 @@ import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
|
|||
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.AggregateColumn;
|
||||
import org.hibernate.mapping.CheckConstraint;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UserDefinedType;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
|
@ -81,6 +83,7 @@ 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.tool.schema.internal.StandardTableExporter;
|
||||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
import org.hibernate.type.JavaObjectType;
|
||||
import org.hibernate.type.NullType;
|
||||
|
@ -172,6 +175,17 @@ public class OracleLegacyDialect extends Dialect {
|
|||
private final OracleUserDefinedTypeExporter userDefinedTypeExporter = new OracleUserDefinedTypeExporter( this );
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
private final SequenceSupport oracleSequenceSupport = OracleSequenceSupport.getInstance(this);
|
||||
private final StandardTableExporter oracleTableExporter = new StandardTableExporter( this ) {
|
||||
@Override
|
||||
protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
|
||||
final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
|
||||
if ( dialect.getVersion().isBefore( 23, 6 ) && jdbcType.isXml() ) {
|
||||
// ORA-00600 when selecting XML columns that have a check constraint was fixed in 23.6
|
||||
return;
|
||||
}
|
||||
super.applyAggregateColumnCheck( buf, aggregateColumn );
|
||||
}
|
||||
};
|
||||
|
||||
public OracleLegacyDialect() {
|
||||
this( DatabaseVersion.make( 8, 0 ) );
|
||||
|
@ -503,6 +517,8 @@ public class OracleLegacyDialect extends Dialect {
|
|||
return "to_timestamp_tz(?1,'YYYY-MM-DD HH24:MI:SS.FF9 TZR')";
|
||||
}
|
||||
break;
|
||||
case XML:
|
||||
return "xmlparse(document ?1)";
|
||||
}
|
||||
return super.castPattern(from, to);
|
||||
}
|
||||
|
@ -1042,6 +1058,11 @@ public class OracleLegacyDialect extends Dialect {
|
|||
return oracleSequenceSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exporter<Table> getTableExporter() {
|
||||
return oracleTableExporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySequencesString() {
|
||||
return "select * from all_sequences";
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.sql.SQLException;
|
|||
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
@ -31,6 +32,11 @@ public class H2JsonJdbcType extends JsonJdbcType {
|
|||
super( embeddableMappingType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCode() {
|
||||
return SqlTypes.VARBINARY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "H2JsonJdbcType";
|
||||
|
|
|
@ -253,6 +253,7 @@ public class OracleArrayJdbcType extends ArrayJdbcType implements SqlTypedJdbcTy
|
|||
userDefinedArrayType.setArraySqlTypeCode( getDdlTypeCode() );
|
||||
userDefinedArrayType.setElementTypeName( elementTypeName );
|
||||
userDefinedArrayType.setElementSqlTypeCode( elementJdbcType.getDefaultSqlTypeCode() );
|
||||
userDefinedArrayType.setElementDdlTypeCode( elementJdbcType.getDdlTypeCode() );
|
||||
userDefinedArrayType.setArrayLength( columnSize.getArrayLength() == null ? 127 : columnSize.getArrayLength() );
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
|||
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
|
||||
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.mapping.AggregateColumn;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UserDefinedType;
|
||||
import org.hibernate.mapping.CheckConstraint;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
|
@ -78,6 +80,7 @@ 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.tool.schema.internal.StandardTableExporter;
|
||||
import org.hibernate.tool.schema.spi.Exporter;
|
||||
import org.hibernate.type.JavaObjectType;
|
||||
import org.hibernate.type.NullType;
|
||||
|
@ -181,6 +184,17 @@ public class OracleDialect extends Dialect {
|
|||
private final OracleUserDefinedTypeExporter userDefinedTypeExporter = new OracleUserDefinedTypeExporter( this );
|
||||
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
|
||||
private final SequenceSupport oracleSequenceSupport = OracleSequenceSupport.getInstance(this);
|
||||
private final StandardTableExporter oracleTableExporter = new StandardTableExporter( this ) {
|
||||
@Override
|
||||
protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
|
||||
final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
|
||||
if ( dialect.getVersion().isBefore( 23, 6 ) && jdbcType.isXml() ) {
|
||||
// ORA-00600 when selecting XML columns that have a check constraint was fixed in 23.6
|
||||
return;
|
||||
}
|
||||
super.applyAggregateColumnCheck( buf, aggregateColumn );
|
||||
}
|
||||
};
|
||||
|
||||
// Is it an Autonomous Database Cloud Service?
|
||||
protected final boolean autonomous;
|
||||
|
@ -589,6 +603,8 @@ public class OracleDialect extends Dialect {
|
|||
return "to_timestamp_tz(?1,'YYYY-MM-DD HH24:MI:SS.FF9 TZR')";
|
||||
}
|
||||
break;
|
||||
case XML:
|
||||
return "xmlparse(document ?1)";
|
||||
}
|
||||
return super.castPattern(from, to);
|
||||
}
|
||||
|
@ -988,6 +1004,7 @@ public class OracleDialect extends Dialect {
|
|||
typeContributions.contributeJdbcType( OracleBooleanJdbcType.INSTANCE );
|
||||
}
|
||||
typeContributions.contributeJdbcType( OracleXmlJdbcType.INSTANCE );
|
||||
typeContributions.contributeJdbcTypeConstructor( OracleXmlArrayJdbcTypeConstructor.INSTANCE );
|
||||
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
|
||||
typeContributions.contributeJdbcType( OracleJdbcHelper.getStructJdbcType( serviceRegistry ) );
|
||||
}
|
||||
|
@ -1132,6 +1149,11 @@ public class OracleDialect extends Dialect {
|
|||
return oracleSequenceSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exporter<Table> getTableExporter() {
|
||||
return oracleTableExporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySequencesString() {
|
||||
return "select * from all_sequences";
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
@ -20,6 +21,11 @@ public class OracleJsonArrayJdbcType extends OracleJsonArrayBlobJdbcType {
|
|||
super( elementJdbcType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.JSON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OracleJsonJdbcType";
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.relational.QualifiedName;
|
||||
|
@ -16,18 +14,16 @@ import org.hibernate.tool.schema.internal.StandardUserDefinedTypeExporter;
|
|||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
import static java.sql.Types.BOOLEAN;
|
||||
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.DATE;
|
||||
import static org.hibernate.type.SqlTypes.INTEGER;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.TABLE;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.UUID;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
|
||||
|
@ -61,11 +57,13 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
|
|||
}
|
||||
final int arrayLength = userDefinedType.getArrayLength();
|
||||
final Integer elementSqlTypeCode = userDefinedType.getElementSqlTypeCode();
|
||||
final Integer elementDdlTypeCode = userDefinedType.getElementDdlTypeCode();
|
||||
final String jsonTypeName = metadata.getDatabase().getTypeConfiguration().getDdlTypeRegistry().getTypeName(
|
||||
SqlTypes.JSON,
|
||||
dialect
|
||||
);
|
||||
final String valueExpression = determineValueExpression( "t.value", elementSqlTypeCode, elementType );
|
||||
final String valueExpression = determineValueExpression( "t.value", elementSqlTypeCode, elementDdlTypeCode, elementType );
|
||||
final String jsonElementType = determineJsonElementType( elementSqlTypeCode, elementDdlTypeCode, elementType );
|
||||
return new String[] {
|
||||
"create or replace type " + arrayTypeName + " as varying array(" + arrayLength + ") of " + elementType,
|
||||
"create or replace function " + arrayTypeName + "_cmp(a in " + arrayTypeName +
|
||||
|
@ -266,7 +264,7 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
|
|||
"res " + arrayTypeName + ":=" + arrayTypeName + "(); begin " +
|
||||
"if arr is null then return null; end if; " +
|
||||
"select " + valueExpression + " bulk collect into res " +
|
||||
"from json_table(arr,'$[*]' columns (value path '$')) t; " +
|
||||
"from json_table(arr,'$[*]' columns (value " + jsonElementType + " path '$')) t; " +
|
||||
"return res; " +
|
||||
"end;"
|
||||
};
|
||||
|
@ -332,17 +330,8 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
|
|||
return dialect.getVersion().isSameOrAfter( 23 );
|
||||
}
|
||||
|
||||
private String determineValueExpression(String expression, int elementSqlTypeCode, String elementType) {
|
||||
private String determineValueExpression(String expression, int elementSqlTypeCode, Integer elementDdlTypeCode, String elementType) {
|
||||
switch ( elementSqlTypeCode ) {
|
||||
case BOOLEAN:
|
||||
if ( elementType.toLowerCase( Locale.ROOT ).trim().startsWith( "number" ) ) {
|
||||
return "decode(" + expression + ",'true',1,'false',0,null)";
|
||||
}
|
||||
case TINYINT:
|
||||
case SMALLINT:
|
||||
case INTEGER:
|
||||
case BIGINT:
|
||||
return "cast(" + expression + " as " + elementType + ")";
|
||||
case DATE:
|
||||
return "to_date(" + expression + ",'YYYY-MM-DD')";
|
||||
case TIME:
|
||||
|
@ -355,14 +344,47 @@ public class OracleUserDefinedTypeExporter extends StandardUserDefinedTypeExport
|
|||
case BINARY:
|
||||
case VARBINARY:
|
||||
case LONG32VARBINARY:
|
||||
return "hextoraw(" + expression + ")";
|
||||
case BLOB:
|
||||
return "xmlcast(xmlcdata(" + expression + ") as " + elementType + ")";
|
||||
case UUID:
|
||||
return "hextoraw(replace(" + expression + ",'-',''))";
|
||||
case BIT:
|
||||
return "decode(" + expression + ",'true',1,'false',0,null)";
|
||||
case BOOLEAN:
|
||||
if ( SqlTypes.isNumericType( elementDdlTypeCode ) ) {
|
||||
return "decode(" + expression + ",'true',1,'false',0,null)";
|
||||
}
|
||||
// Fall-through intended
|
||||
default:
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
private String determineJsonElementType(Integer elementSqlTypeCode, Integer elementDdlTypeCode, String elementType) {
|
||||
switch ( elementSqlTypeCode ) {
|
||||
case BINARY:
|
||||
case VARBINARY:
|
||||
case LONG32VARBINARY:
|
||||
case BLOB:
|
||||
return "clob";
|
||||
case BOOLEAN:
|
||||
if ( !SqlTypes.isNumericType( elementDdlTypeCode ) ) {
|
||||
return elementType;
|
||||
}
|
||||
// Fall-through intended
|
||||
case BIT:
|
||||
case DATE:
|
||||
case TIME:
|
||||
case TIMESTAMP:
|
||||
case TIMESTAMP_WITH_TIMEZONE:
|
||||
case TIMESTAMP_UTC:
|
||||
case UUID:
|
||||
return "varchar2(4000)";
|
||||
default:
|
||||
return elementType;
|
||||
}
|
||||
}
|
||||
|
||||
protected String createOrReplaceConcatFunction(String arrayTypeName) {
|
||||
// Since Oracle has no builtin concat function for varrays and doesn't support varargs,
|
||||
// we have to create a function with a fixed amount of arguments with default that fits "most" cases.
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.XmlArrayJdbcType;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class OracleXmlArrayJdbcType extends XmlArrayJdbcType {
|
||||
|
||||
public OracleXmlArrayJdbcType(JdbcType elementJdbcType) {
|
||||
super( elementJdbcType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
|
||||
// Seems the Oracle JDBC driver doesn't support `setNull(index, Types.SQLXML)`
|
||||
// but it seems that the following works fine
|
||||
return new XmlArrayBinder<>( javaType, this ) {
|
||||
@Override
|
||||
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
|
||||
st.setNull( index, Types.VARCHAR );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
|
||||
st.setNull( name, Types.VARCHAR );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Factory for {@link OracleXmlArrayJdbcType}.
|
||||
*/
|
||||
public class OracleXmlArrayJdbcTypeConstructor implements JdbcTypeConstructor {
|
||||
|
||||
public static final OracleXmlArrayJdbcTypeConstructor INSTANCE = new OracleXmlArrayJdbcTypeConstructor();
|
||||
|
||||
@Override
|
||||
public JdbcType resolveType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
BasicType<?> elementType,
|
||||
ColumnTypeInformation columnTypeInformation) {
|
||||
return resolveType( typeConfiguration, dialect, elementType.getJdbcType(), columnTypeInformation );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType resolveType(
|
||||
TypeConfiguration typeConfiguration,
|
||||
Dialect dialect,
|
||||
JdbcType elementType,
|
||||
ColumnTypeInformation columnTypeInformation) {
|
||||
return new OracleXmlArrayJdbcType( elementType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultSqlTypeCode() {
|
||||
return SqlTypes.XML_ARRAY;
|
||||
}
|
||||
}
|
|
@ -91,6 +91,14 @@ public class XmlHelper {
|
|||
sb.append( '&' );
|
||||
i += 4;
|
||||
}
|
||||
else if ( i + 5 < end
|
||||
&& string.charAt( i + 2 ) == 'p'
|
||||
&& string.charAt( i + 3 ) == 'o'
|
||||
&& string.charAt( i + 4 ) == 's'
|
||||
&& string.charAt( i + 5 ) == ';' ) {
|
||||
sb.append( '\'' );
|
||||
i += 5;
|
||||
}
|
||||
break OUTER;
|
||||
case 'g':
|
||||
if ( string.charAt( i + 2 ) == 't' && string.charAt( i + 3 ) == ';' ) {
|
||||
|
@ -274,7 +282,14 @@ public class XmlHelper {
|
|||
if ( NULL_TAG.equals( string ) ) {
|
||||
return null;
|
||||
}
|
||||
if ( !string.startsWith( START_TAG ) || !string.endsWith( END_TAG ) ) {
|
||||
int contentEnd = string.length() - 1;
|
||||
while ( contentEnd >= 0 ) {
|
||||
if ( !Character.isWhitespace( string.charAt( contentEnd ) ) ) {
|
||||
break;
|
||||
}
|
||||
contentEnd--;
|
||||
}
|
||||
if ( !string.startsWith( START_TAG ) || !string.regionMatches( contentEnd - END_TAG.length()+ 1, END_TAG, 0, END_TAG.length() ) ) {
|
||||
throw new IllegalArgumentException( "XML not properly formatted: " + string );
|
||||
}
|
||||
int end;
|
||||
|
@ -289,7 +304,7 @@ public class XmlHelper {
|
|||
array = new Object[embeddableMappingType.getJdbcValueCount() + ( embeddableMappingType.isPolymorphic() ? 1 : 0 )];
|
||||
end = fromString( embeddableMappingType, string, returnEmbeddable, options, array, START_TAG.length() );
|
||||
}
|
||||
assert end + END_TAG.length() == string.length();
|
||||
assert end + END_TAG.length() == contentEnd + 1;
|
||||
|
||||
if ( returnEmbeddable ) {
|
||||
final StructAttributeValues attributeValues = StructHelper.getAttributeValues( embeddableMappingType, array, options );
|
||||
|
|
|
@ -13,9 +13,14 @@ import org.hibernate.mapping.AggregateColumn;
|
|||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.SqlTypedMapping;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.ARRAY;
|
||||
import static org.hibernate.type.SqlTypes.JSON;
|
||||
import static org.hibernate.type.SqlTypes.JSON_ARRAY;
|
||||
import static org.hibernate.type.SqlTypes.SQLXML;
|
||||
import static org.hibernate.type.SqlTypes.XML_ARRAY;
|
||||
|
||||
public class AggregateSupportImpl implements AggregateSupport {
|
||||
|
||||
public static final AggregateSupport INSTANCE = new AggregateSupportImpl();
|
||||
|
@ -85,7 +90,8 @@ public class AggregateSupportImpl implements AggregateSupport {
|
|||
@Override
|
||||
public int aggregateComponentSqlTypeCode(int aggregateColumnSqlTypeCode, int columnSqlTypeCode) {
|
||||
return switch (aggregateColumnSqlTypeCode) {
|
||||
case SqlTypes.JSON -> columnSqlTypeCode == SqlTypes.ARRAY ? SqlTypes.JSON_ARRAY : columnSqlTypeCode;
|
||||
case JSON -> columnSqlTypeCode == ARRAY ? JSON_ARRAY : columnSqlTypeCode;
|
||||
case SQLXML -> columnSqlTypeCode == ARRAY ? XML_ARRAY : columnSqlTypeCode;
|
||||
default -> columnSqlTypeCode;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ public class DB2AggregateSupport extends AggregateSupportImpl {
|
|||
// We need to know what array this is STRUCT_ARRAY/JSON_ARRAY/XML_ARRAY,
|
||||
// which we can easily get from the type code of the aggregate column
|
||||
final int sqlTypeCode = aggregateColumn.getType().getJdbcType().getDefaultSqlTypeCode();
|
||||
switch ( sqlTypeCode == SqlTypes.ARRAY ? aggregateColumn.getTypeCode() : sqlTypeCode ) {
|
||||
switch ( sqlTypeCode == ARRAY ? aggregateColumn.getTypeCode() : sqlTypeCode ) {
|
||||
case JSON:
|
||||
case JSON_ARRAY:
|
||||
if ( jsonSupport ) {
|
||||
|
@ -350,19 +350,13 @@ public class DB2AggregateSupport extends AggregateSupportImpl {
|
|||
|
||||
@Override
|
||||
public int aggregateComponentSqlTypeCode(int aggregateColumnSqlTypeCode, int columnSqlTypeCode) {
|
||||
if ( aggregateColumnSqlTypeCode == STRUCT ) {
|
||||
return switch (aggregateColumnSqlTypeCode) {
|
||||
// DB2 doesn't support booleans in structs
|
||||
return columnSqlTypeCode == BOOLEAN ? SMALLINT : columnSqlTypeCode;
|
||||
}
|
||||
else if ( aggregateColumnSqlTypeCode == JSON ) {
|
||||
return columnSqlTypeCode == ARRAY ? JSON_ARRAY : columnSqlTypeCode;
|
||||
}
|
||||
else if ( aggregateColumnSqlTypeCode == SQLXML ) {
|
||||
return columnSqlTypeCode == ARRAY ? XML_ARRAY : columnSqlTypeCode;
|
||||
}
|
||||
else {
|
||||
return columnSqlTypeCode;
|
||||
}
|
||||
case STRUCT -> columnSqlTypeCode == BOOLEAN ? SMALLINT : columnSqlTypeCode;
|
||||
case JSON -> columnSqlTypeCode == ARRAY ? JSON_ARRAY : columnSqlTypeCode;
|
||||
case SQLXML -> columnSqlTypeCode == ARRAY ? XML_ARRAY : columnSqlTypeCode;
|
||||
default -> columnSqlTypeCode;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.util.Map;
|
|||
|
||||
import static org.hibernate.dialect.function.json.HANAJsonValueFunction.jsonValueReturningType;
|
||||
import static org.hibernate.dialect.function.xml.HANAXmlTableFunction.xmlValueReturningType;
|
||||
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.BLOB;
|
||||
|
@ -284,19 +283,6 @@ public class HANAAggregateSupport extends AggregateSupportImpl {
|
|||
throw new IllegalArgumentException( "Unsupported aggregate SQL type: " + aggregateColumn.getTypeCode() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int aggregateComponentSqlTypeCode(int aggregateColumnSqlTypeCode, int columnSqlTypeCode) {
|
||||
if ( aggregateColumnSqlTypeCode == JSON ) {
|
||||
return columnSqlTypeCode == ARRAY ? JSON_ARRAY : columnSqlTypeCode;
|
||||
}
|
||||
if ( aggregateColumnSqlTypeCode == SQLXML ) {
|
||||
return columnSqlTypeCode == ARRAY ? XML_ARRAY : columnSqlTypeCode;
|
||||
}
|
||||
else {
|
||||
return columnSqlTypeCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresAggregateCustomWriteExpressionRenderer(int aggregateSqlTypeCode) {
|
||||
return aggregateSqlTypeCode == JSON || aggregateSqlTypeCode == SQLXML;
|
||||
|
|
|
@ -4,17 +4,13 @@
|
|||
*/
|
||||
package org.hibernate.dialect.aggregate;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
|
||||
import org.hibernate.boot.model.relational.Namespace;
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.OracleArrayJdbcType;
|
||||
import org.hibernate.dialect.XmlHelper;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.AggregateColumn;
|
||||
|
@ -27,45 +23,29 @@ import org.hibernate.metamodel.mapping.SelectablePath;
|
|||
import org.hibernate.metamodel.mapping.SqlTypedMapping;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.type.BasicPluralType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.StructJdbcType;
|
||||
import org.hibernate.type.descriptor.sql.DdlType;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.internal.TypeConfigurationWrapperOptions;
|
||||
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;
|
||||
import static org.hibernate.type.SqlTypes.DATE;
|
||||
import static org.hibernate.type.SqlTypes.INTEGER;
|
||||
import static org.hibernate.type.SqlTypes.JSON;
|
||||
import static org.hibernate.type.SqlTypes.JSON_ARRAY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.STRUCT;
|
||||
import static org.hibernate.type.SqlTypes.STRUCT_ARRAY;
|
||||
import static org.hibernate.type.SqlTypes.STRUCT_TABLE;
|
||||
import static org.hibernate.type.SqlTypes.TABLE;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.UUID;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
|
||||
public class OracleAggregateSupport extends AggregateSupportImpl {
|
||||
|
||||
|
@ -79,6 +59,12 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
private static final String JSON_QUERY_START = "json_query(";
|
||||
private static final String JSON_QUERY_JSON_END = "' returning json)";
|
||||
private static final String JSON_QUERY_BLOB_END = "' returning blob)";
|
||||
private static final String XML_EXTRACT_START = "xmlelement(\"" + XmlHelper.ROOT_TAG + "\",xmlquery(";
|
||||
private static final String XML_EXTRACT_SEPARATOR = "/*' passing ";
|
||||
private static final String XML_EXTRACT_END = " returning content))";
|
||||
private static final String XML_QUERY_START = "xmlquery(";
|
||||
private static final String XML_QUERY_SEPARATOR = "' passing ";
|
||||
private static final String XML_QUERY_END = " returning content)";
|
||||
|
||||
private final boolean checkConstraintSupport;
|
||||
private final JsonSupport jsonSupport;
|
||||
|
@ -141,22 +127,24 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
}
|
||||
switch ( column.getJdbcMapping().getJdbcType().getDefaultSqlTypeCode() ) {
|
||||
case BIT:
|
||||
case BOOLEAN:
|
||||
//noinspection unchecked
|
||||
final JdbcLiteralFormatter<Boolean> jdbcLiteralFormatter = (JdbcLiteralFormatter<Boolean>) column.getJdbcMapping().getJdbcType()
|
||||
.getJdbcLiteralFormatter( column.getJdbcMapping().getMappedJavaType() );
|
||||
final Dialect dialect = typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect();
|
||||
final WrapperOptions wrapperOptions = new TypeConfigurationWrapperOptions( typeConfiguration );
|
||||
final String trueLiteral = jdbcLiteralFormatter.toJdbcLiteral( true, dialect, wrapperOptions );
|
||||
final String falseLiteral = jdbcLiteralFormatter.toJdbcLiteral( false, dialect, wrapperOptions );
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"decode(json_value(" + parentPartExpression + columnExpression + "'),'true',1,'false',0,null)"
|
||||
"decode(json_value(" + parentPartExpression + columnExpression + "'),'true'," + trueLiteral + ",'false'," + falseLiteral + ",null)"
|
||||
);
|
||||
case BOOLEAN:
|
||||
if ( column.getColumnDefinition().toLowerCase( Locale.ROOT ).trim().startsWith( "number" ) ) {
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"decode(json_value(" + parentPartExpression + columnExpression + "'),'true',1,'false',0,null)"
|
||||
);
|
||||
}
|
||||
// Fall-through intended
|
||||
case TINYINT:
|
||||
case SMALLINT:
|
||||
case INTEGER:
|
||||
case BIGINT:
|
||||
case CLOB:
|
||||
case NCLOB:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"json_value(" + parentPartExpression + columnExpression + "' returning " + column.getColumnDefinition() + ')'
|
||||
|
@ -182,26 +170,29 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
placeholder,
|
||||
"to_timestamp_tz(json_value(" + parentPartExpression + columnExpression + "'),'YYYY-MM-DD\"T\"hh24:mi:ss.FF9TZH:TZM')"
|
||||
);
|
||||
case BINARY:
|
||||
case VARBINARY:
|
||||
case LONG32VARBINARY:
|
||||
// We encode binary data as hex, so we have to decode here
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"hextoraw(json_value(" + parentPartExpression + columnExpression + "'))"
|
||||
);
|
||||
case UUID:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"hextoraw(replace(json_value(" + parentPartExpression + columnExpression + "'),'-',''))"
|
||||
);
|
||||
case CLOB:
|
||||
case NCLOB:
|
||||
case BINARY:
|
||||
case VARBINARY:
|
||||
case LONG32VARBINARY:
|
||||
// We encode binary data as hex, so we have to decode here
|
||||
if ( determineLength( column ) * 2 < 4000L ) {
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"hextoraw(json_value(" + parentPartExpression + columnExpression + "'))"
|
||||
);
|
||||
}
|
||||
// Fall-through intended
|
||||
case BLOB:
|
||||
// We encode binary data as hex, so we have to decode here
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"(select * from json_table(" + aggregateParentReadExpression + ",'$' columns (" + columnExpression + " " + column.getColumnDefinition() + " path '$." + columnExpression + "')))"
|
||||
// returning binary data is not yet implemented in the json functions,
|
||||
// so use the xml implementation
|
||||
"xmlcast(xmlcdata(json_value(" + parentPartExpression + columnExpression + "' returning clob))) as " + column.getColumnDefinition() + ')'
|
||||
);
|
||||
case ARRAY:
|
||||
final BasicPluralType<?, ?> pluralType = (BasicPluralType<?, ?>) column.getJdbcMapping();
|
||||
|
@ -242,6 +233,83 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
case NONE:
|
||||
throw new UnsupportedOperationException( "The Oracle version doesn't support JSON aggregates!" );
|
||||
}
|
||||
case SQLXML:
|
||||
case XML_ARRAY:
|
||||
switch ( column.getJdbcMapping().getJdbcType().getDefaultSqlTypeCode() ) {
|
||||
case BIT:
|
||||
case BOOLEAN:
|
||||
//noinspection unchecked
|
||||
final JdbcLiteralFormatter<Boolean> jdbcLiteralFormatter = (JdbcLiteralFormatter<Boolean>) column.getJdbcMapping().getJdbcType()
|
||||
.getJdbcLiteralFormatter( column.getJdbcMapping().getMappedJavaType() );
|
||||
final Dialect dialect = typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect();
|
||||
final WrapperOptions wrapperOptions = new TypeConfigurationWrapperOptions( typeConfiguration );
|
||||
final String trueLiteral = jdbcLiteralFormatter.toJdbcLiteral( true, dialect, wrapperOptions );
|
||||
final String falseLiteral = jdbcLiteralFormatter.toJdbcLiteral( false, dialect, wrapperOptions );
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"decode(xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as varchar(5)),'true'," + trueLiteral + ",'false'," + falseLiteral + ",null)"
|
||||
);
|
||||
case FLOAT:
|
||||
case REAL:
|
||||
case DOUBLE:
|
||||
// Since cast is the only way to do optional exponential form parsing, we have to use that.
|
||||
// Unfortunately, the parsing is nationalized, so we need to replace the standard decimal separator dot with the nationalized one first
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"cast(replace(xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as varchar2(255)),'.',substr(to_char(0.1),1,1)) as " + column.getColumnDefinition() + ")"
|
||||
);
|
||||
case DATE:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"to_date(xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as varchar(35)),'YYYY-MM-DD')"
|
||||
);
|
||||
case TIME:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"to_timestamp(xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as varchar(35)),'hh24:mi:ss')"
|
||||
);
|
||||
case TIMESTAMP:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"to_timestamp(xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as varchar(35)),'YYYY-MM-DD\"T\"hh24:mi:ss.FF9')"
|
||||
);
|
||||
case TIMESTAMP_WITH_TIMEZONE:
|
||||
case TIMESTAMP_UTC:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"to_timestamp_tz(xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as varchar(35)),'YYYY-MM-DD\"T\"hh24:mi:ss.FF9TZH:TZM')"
|
||||
);
|
||||
case ARRAY:
|
||||
throw new UnsupportedOperationException( "Transforming XML_ARRAY to native arrays is not supported on Oracle!" );
|
||||
case SQLXML:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
XML_EXTRACT_START + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/*" ) + "))"
|
||||
);
|
||||
case XML_ARRAY:
|
||||
if ( typeConfiguration.getCurrentBaseSqlTypeIndicators().isXmlFormatMapperLegacyFormatEnabled() ) {
|
||||
throw new IllegalArgumentException( "XML array '" + columnExpression + "' in '" + aggregateParentReadExpression + "' is not supported with legacy format enabled." );
|
||||
}
|
||||
else {
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"xmlelement(\"Collection\",xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/*" ) + "))"
|
||||
);
|
||||
}
|
||||
case UUID:
|
||||
if ( SqlTypes.isBinaryType( column.getJdbcMapping().getJdbcType().getDdlTypeCode() ) ) {
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"hextoraw(replace(xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as varchar(36)),'-',''))"
|
||||
);
|
||||
}
|
||||
// Fall-through intended
|
||||
default:
|
||||
return template.replace(
|
||||
placeholder,
|
||||
"xmlcast(xmlquery(" + xmlExtractArguments( aggregateParentReadExpression, columnExpression + "/text()" ) + ") as " + column.getColumnDefinition() + ")"
|
||||
);
|
||||
}
|
||||
case STRUCT:
|
||||
case STRUCT_ARRAY:
|
||||
case STRUCT_TABLE:
|
||||
|
@ -250,6 +318,58 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
throw new IllegalArgumentException( "Unsupported aggregate SQL type: " + aggregateColumnTypeCode );
|
||||
}
|
||||
|
||||
private static String xmlExtractArguments(String aggregateParentReadExpression, String xpathFragment) {
|
||||
final String extractArguments;
|
||||
int separatorIndex;
|
||||
if ( aggregateParentReadExpression.startsWith( XML_EXTRACT_START )
|
||||
&& aggregateParentReadExpression.endsWith( XML_EXTRACT_END )
|
||||
&& (separatorIndex = aggregateParentReadExpression.indexOf( XML_EXTRACT_SEPARATOR )) != -1 ) {
|
||||
final StringBuilder sb = new StringBuilder( aggregateParentReadExpression.length() - XML_EXTRACT_START.length() + xpathFragment.length() );
|
||||
sb.append( aggregateParentReadExpression, XML_EXTRACT_START.length(), separatorIndex );
|
||||
sb.append( '/' );
|
||||
sb.append( xpathFragment );
|
||||
sb.append( aggregateParentReadExpression, separatorIndex + 2, aggregateParentReadExpression.length() - 2 );
|
||||
extractArguments = sb.toString();
|
||||
}
|
||||
else if ( aggregateParentReadExpression.startsWith( XML_QUERY_START )
|
||||
&& aggregateParentReadExpression.endsWith( XML_QUERY_END )
|
||||
&& (separatorIndex = aggregateParentReadExpression.indexOf( XML_QUERY_SEPARATOR )) != -1 ) {
|
||||
final StringBuilder sb = new StringBuilder( aggregateParentReadExpression.length() - XML_QUERY_START.length() + xpathFragment.length() );
|
||||
sb.append( aggregateParentReadExpression, XML_QUERY_START.length(), separatorIndex );
|
||||
sb.append( '/' );
|
||||
sb.append( xpathFragment );
|
||||
sb.append( aggregateParentReadExpression, separatorIndex, aggregateParentReadExpression.length() - 1 );
|
||||
extractArguments = sb.toString();
|
||||
}
|
||||
else {
|
||||
extractArguments = "'/" + XmlHelper.ROOT_TAG + "/" + xpathFragment + "' passing " + aggregateParentReadExpression + " returning content";
|
||||
}
|
||||
return extractArguments;
|
||||
}
|
||||
|
||||
private static long determineLength(SqlTypedMapping column) {
|
||||
final Long length = column.getLength();
|
||||
if ( length != null ) {
|
||||
return length;
|
||||
}
|
||||
else {
|
||||
final String columnDefinition = column.getColumnDefinition();
|
||||
assert columnDefinition != null;
|
||||
final int parenthesisIndex = columnDefinition.indexOf( '(' );
|
||||
if ( parenthesisIndex != -1 ) {
|
||||
int end;
|
||||
for ( end = parenthesisIndex + 1; end < columnDefinition.length(); end++ ) {
|
||||
if ( !Character.isDigit( columnDefinition.charAt( end ) ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Long.parseLong( columnDefinition.substring( parenthesisIndex + 1, end ) );
|
||||
}
|
||||
// Default to the max varchar length
|
||||
return 4000L;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String aggregateComponentAssignmentExpression(
|
||||
String aggregateParentAssignmentExpression,
|
||||
|
@ -259,7 +379,9 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
switch ( aggregateColumnTypeCode ) {
|
||||
case JSON:
|
||||
case JSON_ARRAY:
|
||||
// For JSON we always have to replace the whole object
|
||||
case SQLXML:
|
||||
case XML_ARRAY:
|
||||
// For JSON/XML we always have to replace the whole object
|
||||
return aggregateParentAssignmentExpression;
|
||||
case STRUCT:
|
||||
case STRUCT_ARRAY:
|
||||
|
@ -307,10 +429,14 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
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" ) ) {
|
||||
return "decode(" + customWriteExpression + ",1,'true',0,'false',null)";
|
||||
}
|
||||
//noinspection unchecked
|
||||
final JdbcLiteralFormatter<Boolean> jdbcLiteralFormatter = (JdbcLiteralFormatter<Boolean>) jdbcMapping.getJdbcType()
|
||||
.getJdbcLiteralFormatter( jdbcMapping.getMappedJavaType() );
|
||||
final Dialect dialect = typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect();
|
||||
final WrapperOptions wrapperOptions = new TypeConfigurationWrapperOptions( typeConfiguration );
|
||||
final String trueLiteral = jdbcLiteralFormatter.toJdbcLiteral( true, dialect, wrapperOptions );
|
||||
final String falseLiteral = jdbcLiteralFormatter.toJdbcLiteral( false, dialect, wrapperOptions );
|
||||
return "decode(" + customWriteExpression + "," + trueLiteral + ",'true'," + falseLiteral + ",'false')";
|
||||
// Fall-through intended
|
||||
default:
|
||||
return customWriteExpression;
|
||||
|
@ -319,6 +445,34 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
throw new IllegalStateException( "JSON not supported!" );
|
||||
}
|
||||
|
||||
private static String xmlCustomWriteExpression(String customWriteExpression, JdbcMapping jdbcMapping, TypeConfiguration typeConfiguration) {
|
||||
final int sqlTypeCode = jdbcMapping.getJdbcType().getDefaultSqlTypeCode();
|
||||
switch ( sqlTypeCode ) {
|
||||
case UUID:
|
||||
return "regexp_replace(lower(rawtohex(" + customWriteExpression + ")),'^(.{8})(.{4})(.{4})(.{4})(.{12})$','\\1-\\2-\\3-\\4-\\5')";
|
||||
// case ARRAY:
|
||||
// case XML_ARRAY:
|
||||
// return "(" + customWriteExpression + ") format json";
|
||||
case BOOLEAN:
|
||||
//noinspection unchecked
|
||||
final JdbcLiteralFormatter<Boolean> jdbcLiteralFormatter = (JdbcLiteralFormatter<Boolean>) jdbcMapping.getJdbcType()
|
||||
.getJdbcLiteralFormatter( jdbcMapping.getMappedJavaType() );
|
||||
final Dialect dialect = typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect();
|
||||
final WrapperOptions wrapperOptions = new TypeConfigurationWrapperOptions( typeConfiguration );
|
||||
final String trueLiteral = jdbcLiteralFormatter.toJdbcLiteral( true, dialect, wrapperOptions );
|
||||
final String falseLiteral = jdbcLiteralFormatter.toJdbcLiteral( false, dialect, wrapperOptions );
|
||||
return "decode(" + customWriteExpression + "," + trueLiteral + ",'true'," + falseLiteral + ",'false')";
|
||||
// case TIME:
|
||||
// return "varchar_format(timestamp('1970-01-01'," + customWriteExpression + "),'HH24:MI:SS')";
|
||||
// case TIMESTAMP:
|
||||
// return "replace(varchar_format(" + customWriteExpression + ",'YYYY-MM-DD HH24:MI:SS.FF9'),' ','T')";
|
||||
// case TIMESTAMP_UTC:
|
||||
// return "replace(varchar_format(" + customWriteExpression + ",'YYYY-MM-DD HH24:MI:SS.FF9'),' ','T')||'Z'";
|
||||
default:
|
||||
return customWriteExpression;
|
||||
}
|
||||
}
|
||||
|
||||
private static String determineElementTypeName(
|
||||
Size castTargetSize,
|
||||
BasicPluralType<?, ?> pluralType,
|
||||
|
@ -337,7 +491,7 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
|
||||
@Override
|
||||
public boolean requiresAggregateCustomWriteExpressionRenderer(int aggregateSqlTypeCode) {
|
||||
return aggregateSqlTypeCode == JSON;
|
||||
return aggregateSqlTypeCode == JSON || aggregateSqlTypeCode == SQLXML;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -348,7 +502,9 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
final int aggregateSqlTypeCode = aggregateColumn.getJdbcMapping().getJdbcType().getDefaultSqlTypeCode();
|
||||
switch ( aggregateSqlTypeCode ) {
|
||||
case JSON:
|
||||
return jsonAggregateColumnWriter( aggregateColumn, columnsToUpdate, typeConfiguration );
|
||||
return new RootJsonWriteExpression( aggregateColumn, columnsToUpdate, this, typeConfiguration );
|
||||
case SQLXML:
|
||||
return new RootXmlWriteExpression( aggregateColumn, columnsToUpdate, typeConfiguration );
|
||||
}
|
||||
throw new IllegalArgumentException( "Unsupported aggregate SQL type: " + aggregateSqlTypeCode );
|
||||
}
|
||||
|
@ -381,6 +537,7 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
}
|
||||
arrayType.setElementTypeName( elementJdbcType.getStructTypeName() );
|
||||
arrayType.setElementSqlTypeCode( elementJdbcType.getDefaultSqlTypeCode() );
|
||||
arrayType.setElementDdlTypeCode( elementJdbcType.getDdlTypeCode() );
|
||||
}
|
||||
return super.aggregateAuxiliaryDatabaseObjects(
|
||||
namespace,
|
||||
|
@ -416,13 +573,6 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
NONE;
|
||||
}
|
||||
|
||||
private WriteExpressionRenderer jsonAggregateColumnWriter(
|
||||
SelectableMapping aggregateColumn,
|
||||
SelectableMapping[] columns,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
return new RootJsonWriteExpression( aggregateColumn, columns, this, typeConfiguration );
|
||||
}
|
||||
|
||||
interface JsonWriteExpression {
|
||||
void append(
|
||||
SqlAppender sb,
|
||||
|
@ -615,4 +765,198 @@ public class OracleAggregateSupport extends AggregateSupportImpl {
|
|||
}
|
||||
}
|
||||
|
||||
interface XmlWriteExpression {
|
||||
void append(
|
||||
SqlAppender sb,
|
||||
String path,
|
||||
SqlAstTranslator<?> translator,
|
||||
AggregateColumnWriteExpression expression);
|
||||
}
|
||||
private static class AggregateXmlWriteExpression implements XmlWriteExpression {
|
||||
|
||||
private final SelectableMapping selectableMapping;
|
||||
private final String columnDefinition;
|
||||
private final LinkedHashMap<String, XmlWriteExpression> subExpressions = new LinkedHashMap<>();
|
||||
|
||||
private AggregateXmlWriteExpression(SelectableMapping selectableMapping, String columnDefinition) {
|
||||
this.selectableMapping = selectableMapping;
|
||||
this.columnDefinition = columnDefinition;
|
||||
}
|
||||
|
||||
protected void initializeSubExpressions(SelectableMapping aggregateColumn, SelectableMapping[] columns, TypeConfiguration typeConfiguration) {
|
||||
for ( SelectableMapping column : columns ) {
|
||||
final SelectablePath selectablePath = column.getSelectablePath();
|
||||
final SelectablePath[] parts = selectablePath.getParts();
|
||||
AggregateXmlWriteExpression currentAggregate = this;
|
||||
for ( int i = 1; i < parts.length - 1; i++ ) {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) currentAggregate.selectableMapping.getJdbcMapping().getJdbcType();
|
||||
final EmbeddableMappingType embeddableMappingType = aggregateJdbcType.getEmbeddableMappingType();
|
||||
final int selectableIndex = embeddableMappingType.getSelectableIndex( parts[i].getSelectableName() );
|
||||
currentAggregate = (AggregateXmlWriteExpression) currentAggregate.subExpressions.computeIfAbsent(
|
||||
parts[i].getSelectableName(),
|
||||
k -> new AggregateXmlWriteExpression( embeddableMappingType.getJdbcValueSelectable( selectableIndex ), columnDefinition )
|
||||
);
|
||||
}
|
||||
final String customWriteExpression = column.getWriteExpression();
|
||||
currentAggregate.subExpressions.put(
|
||||
parts[parts.length - 1].getSelectableName(),
|
||||
new BasicXmlWriteExpression(
|
||||
column,
|
||||
xmlCustomWriteExpression( customWriteExpression, column.getJdbcMapping(), typeConfiguration )
|
||||
)
|
||||
);
|
||||
}
|
||||
passThroughUnsetSubExpressions( aggregateColumn );
|
||||
}
|
||||
|
||||
protected void passThroughUnsetSubExpressions(SelectableMapping aggregateColumn) {
|
||||
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) aggregateColumn.getJdbcMapping().getJdbcType();
|
||||
final EmbeddableMappingType embeddableMappingType = aggregateJdbcType.getEmbeddableMappingType();
|
||||
final int jdbcValueCount = embeddableMappingType.getJdbcValueCount();
|
||||
for ( int i = 0; i < jdbcValueCount; i++ ) {
|
||||
final SelectableMapping selectableMapping = embeddableMappingType.getJdbcValueSelectable( i );
|
||||
|
||||
final XmlWriteExpression xmlWriteExpression = subExpressions.get( selectableMapping.getSelectableName() );
|
||||
if ( xmlWriteExpression == null ) {
|
||||
subExpressions.put(
|
||||
selectableMapping.getSelectableName(),
|
||||
new PassThroughXmlWriteExpression( selectableMapping )
|
||||
);
|
||||
}
|
||||
else if ( xmlWriteExpression instanceof AggregateXmlWriteExpression writeExpression ) {
|
||||
writeExpression.passThroughUnsetSubExpressions( selectableMapping );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String getTagName() {
|
||||
return selectableMapping.getSelectableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(
|
||||
SqlAppender sb,
|
||||
String path,
|
||||
SqlAstTranslator<?> translator,
|
||||
AggregateColumnWriteExpression expression) {
|
||||
sb.append( "xmlelement(" );
|
||||
sb.appendDoubleQuoteEscapedString( getTagName() );
|
||||
sb.append( ",xmlconcat" );
|
||||
char separator = '(';
|
||||
for ( Map.Entry<String, XmlWriteExpression> entry : subExpressions.entrySet() ) {
|
||||
sb.append( separator );
|
||||
|
||||
final XmlWriteExpression value = entry.getValue();
|
||||
if ( value instanceof AggregateXmlWriteExpression ) {
|
||||
final String subPath = "xmlquery(" + xmlExtractArguments( path, entry.getKey() ) + ")";
|
||||
value.append( sb, subPath, translator, expression );
|
||||
}
|
||||
else {
|
||||
value.append( sb, path, translator, expression );
|
||||
}
|
||||
separator = ',';
|
||||
}
|
||||
sb.append( "))" );
|
||||
}
|
||||
}
|
||||
|
||||
private static class RootXmlWriteExpression extends AggregateXmlWriteExpression
|
||||
implements WriteExpressionRenderer {
|
||||
private final String path;
|
||||
|
||||
RootXmlWriteExpression(SelectableMapping aggregateColumn, SelectableMapping[] columns, TypeConfiguration typeConfiguration) {
|
||||
super( aggregateColumn, aggregateColumn.getColumnDefinition() );
|
||||
path = aggregateColumn.getSelectionExpression();
|
||||
initializeSubExpressions( aggregateColumn, columns, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTagName() {
|
||||
return XmlHelper.ROOT_TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
SqlAppender sqlAppender,
|
||||
SqlAstTranslator<?> translator,
|
||||
AggregateColumnWriteExpression aggregateColumnWriteExpression,
|
||||
String qualifier) {
|
||||
final String basePath;
|
||||
if ( qualifier == null || qualifier.isBlank() ) {
|
||||
basePath = path;
|
||||
}
|
||||
else {
|
||||
basePath = qualifier + "." + path;
|
||||
}
|
||||
append( sqlAppender, "xmlquery('/" + getTagName() + "' passing " + basePath + " returning content)", translator, aggregateColumnWriteExpression );
|
||||
}
|
||||
}
|
||||
private static class BasicXmlWriteExpression implements XmlWriteExpression {
|
||||
|
||||
private final SelectableMapping selectableMapping;
|
||||
private final String[] customWriteExpressionParts;
|
||||
|
||||
BasicXmlWriteExpression(SelectableMapping selectableMapping, String customWriteExpression) {
|
||||
this.selectableMapping = selectableMapping;
|
||||
if ( customWriteExpression.equals( "?" ) ) {
|
||||
this.customWriteExpressionParts = new String[]{ "", "" };
|
||||
}
|
||||
else {
|
||||
assert !customWriteExpression.startsWith( "?" );
|
||||
final String[] parts = StringHelper.split( "?", customWriteExpression );
|
||||
assert parts.length == 2 || (parts.length & 1) == 1;
|
||||
this.customWriteExpressionParts = parts;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(
|
||||
SqlAppender sb,
|
||||
String path,
|
||||
SqlAstTranslator<?> translator,
|
||||
AggregateColumnWriteExpression expression) {
|
||||
final JdbcType jdbcType = selectableMapping.getJdbcMapping().getJdbcType();
|
||||
final boolean isArray = jdbcType.getDefaultSqlTypeCode() == XML_ARRAY;
|
||||
sb.append( "xmlelement(" );
|
||||
sb.appendDoubleQuoteEscapedString( selectableMapping.getSelectableName() );
|
||||
sb.append( ',' );
|
||||
if ( isArray ) {
|
||||
// Remove the <Collection> tag to wrap the value into the selectable specific tag
|
||||
sb.append( "xmlquery('/Collection/*' passing " );
|
||||
}
|
||||
sb.append( customWriteExpressionParts[0] );
|
||||
for ( int i = 1; i < customWriteExpressionParts.length; i++ ) {
|
||||
// We use NO_UNTYPED here so that expressions which require type inference are casted explicitly,
|
||||
// since we don't know how the custom write expression looks like where this is embedded,
|
||||
// so we have to be pessimistic and avoid ambiguities
|
||||
translator.render( expression.getValueExpression( selectableMapping ), SqlAstNodeRenderingMode.NO_UNTYPED );
|
||||
sb.append( customWriteExpressionParts[i] );
|
||||
}
|
||||
if ( isArray ) {
|
||||
sb.append( " returning content)" );
|
||||
}
|
||||
sb.append( ')' );
|
||||
}
|
||||
}
|
||||
|
||||
private static class PassThroughXmlWriteExpression implements XmlWriteExpression {
|
||||
|
||||
private final SelectableMapping selectableMapping;
|
||||
|
||||
PassThroughXmlWriteExpression(SelectableMapping selectableMapping) {
|
||||
this.selectableMapping = selectableMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(
|
||||
SqlAppender sb,
|
||||
String path,
|
||||
SqlAstTranslator<?> translator,
|
||||
AggregateColumnWriteExpression expression) {
|
||||
sb.append( "xmlquery(" );
|
||||
sb.append( xmlExtractArguments( path, selectableMapping.getSelectableName() ) );
|
||||
sb.append( ")" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -279,19 +279,6 @@ public class SQLServerAggregateSupport extends AggregateSupportImpl {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int aggregateComponentSqlTypeCode(int aggregateColumnSqlTypeCode, int columnSqlTypeCode) {
|
||||
if ( aggregateColumnSqlTypeCode == JSON ) {
|
||||
return columnSqlTypeCode == ARRAY ? JSON_ARRAY : columnSqlTypeCode;
|
||||
}
|
||||
else if ( aggregateColumnSqlTypeCode == SQLXML ) {
|
||||
return columnSqlTypeCode == ARRAY ? XML_ARRAY : columnSqlTypeCode;
|
||||
}
|
||||
else {
|
||||
return columnSqlTypeCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresAggregateCustomWriteExpressionRenderer(int aggregateSqlTypeCode) {
|
||||
return aggregateSqlTypeCode == JSON || aggregateSqlTypeCode == SQLXML;
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.ARRAY;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
|
@ -280,16 +279,6 @@ public class SybaseASEAggregateSupport extends AggregateSupportImpl {
|
|||
throw new IllegalArgumentException( "Unsupported aggregate SQL type: " + aggregateColumn.getTypeCode() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int aggregateComponentSqlTypeCode(int aggregateColumnSqlTypeCode, int columnSqlTypeCode) {
|
||||
if ( aggregateColumnSqlTypeCode == SQLXML ) {
|
||||
return columnSqlTypeCode == ARRAY ? XML_ARRAY : columnSqlTypeCode;
|
||||
}
|
||||
else {
|
||||
return columnSqlTypeCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresAggregateCustomWriteExpressionRenderer(int aggregateSqlTypeCode) {
|
||||
return aggregateSqlTypeCode == SQLXML;
|
||||
|
|
|
@ -17,6 +17,7 @@ public class UserDefinedArrayType extends AbstractUserDefinedType {
|
|||
private Integer arraySqlTypeCode;
|
||||
private String elementTypeName;
|
||||
private Integer elementSqlTypeCode;
|
||||
private Integer elementDdlTypeCode;
|
||||
private Integer arrayLength;
|
||||
|
||||
public UserDefinedArrayType(String contributor, Namespace namespace, Identifier physicalTypeName) {
|
||||
|
@ -47,6 +48,14 @@ public class UserDefinedArrayType extends AbstractUserDefinedType {
|
|||
this.elementSqlTypeCode = elementSqlTypeCode;
|
||||
}
|
||||
|
||||
public Integer getElementDdlTypeCode() {
|
||||
return elementDdlTypeCode;
|
||||
}
|
||||
|
||||
public void setElementDdlTypeCode(Integer elementDdlTypeCode) {
|
||||
this.elementDdlTypeCode = elementDdlTypeCode;
|
||||
}
|
||||
|
||||
public Integer getArrayLength() {
|
||||
return arrayLength;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ public enum CastType {
|
|||
DATE, TIME, TIMESTAMP,
|
||||
OFFSET_TIMESTAMP, ZONE_TIMESTAMP,
|
||||
JSON,
|
||||
XML,
|
||||
NULL,
|
||||
OTHER;
|
||||
|
||||
|
|
|
@ -350,6 +350,9 @@ public interface JdbcType extends Serializable {
|
|||
case JSON:
|
||||
case JSON_ARRAY:
|
||||
return CastType.JSON;
|
||||
case SQLXML:
|
||||
case XML_ARRAY:
|
||||
return CastType.XML;
|
||||
case NULL:
|
||||
return CastType.NULL;
|
||||
default:
|
||||
|
|
|
@ -34,6 +34,11 @@ public class OracleJsonArrayBlobJdbcType extends JsonArrayJdbcType {
|
|||
return SqlTypes.BLOB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDdlTypeCode() {
|
||||
return SqlTypes.BLOB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JsonArrayBlobJdbcType";
|
||||
|
|
|
@ -87,25 +87,7 @@ public class XmlArrayJdbcType extends ArrayJdbcType {
|
|||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
|
||||
return new BasicBinder<>( javaType, this ) {
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String xml = ( (XmlArrayJdbcType ) getJdbcType() ).toString( value, getJavaType(), options );
|
||||
SQLXML sqlxml = st.getConnection().createSQLXML();
|
||||
sqlxml.setString( xml );
|
||||
st.setSQLXML( index, sqlxml );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String xml = ( (XmlArrayJdbcType ) getJdbcType() ).toString( value, getJavaType(), options );
|
||||
SQLXML sqlxml = st.getConnection().createSQLXML();
|
||||
sqlxml.setString( xml );
|
||||
st.setSQLXML( name, sqlxml );
|
||||
}
|
||||
};
|
||||
return new XmlArrayBinder<>( javaType, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,4 +121,28 @@ public class XmlArrayJdbcType extends ArrayJdbcType {
|
|||
|
||||
};
|
||||
}
|
||||
|
||||
protected static class XmlArrayBinder<X> extends BasicBinder<X> {
|
||||
public XmlArrayBinder(JavaType<X> javaType, XmlArrayJdbcType jdbcType) {
|
||||
super( javaType, jdbcType );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String xml = ( (XmlArrayJdbcType) getJdbcType() ).toString( value, getJavaType(), options );
|
||||
SQLXML sqlxml = st.getConnection().createSQLXML();
|
||||
sqlxml.setString( xml );
|
||||
st.setSQLXML( index, sqlxml );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final String xml = ( (XmlArrayJdbcType ) getJdbcType() ).toString( value, getJavaType(), options );
|
||||
SQLXML sqlxml = st.getConnection().createSQLXML();
|
||||
sqlxml.setString( xml );
|
||||
st.setSQLXML( name, sqlxml );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.type.internal;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class TypeConfigurationWrapperOptions implements WrapperOptions {
|
||||
|
||||
private final TypeConfiguration typeConfiguration;
|
||||
|
||||
public TypeConfigurationWrapperOptions(TypeConfiguration typeConfiguration) {
|
||||
this.typeConfiguration = typeConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialect getDialect() {
|
||||
return typeConfiguration.getCurrentBaseSqlTypeIndicators().getDialect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionContractImplementor getSession() {
|
||||
return typeConfiguration.getSessionFactory().getWrapperOptions().getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return typeConfiguration.getSessionFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useStreamForLobBinding() {
|
||||
return typeConfiguration.getSessionFactory().getWrapperOptions().useStreamForLobBinding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreferredSqlTypeCodeForBoolean() {
|
||||
return typeConfiguration.getCurrentBaseSqlTypeIndicators().getPreferredSqlTypeCodeForBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LobCreator getLobCreator() {
|
||||
return typeConfiguration.getSessionFactory().getWrapperOptions().getLobCreator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return typeConfiguration.getSessionFactory().getWrapperOptions().getJdbcTimeZone();
|
||||
}
|
||||
}
|
|
@ -108,10 +108,10 @@ public class XmlEmbeddableTest extends BaseSessionFactoryFunctionalTest {
|
|||
public void testFetchNull() {
|
||||
sessionFactoryScope().inSession(
|
||||
entityManager -> {
|
||||
List<XmlHolder> XmlHolders = entityManager.createQuery( "from XmlHolder b where b.id = 2", XmlHolder.class ).getResultList();
|
||||
assertEquals( 1, XmlHolders.size() );
|
||||
assertEquals( 2L, XmlHolders.get( 0 ).getId() );
|
||||
EmbeddableAggregate.assertEquals( EmbeddableAggregate.createAggregate2(), XmlHolders.get( 0 ).getAggregate() );
|
||||
List<XmlHolder> xmlHolders = entityManager.createQuery( "from XmlHolder b where b.id = 2", XmlHolder.class ).getResultList();
|
||||
assertEquals( 1, xmlHolders.size() );
|
||||
assertEquals( 2L, xmlHolders.get( 0 ).getId() );
|
||||
EmbeddableAggregate.assertEquals( EmbeddableAggregate.createAggregate2(), xmlHolders.get( 0 ).getAggregate() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue