Skip to content

Commit

Permalink
HHH-15862 Support basic array values in aggregate components
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed May 2, 2024
1 parent 88bdfbf commit e7a7eb7
Show file tree
Hide file tree
Showing 187 changed files with 9,078 additions and 3,501 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
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;
Expand Down Expand Up @@ -67,6 +68,7 @@
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
Expand All @@ -93,6 +95,7 @@
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.spi.Exporter;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.NullType;
import org.hibernate.type.SqlTypes;
Expand All @@ -104,6 +107,7 @@
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.SqlTypedJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
Expand Down Expand Up @@ -177,6 +181,7 @@ public class OracleLegacyDialect extends Dialect {
private final LimitHandler limitHandler = supportsFetchClause( FetchClauseType.ROWS_ONLY )
? Oracle12LimitHandler.INSTANCE
: new LegacyOracleLimitHandler( getVersion() );
private final OracleUserDefinedTypeExporter userDefinedTypeExporter = new OracleUserDefinedTypeExporter( this );
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);

public OracleLegacyDialect() {
Expand Down Expand Up @@ -760,12 +765,12 @@ public JdbcType resolveSqlTypeDescriptor(
jdbcTypeCode = SqlTypes.GEOMETRY;
}
else {
final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor(
final SqlTypedJdbcType descriptor = jdbcTypeRegistry.findSqlTypedDescriptor(
// Skip the schema
columnTypeName.substring( columnTypeName.indexOf( '.' ) + 1 )
);
if ( aggregateDescriptor != null ) {
return aggregateDescriptor;
if ( descriptor != null ) {
return descriptor;
}
}
break;
Expand All @@ -777,6 +782,15 @@ public JdbcType resolveSqlTypeDescriptor(
ColumnTypeInformation.EMPTY
);
}
else {
final SqlTypedJdbcType descriptor = jdbcTypeRegistry.findSqlTypedDescriptor(
// Skip the schema
columnTypeName.substring( columnTypeName.indexOf( '.' ) + 1 )
);
if ( descriptor != null ) {
return descriptor;
}
}
break;
case Types.NUMERIC:
if ( precision > 8 // precision of 0 means something funny
Expand Down Expand Up @@ -828,7 +842,7 @@ public boolean supportsBitType() {

@Override
public String getArrayTypeName(String javaElementTypeName, String elementTypeName, Integer maxLength) {
return javaElementTypeName + "Array";
return ( javaElementTypeName == null ? elementTypeName : javaElementTypeName ) + "Array";
}

@Override
Expand All @@ -837,6 +851,11 @@ public int getPreferredSqlTypeCodeForArray() {
return ARRAY;
}

@Override
public Exporter<UserDefinedType> getUserDefinedTypeExporter() {
return userDefinedTypeExporter;
}

@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType;
import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl;
Expand Down Expand Up @@ -339,12 +340,23 @@ public JdbcType resolveSqlTypeDescriptor(
ColumnTypeInformation.EMPTY
);
}
final SqlTypedJdbcType elementDescriptor = jdbcTypeRegistry.findSqlTypedDescriptor( componentTypeName );
if ( elementDescriptor != null ) {
return jdbcTypeRegistry.resolveTypeConstructorDescriptor(
jdbcTypeCode,
elementDescriptor,
ColumnTypeInformation.EMPTY
);
}
}
break;
case STRUCT:
final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor( columnTypeName );
if ( aggregateDescriptor != null ) {
return aggregateDescriptor;
final SqlTypedJdbcType descriptor = jdbcTypeRegistry.findSqlTypedDescriptor(
// Skip the schema
columnTypeName.substring( columnTypeName.indexOf( '.' ) + 1 )
);
if ( descriptor != null ) {
return descriptor;
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,12 +430,17 @@ pathContinuation
* * VALUE( path )
* * KEY( path )
* * path[ selector ]
* * ARRAY_GET( embeddableArrayPath, index ).path
* * COALESCE( array1, array2 )[ selector ].path
*/
syntacticDomainPath
: treatedNavigablePath
| collectionValueNavigablePath
| mapKeyNavigablePath
| simplePath indexedPathAccessFragment
| toOneFkReference
| function pathContinuation
| function indexedPathAccessFragment pathContinuation?
;

/**
Expand Down Expand Up @@ -732,7 +737,6 @@ primaryExpression
| entityIdReference # EntityIdExpression
| entityVersionReference # EntityVersionExpression
| entityNaturalIdReference # EntityNaturalIdExpression
| toOneFkReference # ToOneFkExpression
| syntacticDomainPath pathContinuation? # SyntacticPathExpression
| function # FunctionExpression
| generalPathFragment # GeneralPathExpression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.hibernate.mapping.PrimaryKey;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedObjectType;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.query.internal.NamedObjectRepositoryImpl;
Expand Down Expand Up @@ -448,13 +449,16 @@ public void orderColumns(boolean forceOrdering) {
}
}
for ( UserDefinedType userDefinedType : namespace.getUserDefinedTypes() ) {
if ( userDefinedType.getColumns().size() > 1 ) {
final List<Column> userDefinedTypeColumns = columnOrderingStrategy.orderUserDefinedTypeColumns(
userDefinedType,
this
);
if ( userDefinedTypeColumns != null ) {
userDefinedType.reorderColumns( userDefinedTypeColumns );
if ( userDefinedType instanceof UserDefinedObjectType ) {
final UserDefinedObjectType objectType = (UserDefinedObjectType) userDefinedType;
if ( objectType.getColumns().size() > 1 ) {
final List<Column> objectTypeColumns = columnOrderingStrategy.orderUserDefinedTypeColumns(
objectType,
this
);
if ( objectTypeColumns != null ) {
objectType.reorderColumns( objectTypeColumns );
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,29 @@ public static void processAggregate(
Component component,
PropertyHolder propertyHolder,
PropertyData inferredData,
XClass returnedClassOrElement,
XClass componentXClass,
AnnotatedColumns columns,
MetadataBuildingContext context) {
if ( isAggregate( inferredData.getProperty(), inferredData.getClassOrElement() ) ) {
if ( isAggregate( inferredData.getProperty(), componentXClass ) ) {
validateComponent( component, BinderHelper.getPath( propertyHolder, inferredData ) );

final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
// Determine a struct name if this is a struct through some means
final String structName = determineStructName( columns, inferredData, returnedClassOrElement );
final String structName = determineStructName( columns, inferredData, componentXClass );

// We must register a special JavaType for the embeddable which can provide a recommended JdbcType
typeConfiguration.getJavaTypeRegistry().resolveDescriptor(
component.getComponentClass(),
() -> new EmbeddableAggregateJavaType<>( component.getComponentClass(), structName )
);
component.setStructName( structName );
component.setStructColumnNames( determineStructAttributeNames( inferredData, returnedClassOrElement ) );
component.setStructColumnNames( determineStructAttributeNames( inferredData, componentXClass ) );

// Determine the aggregate column
BasicValueBinder basicValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ATTRIBUTE, component, context );
basicValueBinder.setPropertyName( inferredData.getPropertyName() );
basicValueBinder.setReturnedClassName( inferredData.getClassOrElementName() );
basicValueBinder.setReturnedClassName( inferredData.getPropertyClass().getName() );
basicValueBinder.setColumns( columns );
basicValueBinder.setPersistentClassName( propertyHolder.getClassName() );
basicValueBinder.setType(
Expand All @@ -71,23 +71,50 @@ public static void processAggregate(
);
final BasicValue propertyValue = basicValueBinder.make();
final AggregateColumn aggregateColumn = (AggregateColumn) propertyValue.getColumn();
aggregateColumn.setSqlType( structName );
if ( structName != null ) {
aggregateColumn.setSqlTypeCode( SqlTypes.STRUCT );
if ( structName != null && aggregateColumn.getSqlType() == null ) {
if ( inferredData.getProperty().isArray() || inferredData.getProperty().isCollection() ) {
aggregateColumn.setSqlTypeCode( getStructPluralSqlTypeCode( context ) );
aggregateColumn.setSqlType(
context.getMetadataCollector()
.getDatabase()
.getDialect()
.getArrayTypeName(
null,
structName,
null
)
);
}
else {
aggregateColumn.setSqlTypeCode( SqlTypes.STRUCT );
aggregateColumn.setSqlType( structName );
}
}
component.setAggregateColumn( aggregateColumn );

context.getMetadataCollector().addSecondPass(
new AggregateComponentSecondPass(
propertyHolder,
component,
returnedClassOrElement,
componentXClass,
context
)
);
}
}

private static int getStructPluralSqlTypeCode(MetadataBuildingContext context) {
final int arrayTypeCode = context.getPreferredSqlTypeCodeForArray();
switch ( arrayTypeCode ) {
case SqlTypes.ARRAY:
return SqlTypes.STRUCT_ARRAY;
case SqlTypes.TABLE:
return SqlTypes.STRUCT_TABLE;
default:
throw new IllegalArgumentException( "Unsupported array type code: " + arrayTypeCode );
}
}

private static void validateComponent(Component component, String basePath) {
for ( Property property : component.getProperties() ) {
final Value value = property.getValue();
Expand Down Expand Up @@ -122,7 +149,9 @@ private static String determineStructName(
return struct.name();
}
final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class );
if ( jdbcTypeCode != null && jdbcTypeCode.value() == SqlTypes.STRUCT && columns != null ) {
if ( jdbcTypeCode != null
&& ( jdbcTypeCode.value() == SqlTypes.STRUCT || jdbcTypeCode.value() == SqlTypes.STRUCT_ARRAY || jdbcTypeCode.value() == SqlTypes.STRUCT_TABLE )
&& columns != null ) {
final List<AnnotatedColumn> columnList = columns.getColumns();
if ( columnList.size() == 1 && columnList.get( 0 ).getSqlType() != null ) {
return columnList.get( 0 ).getSqlType();
Expand Down Expand Up @@ -163,6 +192,10 @@ private static boolean isAggregate(XProperty property, XClass returnedClass) {
case SqlTypes.STRUCT:
case SqlTypes.JSON:
case SqlTypes.SQLXML:
case SqlTypes.STRUCT_ARRAY:
case SqlTypes.STRUCT_TABLE:
case SqlTypes.JSON_ARRAY:
case SqlTypes.XML_ARRAY:
return true;
}
}
Expand Down

0 comments on commit e7a7eb7

Please sign in to comment.