Skip to content

Commit 6965f31

Browse files
committed
HHH-15862 Support basic array values in aggregate components
1 parent 4c9b8b1 commit 6965f31

File tree

130 files changed

+8172
-3261
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+8172
-3261
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.hibernate.dialect.OracleJsonJdbcType;
3333
import org.hibernate.dialect.OracleReflectionStructJdbcType;
3434
import org.hibernate.dialect.OracleTypes;
35+
import org.hibernate.dialect.OracleUserDefinedTypeExporter;
3536
import org.hibernate.dialect.OracleXmlJdbcType;
3637
import org.hibernate.dialect.Replacer;
3738
import org.hibernate.dialect.RowLockStrategy;
@@ -67,6 +68,7 @@
6768
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
6869
import org.hibernate.internal.util.JdbcExceptionHelper;
6970
import org.hibernate.internal.util.StringHelper;
71+
import org.hibernate.mapping.UserDefinedType;
7072
import org.hibernate.metamodel.mapping.EntityMappingType;
7173
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
7274
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
@@ -93,6 +95,7 @@
9395
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl;
9496
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
9597
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
98+
import org.hibernate.tool.schema.spi.Exporter;
9699
import org.hibernate.type.JavaObjectType;
97100
import org.hibernate.type.NullType;
98101
import org.hibernate.type.SqlTypes;
@@ -104,6 +107,7 @@
104107
import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType;
105108
import org.hibernate.type.descriptor.jdbc.NullJdbcType;
106109
import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType;
110+
import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType;
107111
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
108112
import org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl;
109113
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
@@ -177,6 +181,7 @@ public class OracleLegacyDialect extends Dialect {
177181
private final LimitHandler limitHandler = supportsFetchClause( FetchClauseType.ROWS_ONLY )
178182
? Oracle12LimitHandler.INSTANCE
179183
: new LegacyOracleLimitHandler( getVersion() );
184+
private final OracleUserDefinedTypeExporter userDefinedTypeExporter = new OracleUserDefinedTypeExporter( this );
180185
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
181186

182187
public OracleLegacyDialect() {
@@ -760,12 +765,12 @@ public JdbcType resolveSqlTypeDescriptor(
760765
jdbcTypeCode = SqlTypes.GEOMETRY;
761766
}
762767
else {
763-
final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor(
768+
final SqlTypedJdbcType descriptor = jdbcTypeRegistry.findSqlTypedDescriptor(
764769
// Skip the schema
765770
columnTypeName.substring( columnTypeName.indexOf( '.' ) + 1 )
766771
);
767-
if ( aggregateDescriptor != null ) {
768-
return aggregateDescriptor;
772+
if ( descriptor != null ) {
773+
return descriptor;
769774
}
770775
}
771776
break;
@@ -777,6 +782,15 @@ public JdbcType resolveSqlTypeDescriptor(
777782
ColumnTypeInformation.EMPTY
778783
);
779784
}
785+
else {
786+
final SqlTypedJdbcType descriptor = jdbcTypeRegistry.findSqlTypedDescriptor(
787+
// Skip the schema
788+
columnTypeName.substring( columnTypeName.indexOf( '.' ) + 1 )
789+
);
790+
if ( descriptor != null ) {
791+
return descriptor;
792+
}
793+
}
780794
break;
781795
case Types.NUMERIC:
782796
if ( precision > 8 // precision of 0 means something funny
@@ -828,7 +842,7 @@ public boolean supportsBitType() {
828842

829843
@Override
830844
public String getArrayTypeName(String javaElementTypeName, String elementTypeName, Integer maxLength) {
831-
return javaElementTypeName + "Array";
845+
return ( javaElementTypeName == null ? elementTypeName : javaElementTypeName ) + "Array";
832846
}
833847

834848
@Override
@@ -837,6 +851,11 @@ public int getPreferredSqlTypeCodeForArray() {
837851
return ARRAY;
838852
}
839853

854+
@Override
855+
public Exporter<UserDefinedType> getUserDefinedTypeExporter() {
856+
return userDefinedTypeExporter;
857+
}
858+
840859
@Override
841860
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
842861
super.contributeTypes( typeContributions, serviceRegistry );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp
560560
appendSql( ')' );
561561
break;
562562
case SqlTypes.ARRAY:
563-
final String arrayTypeName = ( (OracleArrayJdbcType) jdbcType ).getTypeName();
563+
final String arrayTypeName = ( (OracleArrayJdbcType) jdbcType ).getSqlTypeName();
564564
switch ( operator ) {
565565
case DISTINCT_FROM:
566566
case NOT_DISTINCT_FROM:

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
8383
import org.hibernate.type.descriptor.jdbc.JdbcType;
8484
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
85+
import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType;
8586
import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
8687
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
8788
import org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl;
@@ -339,12 +340,23 @@ public JdbcType resolveSqlTypeDescriptor(
339340
ColumnTypeInformation.EMPTY
340341
);
341342
}
343+
final SqlTypedJdbcType elementDescriptor = jdbcTypeRegistry.findSqlTypedDescriptor( componentTypeName );
344+
if ( elementDescriptor != null ) {
345+
return jdbcTypeRegistry.resolveTypeConstructorDescriptor(
346+
jdbcTypeCode,
347+
elementDescriptor,
348+
ColumnTypeInformation.EMPTY
349+
);
350+
}
342351
}
343352
break;
344353
case STRUCT:
345-
final AggregateJdbcType aggregateDescriptor = jdbcTypeRegistry.findAggregateDescriptor( columnTypeName );
346-
if ( aggregateDescriptor != null ) {
347-
return aggregateDescriptor;
354+
final SqlTypedJdbcType descriptor = jdbcTypeRegistry.findSqlTypedDescriptor(
355+
// Skip the schema
356+
columnTypeName.substring( columnTypeName.indexOf( '.' ) + 1 )
357+
);
358+
if ( descriptor != null ) {
359+
return descriptor;
348360
}
349361
break;
350362
}

hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.hibernate.mapping.PrimaryKey;
5959
import org.hibernate.mapping.Property;
6060
import org.hibernate.mapping.Table;
61+
import org.hibernate.mapping.UserDefinedObjectType;
6162
import org.hibernate.mapping.UserDefinedType;
6263
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
6364
import org.hibernate.query.internal.NamedObjectRepositoryImpl;
@@ -448,13 +449,16 @@ public void orderColumns(boolean forceOrdering) {
448449
}
449450
}
450451
for ( UserDefinedType userDefinedType : namespace.getUserDefinedTypes() ) {
451-
if ( userDefinedType.getColumns().size() > 1 ) {
452-
final List<Column> userDefinedTypeColumns = columnOrderingStrategy.orderUserDefinedTypeColumns(
453-
userDefinedType,
454-
this
455-
);
456-
if ( userDefinedTypeColumns != null ) {
457-
userDefinedType.reorderColumns( userDefinedTypeColumns );
452+
if ( userDefinedType instanceof UserDefinedObjectType ) {
453+
final UserDefinedObjectType objectType = (UserDefinedObjectType) userDefinedType;
454+
if ( objectType.getColumns().size() > 1 ) {
455+
final List<Column> objectTypeColumns = columnOrderingStrategy.orderUserDefinedTypeColumns(
456+
objectType,
457+
this
458+
);
459+
if ( objectTypeColumns != null ) {
460+
objectType.reorderColumns( objectTypeColumns );
461+
}
458462
}
459463
}
460464
}

hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,29 +38,29 @@ public static void processAggregate(
3838
Component component,
3939
PropertyHolder propertyHolder,
4040
PropertyData inferredData,
41-
XClass returnedClassOrElement,
41+
XClass componentXClass,
4242
AnnotatedColumns columns,
4343
MetadataBuildingContext context) {
44-
if ( isAggregate( inferredData.getProperty(), inferredData.getClassOrElement() ) ) {
44+
if ( isAggregate( inferredData.getProperty(), componentXClass ) ) {
4545
validateComponent( component, BinderHelper.getPath( propertyHolder, inferredData ) );
4646

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

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

6060
// Determine the aggregate column
6161
BasicValueBinder basicValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ATTRIBUTE, component, context );
6262
basicValueBinder.setPropertyName( inferredData.getPropertyName() );
63-
basicValueBinder.setReturnedClassName( inferredData.getClassOrElementName() );
63+
basicValueBinder.setReturnedClassName( inferredData.getPropertyClass().getName() );
6464
basicValueBinder.setColumns( columns );
6565
basicValueBinder.setPersistentClassName( propertyHolder.getClassName() );
6666
basicValueBinder.setType(
@@ -71,23 +71,50 @@ public static void processAggregate(
7171
);
7272
final BasicValue propertyValue = basicValueBinder.make();
7373
final AggregateColumn aggregateColumn = (AggregateColumn) propertyValue.getColumn();
74-
aggregateColumn.setSqlType( structName );
75-
if ( structName != null ) {
76-
aggregateColumn.setSqlTypeCode( SqlTypes.STRUCT );
74+
if ( structName != null && aggregateColumn.getSqlType() == null ) {
75+
if ( inferredData.getProperty().isArray() || inferredData.getProperty().isCollection() ) {
76+
aggregateColumn.setSqlTypeCode( getStructPluralSqlTypeCode( context ) );
77+
aggregateColumn.setSqlType(
78+
context.getMetadataCollector()
79+
.getDatabase()
80+
.getDialect()
81+
.getArrayTypeName(
82+
null,
83+
structName,
84+
null
85+
)
86+
);
87+
}
88+
else {
89+
aggregateColumn.setSqlTypeCode( SqlTypes.STRUCT );
90+
aggregateColumn.setSqlType( structName );
91+
}
7792
}
7893
component.setAggregateColumn( aggregateColumn );
7994

8095
context.getMetadataCollector().addSecondPass(
8196
new AggregateComponentSecondPass(
8297
propertyHolder,
8398
component,
84-
returnedClassOrElement,
99+
componentXClass,
85100
context
86101
)
87102
);
88103
}
89104
}
90105

106+
private static int getStructPluralSqlTypeCode(MetadataBuildingContext context) {
107+
final int arrayTypeCode = context.getPreferredSqlTypeCodeForArray();
108+
switch ( arrayTypeCode ) {
109+
case SqlTypes.ARRAY:
110+
return SqlTypes.STRUCT_ARRAY;
111+
case SqlTypes.TABLE:
112+
return SqlTypes.STRUCT_TABLE;
113+
default:
114+
throw new IllegalArgumentException( "Unsupported array type code: " + arrayTypeCode );
115+
}
116+
}
117+
91118
private static void validateComponent(Component component, String basePath) {
92119
for ( Property property : component.getProperties() ) {
93120
final Value value = property.getValue();
@@ -122,7 +149,9 @@ private static String determineStructName(
122149
return struct.name();
123150
}
124151
final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class );
125-
if ( jdbcTypeCode != null && jdbcTypeCode.value() == SqlTypes.STRUCT && columns != null ) {
152+
if ( jdbcTypeCode != null
153+
&& ( jdbcTypeCode.value() == SqlTypes.STRUCT || jdbcTypeCode.value() == SqlTypes.STRUCT_ARRAY || jdbcTypeCode.value() == SqlTypes.STRUCT_TABLE )
154+
&& columns != null ) {
126155
final List<AnnotatedColumn> columnList = columns.getColumns();
127156
if ( columnList.size() == 1 && columnList.get( 0 ).getSqlType() != null ) {
128157
return columnList.get( 0 ).getSqlType();
@@ -163,6 +192,10 @@ private static boolean isAggregate(XProperty property, XClass returnedClass) {
163192
case SqlTypes.STRUCT:
164193
case SqlTypes.JSON:
165194
case SqlTypes.SQLXML:
195+
case SqlTypes.STRUCT_ARRAY:
196+
case SqlTypes.STRUCT_TABLE:
197+
case SqlTypes.JSON_ARRAY:
198+
case SqlTypes.XML_ARRAY:
166199
return true;
167200
}
168201
}

0 commit comments

Comments
 (0)