diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java
index 507d072196..efa83ac68f 100644
--- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java
+++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java
@@ -407,6 +407,8 @@ public class CockroachLegacyDialect extends Dialect {
.getDescriptor( Object.class )
)
);
+
+ jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
}
@Override
diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java
index 6693b3b6fe..65c309e95c 100644
--- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java
+++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java
@@ -1441,6 +1441,8 @@ public class PostgreSQLLegacyDialect extends Dialect {
.getDescriptor( Object.class )
)
);
+
+ jdbcTypeRegistry.addTypeConstructor( PostgreSQLArrayJdbcTypeConstructor.INSTANCE );
}
@Override
diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Struct.java b/hibernate-core/src/main/java/org/hibernate/annotations/Struct.java
index d4f45cbc66..de3fab5efe 100644
--- a/hibernate-core/src/main/java/org/hibernate/annotations/Struct.java
+++ b/hibernate-core/src/main/java/org/hibernate/annotations/Struct.java
@@ -47,6 +47,16 @@ public @interface Struct {
*/
String name();
+ /** (Optional) The catalog of the UDT.
+ *
Defaults to the default catalog.
+ */
+ String catalog() default "";
+
+ /** (Optional) The schema of the UDT.
+ *
Defaults to the default schema for user.
+ */
+ String schema() default "";
+
/**
* The ordered set of attributes of the UDT, as they appear physically in the DDL.
* It is important to specify the attributes in the same order for JDBC interactions to work correctly.
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java
index 07fac7e806..eacd5272be 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java
@@ -1778,7 +1778,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
processSecondPasses( idGeneratorResolverSecondPassList );
processSecondPasses( implicitColumnNamingSecondPassList );
processSecondPasses( setBasicValueTypeSecondPassList );
- processSecondPasses( aggregateComponentSecondPassList );
processSecondPasses( toOneJoinTableSecondPassList );
composites.forEach( Component::sortProperties );
@@ -1794,6 +1793,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
processPropertyReferences();
+ processSecondPasses( aggregateComponentSecondPassList );
secondPassCompileForeignKeys( buildingContext );
processNaturalIdUniqueKeyBinders();
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java
index b12064c4a2..1e0c388cdb 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java
@@ -8,20 +8,20 @@ package org.hibernate.boot.model.internal;
import java.util.List;
-import org.hibernate.AnnotationException;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.Struct;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.boot.model.relational.Database;
+import org.hibernate.boot.model.relational.QualifiedName;
+import org.hibernate.boot.model.relational.QualifiedNameImpl;
+import org.hibernate.boot.model.relational.QualifiedNameParser;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.PropertyData;
-import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Component;
-import org.hibernate.mapping.Property;
-import org.hibernate.mapping.Value;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.java.spi.EmbeddableAggregateJavaType;
import org.hibernate.type.spi.TypeConfiguration;
@@ -42,19 +42,18 @@ public final class AggregateComponentBinder {
AnnotatedColumns columns,
MetadataBuildingContext context) {
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, componentXClass );
+ final QualifiedName structQualifiedName = determineStructName( columns, inferredData, componentXClass, context );
+ final String structName = structQualifiedName == null ? null : structQualifiedName.render();
// 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.setStructName( structQualifiedName );
component.setStructColumnNames( determineStructAttributeNames( inferredData, componentXClass ) );
// Determine the aggregate column
@@ -97,6 +96,7 @@ public final class AggregateComponentBinder {
propertyHolder,
component,
componentXClass,
+ inferredData.getPropertyName(),
context
)
);
@@ -111,60 +111,59 @@ public final class AggregateComponentBinder {
case SqlTypes.TABLE:
return SqlTypes.STRUCT_TABLE;
default:
- throw new IllegalArgumentException( "Unsupported array type code: " + arrayTypeCode );
+ throw new UnsupportedOperationException( "Dialect does not support structured array types: " + context.getMetadataCollector()
+ .getDatabase()
+ .getDialect()
+ .getClass()
+ .getName() );
}
}
- private static void validateComponent(Component component, String basePath) {
- for ( Property property : component.getProperties() ) {
- final Value value = property.getValue();
- if ( !( value instanceof BasicValue ) && !( value instanceof Component ) ) {
- // todo: see HHH-15831
- throw new AnnotationException(
- "Property '" + StringHelper.qualify( basePath, property.getName() )
- + "' uses not yet supported mapping type '"
- + value.getClass().getName()
- + "' in component class '"
- + component.getComponentClassName()
- + "'. Aggregate components currently may only contain basic values and components of basic values."
- );
- }
- if ( value instanceof Component ) {
- final Component c = (Component) value;
- if ( c.getAggregateColumn() == null ) {
- validateComponent( c, StringHelper.qualify( basePath, property.getName() ) );
- }
- }
- }
- }
-
- private static String determineStructName(
+ private static QualifiedName determineStructName(
AnnotatedColumns columns,
PropertyData inferredData,
- XClass returnedClassOrElement) {
+ XClass returnedClassOrElement,
+ MetadataBuildingContext context) {
final XProperty property = inferredData.getProperty();
if ( property != null ) {
final Struct struct = property.getAnnotation( Struct.class );
if ( struct != null ) {
- return struct.name();
+ return toQualifiedName( struct, context );
}
final JdbcTypeCode jdbcTypeCode = property.getAnnotation( JdbcTypeCode.class );
if ( jdbcTypeCode != null
&& ( jdbcTypeCode.value() == SqlTypes.STRUCT || jdbcTypeCode.value() == SqlTypes.STRUCT_ARRAY || jdbcTypeCode.value() == SqlTypes.STRUCT_TABLE )
&& columns != null ) {
final List columnList = columns.getColumns();
- if ( columnList.size() == 1 && columnList.get( 0 ).getSqlType() != null ) {
- return columnList.get( 0 ).getSqlType();
+ final String sqlType;
+ if ( columnList.size() == 1 && ( sqlType = columnList.get( 0 ).getSqlType() ) != null ) {
+ if ( sqlType.contains( "." ) ) {
+ return QualifiedNameParser.INSTANCE.parse( sqlType );
+ }
+ return new QualifiedNameParser.NameParts(
+ null,
+ null,
+ context.getMetadataCollector().getDatabase().toIdentifier( sqlType )
+ );
}
}
}
final Struct struct = returnedClassOrElement.getAnnotation( Struct.class );
if ( struct != null ) {
- return struct.name();
+ return toQualifiedName( struct, context );
}
return null;
}
+ private static QualifiedName toQualifiedName(Struct struct, MetadataBuildingContext context) {
+ final Database database = context.getMetadataCollector().getDatabase();
+ return new QualifiedNameImpl(
+ database.toIdentifier( struct.catalog() ),
+ database.toIdentifier( struct.schema() ),
+ database.toIdentifier( struct.name() )
+ );
+ }
+
private static String[] determineStructAttributeNames(PropertyData inferredData, XClass returnedClassOrElement) {
final XProperty property = inferredData.getProperty();
if ( property != null ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java
index f85646d6c3..8872cfb80a 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentSecondPass.java
@@ -11,25 +11,27 @@ import java.util.List;
import java.util.Map;
import java.util.TreeSet;
+import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.common.reflection.XClass;
-import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.Namespace;
+import org.hibernate.boot.model.relational.QualifiedName;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.SecondPass;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.aggregate.AggregateSupport;
import org.hibernate.internal.util.ReflectHelper;
-import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.AggregateColumn;
+import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.UserDefinedObjectType;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.internal.EmbeddableHelper;
@@ -37,6 +39,8 @@ import org.hibernate.sql.Template;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.spi.TypeConfiguration;
+import static org.hibernate.internal.util.StringHelper.qualify;
+
/**
* @author Christian Beikov
*/
@@ -45,20 +49,26 @@ public class AggregateComponentSecondPass implements SecondPass {
private final PropertyHolder propertyHolder;
private final Component component;
private final XClass componentXClass;
+ private final String propertyName;
private final MetadataBuildingContext context;
public AggregateComponentSecondPass(
PropertyHolder propertyHolder,
Component component,
XClass componentXClass,
+ String propertyName,
MetadataBuildingContext context) {
this.propertyHolder = propertyHolder;
this.component = component;
this.componentXClass = componentXClass;
+ this.propertyName = propertyName;
this.context = context;
}
+ @Override
public void doSecondPass(Map persistentClasses) throws MappingException {
+ validateComponent( component, qualify( propertyHolder.getPath(), propertyName ), isAggregateArray() );
+
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
final TypeConfiguration typeConfiguration = metadataCollector.getTypeConfiguration();
final Database database = metadataCollector.getDatabase();
@@ -72,21 +82,17 @@ public class AggregateComponentSecondPass implements SecondPass {
final List aggregatedColumns = component.getAggregatedColumns();
final AggregateColumn aggregateColumn = component.getAggregateColumn();
- ensureInitialized( metadataCollector, typeConfiguration, dialect, aggregateColumn );
+ ensureInitialized( metadataCollector, aggregateColumn );
validateSupportedColumnTypes( propertyHolder.getPath(), component );
- for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
- // Make sure this state is initialized
- aggregatedColumn.getSqlTypeCode( metadataCollector );
- aggregatedColumn.getSqlType( metadataCollector );
- }
-
- final String structName = component.getStructName();
+ final QualifiedName structName = component.getStructName();
final boolean addAuxiliaryObjects;
if ( structName != null ) {
- final Namespace defaultNamespace = database.getDefaultNamespace();
- final Identifier udtName = Identifier.toIdentifier( structName );
- final UserDefinedObjectType udt = new UserDefinedObjectType( "orm", defaultNamespace, udtName );
+ final Namespace namespace = database.locateNamespace(
+ structName.getCatalogName(),
+ structName.getSchemaName()
+ );
+ final UserDefinedObjectType udt = new UserDefinedObjectType( "orm", namespace, structName.getObjectName() );
final Comment comment = componentXClass.getAnnotation( Comment.class );
if ( comment != null ) {
udt.setComment( comment.value() );
@@ -94,8 +100,8 @@ public class AggregateComponentSecondPass implements SecondPass {
for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
udt.addColumn( aggregatedColumn );
}
- final UserDefinedObjectType registeredUdt = defaultNamespace.createUserDefinedType(
- udtName,
+ final UserDefinedObjectType registeredUdt = namespace.createUserDefinedType(
+ structName.getObjectName(),
name -> udt
);
if ( registeredUdt == udt ) {
@@ -187,6 +193,66 @@ public class AggregateComponentSecondPass implements SecondPass {
propertyHolder.getTable().getColumns().removeAll( aggregatedColumns );
}
+ private static void validateComponent(Component component, String basePath, boolean inArray) {
+ for ( Property property : component.getProperties() ) {
+ final Value value = property.getValue();
+ if ( value instanceof Component ) {
+ final Component c = (Component) value;
+ validateComponent( c, qualify( basePath, property.getName() ), inArray );
+ }
+ else if ( value instanceof ToOne ) {
+ final ToOne toOne = (ToOne) value;
+ if ( inArray && toOne.getReferencedPropertyName() != null ) {
+ throw new AnnotationException(
+ "Property '" + qualify( basePath, property.getName() )
+ + "' uses one-to-one mapping with mappedBy '"
+ + toOne.getReferencedPropertyName()
+ + "' in the aggregate component class '"
+ + component.getComponentClassName()
+ + "' within an array property, which is not allowed."
+ );
+ }
+ }
+ else if ( value instanceof Collection ) {
+ final Collection collection = (Collection) value;
+ if ( inArray && collection.getMappedByProperty() != null ) {
+ throw new AnnotationException(
+ "Property '" + qualify( basePath, property.getName() )
+ + "' uses *-to-many mapping with mappedBy '"
+ + collection.getMappedByProperty()
+ + "' in the aggregate component class '"
+ + component.getComponentClassName()
+ + "' within an array property, which is not allowed."
+ );
+ }
+ if ( inArray && collection.getCollectionTable() != null ) {
+ throw new AnnotationException(
+ "Property '" + qualify( basePath, property.getName() )
+ + "' defines a collection table '"
+ + collection.getCollectionTable()
+ + "' in the aggregate component class '"
+ + component.getComponentClassName()
+ + "' within an array property, which is not allowed."
+ );
+ }
+ }
+ }
+ }
+
+ private boolean isAggregateArray() {
+ switch ( component.getAggregateColumn().getSqlTypeCode( context.getMetadataCollector() ) ) {
+ case SqlTypes.STRUCT_ARRAY:
+ case SqlTypes.STRUCT_TABLE:
+ case SqlTypes.JSON_ARRAY:
+ case SqlTypes.XML_ARRAY:
+ case SqlTypes.ARRAY:
+ case SqlTypes.TABLE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
private void orderColumns(UserDefinedObjectType userDefinedType, int[] originalOrder) {
final Class> componentClass = component.getComponentClass();
final String[] structColumnNames = component.getStructColumnNames();
@@ -303,7 +369,7 @@ public class AggregateComponentSecondPass implements SecondPass {
if ( value instanceof Component ) {
final Component subComponent = (Component) value;
if ( subComponent.getAggregateColumn() == null ) {
- validateSupportedColumnTypes( StringHelper.qualify( basePath, property.getName() ), subComponent );
+ validateSupportedColumnTypes( qualify( basePath, property.getName() ), subComponent );
}
}
}
@@ -311,8 +377,27 @@ public class AggregateComponentSecondPass implements SecondPass {
private static void ensureInitialized(
InFlightMetadataCollector metadataCollector,
- TypeConfiguration typeConfiguration,
- Dialect dialect,
+ AggregateColumn aggregateColumn) {
+ ensureParentInitialized( metadataCollector, aggregateColumn );
+ ensureChildrenInitialized( metadataCollector, aggregateColumn );
+ }
+
+ private static void ensureChildrenInitialized(
+ InFlightMetadataCollector metadataCollector,
+ AggregateColumn aggregateColumn) {
+ for ( Column aggregatedColumn : aggregateColumn.getComponent().getAggregatedColumns() ) {
+ // Make sure this state is initialized
+ aggregatedColumn.getSqlTypeCode( metadataCollector );
+ aggregatedColumn.getSqlType( metadataCollector );
+ if ( aggregatedColumn instanceof AggregateColumn ) {
+ ensureChildrenInitialized( metadataCollector, (AggregateColumn) aggregatedColumn );
+ }
+ }
+
+ }
+
+ private static void ensureParentInitialized(
+ InFlightMetadataCollector metadataCollector,
AggregateColumn aggregateColumn) {
do {
// Trigger resolving of the value so that the column gets properly filled
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java
index b54af8adf9..48558dd2cb 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java
@@ -1224,6 +1224,11 @@ public class BasicValueBinder implements JdbcTypeIndicators {
basicValue = new BasicValue( buildingContext, table );
+ if ( columns.getPropertyHolder().isComponent() ) {
+ final ComponentPropertyHolder propertyHolder = (ComponentPropertyHolder) columns.getPropertyHolder();
+ basicValue.setAggregateColumn( propertyHolder.getAggregateColumn() );
+ }
+
if ( isNationalized() ) {
basicValue.makeNationalized();
}
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java
index b493faf796..d557343243 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ComponentPropertyHolder.java
@@ -14,6 +14,7 @@ import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.PropertyData;
+import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.KeyValue;
@@ -265,7 +266,7 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
// if a property is set already the core cannot support that
if ( columns != null ) {
final Table table = columns.getTable();
- if ( !table.equals( component.getTable() ) ) {
+ if ( !table.equals( getTable() ) ) {
if ( component.getPropertySpan() == 0 ) {
component.setTable( table );
}
@@ -301,6 +302,11 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
return component.getOwner().getClassName();
}
+ public AggregateColumn getAggregateColumn() {
+ final AggregateColumn aggregateColumn = component.getAggregateColumn();
+ return aggregateColumn != null ? aggregateColumn : component.getParentAggregateColumn();
+ }
+
@Override
public Table getTable() {
return component.getTable();
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java
index 1463ec488a..17dbbef4e3 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java
@@ -28,6 +28,7 @@ import org.hibernate.boot.spi.AccessType;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.PropertyData;
import org.hibernate.internal.CoreMessageLogger;
+import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
@@ -371,6 +372,14 @@ public class EmbeddableBinder {
returnedClassOrElement = context.getBootstrapContext().getReflectionManager()
.toXClass( compositeUserType.embeddable() );
}
+ AggregateComponentBinder.processAggregate(
+ component,
+ propertyHolder,
+ inferredData,
+ returnedClassOrElement,
+ columns,
+ context
+ );
final XClass annotatedClass = inferredData.getPropertyClass();
final List classElements =
@@ -447,14 +456,6 @@ public class EmbeddableBinder {
processCompositeUserType( component, compositeUserType );
}
- AggregateComponentBinder.processAggregate(
- component,
- propertyHolder,
- inferredData,
- returnedClassOrElement,
- columns,
- context
- );
return component;
}
@@ -563,6 +564,7 @@ public class EmbeddableBinder {
columns.setBuildingContext( context );
discriminatorColumn.setParent( columns );
final BasicValue discriminatorColumnBinding = new BasicValue( context, component.getTable() );
+ discriminatorColumnBinding.setAggregateColumn( component.getAggregateColumn() );
component.setDiscriminator( discriminatorColumnBinding );
discriminatorColumn.linkWithValue( discriminatorColumnBinding );
discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );
@@ -858,6 +860,10 @@ public class EmbeddableBinder {
if ( constructor != null ) {
component.setInstantiator( constructor, constructor.getAnnotation( Instantiator.class ).value() );
}
+ if ( propertyHolder.isComponent() ) {
+ final ComponentPropertyHolder componentPropertyHolder = (ComponentPropertyHolder) propertyHolder;
+ component.setParentAggregateColumn( componentPropertyHolder.getAggregateColumn() );
+ }
return component;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Namespace.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Namespace.java
index 1c6a4cb28a..84b8fd0b4b 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Namespace.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Namespace.java
@@ -34,6 +34,7 @@ import org.hibernate.mapping.UserDefinedArrayType;
import org.hibernate.mapping.UserDefinedObjectType;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.type.BasicType;
+import org.hibernate.type.Type;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.SqlTypedJdbcType;
@@ -183,14 +184,17 @@ public class Namespace {
final UserDefinedType udt = entry.getValue();
if ( udt instanceof UserDefinedObjectType ) {
for ( Column udtColumn : ( (UserDefinedObjectType) udt ).getColumns() ) {
- final JdbcType jdbcType = ( (BasicType>) udtColumn.getValue().getType() ).getJdbcType();
- if ( jdbcType instanceof SqlTypedJdbcType ) {
- dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) jdbcType ).getSqlTypeName() ) );
- }
- else if ( jdbcType instanceof ArrayJdbcType ) {
- final JdbcType elementJdbcType = ( (ArrayJdbcType) jdbcType ).getElementJdbcType();
- if ( elementJdbcType instanceof SqlTypedJdbcType ) {
- dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) elementJdbcType ).getSqlTypeName() ) );
+ final Type udtColumnType = udtColumn.getValue().getType();
+ if ( udtColumnType instanceof BasicType> ) {
+ final JdbcType jdbcType = ( (BasicType>) udtColumnType ).getJdbcType();
+ if ( jdbcType instanceof SqlTypedJdbcType ) {
+ dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) jdbcType ).getSqlTypeName() ) );
+ }
+ else if ( jdbcType instanceof ArrayJdbcType ) {
+ final JdbcType elementJdbcType = ( (ArrayJdbcType) jdbcType ).getElementJdbcType();
+ if ( elementJdbcType instanceof SqlTypedJdbcType ) {
+ dependencies.add( Identifier.toIdentifier( ( (SqlTypedJdbcType) elementJdbcType ).getSqlTypeName() ) );
+ }
}
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLStructJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLStructJdbcType.java
index 5d9e1eceab..76b67da320 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLStructJdbcType.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLStructJdbcType.java
@@ -24,13 +24,11 @@ import java.util.ArrayList;
import java.util.TimeZone;
import org.hibernate.internal.util.CharSequenceHelper;
-import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.ValuedModelPart;
-import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
import org.hibernate.type.BasicPluralType;
@@ -1008,7 +1006,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
final int size = numberOfAttributeMappings + ( embeddableMappingType.isPolymorphic() ? 1 : 0 );
int count = 0;
for ( int i = 0; i < size; i++ ) {
- final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, numberOfAttributeMappings, orderMapping[i] );
+ final ValuedModelPart modelPart = getEmbeddedPart( embeddableMappingType, orderMapping[i] );
final MappingType mappedType = modelPart.getMappedType();
if ( mappedType instanceof EmbeddableMappingType ) {
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
@@ -1178,7 +1176,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
return rawJdbcValue.toString();
}
- protected String toString(X value, JavaType javaType, WrapperOptions options) {
+ protected String toString(X value, JavaType javaType, WrapperOptions options) throws SQLException {
if ( value == null ) {
return null;
}
@@ -1187,86 +1185,62 @@ public abstract class AbstractPostgreSQLStructJdbcType implements StructJdbcType
return sb.toString();
}
- private void serializeStructTo(PostgreSQLAppender appender, Object value, WrapperOptions options) {
- serializeValuesTo( appender, options, embeddableMappingType, value, '(' );
+ private void serializeStructTo(PostgreSQLAppender appender, Object value, WrapperOptions options) throws SQLException {
+ serializeDomainValueTo( appender, options, value, '(' );
appender.append( ')' );
}
- private void serializeValuesTo(
+ private void serializeDomainValueTo(
PostgreSQLAppender appender,
WrapperOptions options,
- EmbeddableMappingType embeddableMappingType,
Object domainValue,
- char separator) {
- final Object[] array = embeddableMappingType.getValues( domainValue );
- final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
- for ( int i = 0; i < array.length; i++ ) {
- final ValuedModelPart attributeMapping;
- final Object attributeValue;
- if ( orderMapping == null ) {
- attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, i );
- attributeValue = array[i];
- }
- else {
- attributeMapping = getEmbeddedPart( embeddableMappingType, numberOfAttributes, orderMapping[i] );
- attributeValue = array[orderMapping[i]];
- }
- if ( attributeMapping instanceof BasicValuedMapping ) {
- appender.append( separator );
- separator = ',';
- if ( attributeValue == null ) {
- continue;
- }
- final JdbcMapping jdbcMapping = ( (BasicValuedMapping) attributeMapping ).getJdbcMapping();
- serializeBasicTo( appender, options, jdbcMapping, attributeValue );
- }
- else if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
- final EmbeddableMappingType mappingType = (EmbeddableMappingType) attributeMapping.getMappedType();
- final SelectableMapping aggregateMapping = mappingType.getAggregateMapping();
- if ( aggregateMapping == null ) {
- serializeValuesTo(
- appender,
- options,
- mappingType,
- attributeValue,
- separator
- );
- separator = ',';
- }
- else {
- appender.append( separator );
- separator = ',';
- if ( attributeValue == null ) {
- continue;
- }
- appender.quoteStart();
- ( (AbstractPostgreSQLStructJdbcType) aggregateMapping.getJdbcMapping().getJdbcType() ).serializeStructTo(
- appender,
- attributeValue,
- options
- );
- appender.quoteEnd();
- }
- }
- else {
- throw new UnsupportedOperationException( "Unsupported attribute mapping: " + attributeMapping );
- }
- }
+ char separator) throws SQLException {
+ serializeJdbcValuesTo(
+ appender,
+ options,
+ StructHelper.getJdbcValues( embeddableMappingType, orderMapping, domainValue, options ),
+ separator
+ );
}
- private void serializeBasicTo(
+ private void serializeJdbcValuesTo(
PostgreSQLAppender appender,
WrapperOptions options,
- JdbcMapping jdbcMapping,
- Object value) {
- serializeConvertedBasicTo( appender, options, jdbcMapping, jdbcMapping.convertToRelationalValue( value ) );
+ Object[] jdbcValues,
+ char separator) throws SQLException {
+ for ( int i = 0; i < jdbcValues.length; i++ ) {
+ appender.append( separator );
+ separator = ',';
+ final Object jdbcValue = jdbcValues[i];
+ if ( jdbcValue == null ) {
+ continue;
+ }
+ final SelectableMapping selectableMapping = orderMapping == null ?
+ embeddableMappingType.getJdbcValueSelectable( i ) :
+ embeddableMappingType.getJdbcValueSelectable( orderMapping[i] );
+ final JdbcMapping jdbcMapping = selectableMapping.getJdbcMapping();
+ if ( jdbcMapping.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) {
+ appender.quoteStart();
+ ( (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType() ).serializeJdbcValuesTo(
+ appender,
+ options,
+ (Object[]) jdbcValue,
+ '('
+ );
+ appender.append( ')' );
+ appender.quoteEnd();
+ }
+ else {
+ serializeConvertedBasicTo( appender, options, jdbcMapping, jdbcValue );
+ }
+ }
}
private void serializeConvertedBasicTo(
PostgreSQLAppender appender,
WrapperOptions options,
JdbcMapping jdbcMapping,
- Object subValue) {
+ Object subValue) throws SQLException {
//noinspection unchecked
final JavaType