HHH-15872 Add ColumnOrderingStrategy SPI and handle record structs specially

This commit is contained in:
Christian Beikov 2022-12-16 12:33:39 +01:00
parent 1f630e4a5d
commit 7007bafe55
122 changed files with 1495 additions and 140 deletions

View File

@ -76,6 +76,8 @@ public class NestedStructEmbeddableTest extends BaseSessionFactoryFunctionalTest
// otherwise we might run into ORA-21700: object does not exist or is marked for delete
// because the JDBC connection or database session caches something that should have been invalidated
ssrBuilder.applySetting( AvailableSettings.CONNECTION_PROVIDER, DriverManagerConnectionProviderImpl.class.getName() );
// Don't reorder columns in the types here to avoid the need to rewrite the test
ssrBuilder.applySetting( AvailableSettings.COLUMN_ORDERING_STRATEGY, "legacy" );
return super.produceServiceRegistry( ssrBuilder );
}
@ -561,6 +563,7 @@ public class NestedStructEmbeddableTest extends BaseSessionFactoryFunctionalTest
@Test
@SkipForDialect(dialectClass = PostgreSQLDialect.class, majorVersion = 10, reason = "Procedures were only introduced in version 11")
@SkipForDialect(dialectClass = PostgresPlusDialect.class, majorVersion = 10, reason = "Procedures were only introduced in version 11")
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "DB2 does not support struct types in procedures")
public void testProcedure() {
sessionFactoryScope().inTransaction(

View File

@ -76,6 +76,8 @@ public class StructEmbeddableTest extends BaseSessionFactoryFunctionalTest {
// otherwise we might run into ORA-21700: object does not exist or is marked for delete
// because the JDBC connection or database session caches something that should have been invalidated
ssrBuilder.applySetting( AvailableSettings.CONNECTION_PROVIDER, DriverManagerConnectionProviderImpl.class.getName() );
// Don't reorder columns in the types here to avoid the need to rewrite the test
ssrBuilder.applySetting( AvailableSettings.COLUMN_ORDERING_STRATEGY, "legacy" );
return super.produceServiceRegistry( ssrBuilder );
}
@ -521,6 +523,7 @@ public class StructEmbeddableTest extends BaseSessionFactoryFunctionalTest {
@Test
@SkipForDialect(dialectClass = PostgreSQLDialect.class, majorVersion = 10, reason = "Procedures were only introduced in version 11")
@SkipForDialect(dialectClass = PostgresPlusDialect.class, majorVersion = 10, reason = "Procedures were only introduced in version 11")
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "DB2 does not support struct types in procedures")
public void testProcedure() {
sessionFactoryScope().inTransaction(

View File

@ -0,0 +1,115 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.community.dialect;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.TemporalUnit;
import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.TemporalUnit.DAY;
/**
* An SQL dialect for Postgres Plus
*
* @author Jim Mlodgenski
*/
public class PostgresPlusLegacyDialect extends PostgreSQLLegacyDialect {
/**
* Constructs a PostgresPlusDialect
*/
public PostgresPlusLegacyDialect() {
super();
}
public PostgresPlusLegacyDialect(DialectResolutionInfo info) {
super( info );
}
public PostgresPlusLegacyDialect(DatabaseVersion version) {
super( version );
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
CommonFunctionFactory functionFactory = new CommonFunctionFactory(queryEngine);
functionFactory.soundex();
functionFactory.rownumRowid();
functionFactory.sysdate();
functionFactory.systimestamp();
// queryEngine.getSqmFunctionRegistry().register( "coalesce", new NvlCoalesceEmulation() );
}
@Override
public String castPattern(CastType from, CastType to) {
if ( to == CastType.STRING ) {
switch ( from ) {
case DATE:
return "to_char(?1,'YYYY-MM-DD')";
case TIME:
return "to_char(?1,'HH24:MI:SS')";
case TIMESTAMP:
return "to_char(?1,'YYYY-MM-DD HH24:MI:SS.FF9')";
case OFFSET_TIMESTAMP:
return "to_char(?1,'YYYY-MM-DD HH24:MI:SS.FF9TZH:TZM')";
case ZONE_TIMESTAMP:
return "to_char(?1,'YYYY-MM-DD HH24:MI:SS.FF9 TZR')";
}
}
return super.castPattern( from, to );
}
@Override
public String currentTimestamp() {
return "current_timestamp";
}
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
if ( toTemporalType != TemporalType.TIMESTAMP && fromTemporalType != TemporalType.TIMESTAMP && unit == DAY ) {
// special case: subtraction of two dates results in an INTERVAL on Postgres Plus
// because there is no date type i.e. without time for Oracle compatibility
final StringBuilder pattern = new StringBuilder();
extractField( pattern, DAY, fromTemporalType, toTemporalType, unit );
return pattern.toString();
}
return super.timestampdiffPattern( unit, fromTemporalType, toTemporalType );
}
@Override
public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException {
statement.registerOutParameter( col, Types.REF );
col++;
return col;
}
@Override
public ResultSet getResultSet(CallableStatement ps) throws SQLException {
ps.execute();
return (ResultSet) ps.getObject( 1 );
}
@Override
public String getSelectGUIDString() {
return "select uuid_generate_v1";
}
}

View File

@ -283,7 +283,7 @@ if ( gradle.ext.javaVersions.test.release.asInt() >= 17 && gradle.ext.javaToolch
}
// We execute the Java 17 tests in a custom test task
task java17Test(type: Test) {
task testJava17(type: Test) {
javaLauncher = javaToolchains.launcherFor {
languageVersion = gradle.ext.javaVersions.test.launcher
}
@ -300,5 +300,5 @@ if ( gradle.ext.javaVersions.test.release.asInt() >= 17 && gradle.ext.javaToolch
testClasses.dependsOn compileTestJava17Java
// And run this as part of the check task by default
check.dependsOn java17Test
check.dependsOn testJava17
}

View File

@ -16,6 +16,7 @@ import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.ColumnOrderingStrategy;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.metamodel.CollectionClassification;
@ -93,6 +94,20 @@ public interface MetadataBuilder {
*/
MetadataBuilder applyPhysicalNamingStrategy(PhysicalNamingStrategy namingStrategy);
/**
* Specify the {@link ColumnOrderingStrategy}.
* <p>
* Its default is defined by the {@value org.hibernate.cfg.AvailableSettings#COLUMN_ORDERING_STRATEGY}
* setting if using property-based configuration.
*
* @param columnOrderingStrategy The {@link ColumnOrderingStrategy}
*
* @return {@code this}, for method chaining
*
* @see org.hibernate.cfg.AvailableSettings#IMPLICIT_NAMING_STRATEGY
*/
MetadataBuilder applyColumnOrderingStrategy(ColumnOrderingStrategy columnOrderingStrategy);
/**
* Specify the second-level cache mode.
* <p>

View File

@ -11,7 +11,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -78,7 +77,6 @@ import org.hibernate.cfg.SecondaryTableFromAnnotationSecondPass;
import org.hibernate.cfg.SecondaryTableSecondPass;
import org.hibernate.cfg.SetBasicValueTypeSecondPass;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.cfg.annotations.BasicValueBinder;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.FilterDefinition;
@ -86,7 +84,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
@ -104,7 +101,6 @@ import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.query.named.NamedObjectRepository;
@ -243,6 +239,11 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
throw new UnsupportedOperationException();
}
@Override
public void orderColumns(boolean forceOrdering) {
// nothing to do
}
@Override
public void validate() throws MappingException {
// nothing to do
@ -2308,7 +2309,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
*/
public MetadataImpl buildMetadataInstance(MetadataBuildingContext buildingContext) {
processSecondPasses( buildingContext );
processExportableProducers( );
processExportableProducers();
try {
return new MetadataImpl(

View File

@ -39,6 +39,8 @@ import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.boot.model.process.spi.MetadataBuildingProcess;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.ColumnOrderingStrategy;
import org.hibernate.boot.model.relational.ColumnOrderingStrategyStandard;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
@ -180,6 +182,12 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
return this;
}
@Override
public MetadataBuilder applyColumnOrderingStrategy(ColumnOrderingStrategy columnOrderingStrategy) {
this.options.columnOrderingStrategy = columnOrderingStrategy;
return this;
}
@Override
public MetadataBuilder applySharedCacheMode(SharedCacheMode sharedCacheMode) {
this.options.sharedCacheMode = sharedCacheMode;
@ -548,6 +556,7 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
private ImplicitNamingStrategy implicitNamingStrategy;
private PhysicalNamingStrategy physicalNamingStrategy;
private ColumnOrderingStrategy columnOrderingStrategy;
private SharedCacheMode sharedCacheMode;
private final AccessType defaultCacheAccessType;
@ -692,6 +701,21 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
PhysicalNamingStrategyStandardImpl.INSTANCE
);
this.columnOrderingStrategy = strategySelector.resolveDefaultableStrategy(
ColumnOrderingStrategy.class,
configService.getSettings().get( AvailableSettings.COLUMN_ORDERING_STRATEGY ),
new Callable<>() {
@Override
public ColumnOrderingStrategy call() {
return strategySelector.resolveDefaultableStrategy(
ColumnOrderingStrategy.class,
"default",
ColumnOrderingStrategyStandard.INSTANCE
);
}
}
);
this.sourceProcessOrdering = resolveInitialSourceProcessOrdering( configService );
this.useNationalizedCharacterData = configService.getSetting(
@ -823,6 +847,11 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
return physicalNamingStrategy;
}
@Override
public ColumnOrderingStrategy getColumnOrderingStrategy() {
return columnOrderingStrategy;
}
@Override
public SharedCacheMode getSharedCacheMode() {
return sharedCacheMode;

View File

@ -24,6 +24,8 @@ import org.hibernate.SessionFactory;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
import org.hibernate.boot.model.TypeDefinition;
import org.hibernate.boot.model.relational.ColumnOrderingStrategy;
import org.hibernate.boot.model.relational.ColumnOrderingStrategyLegacy;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.boot.model.relational.Sequence;
@ -48,12 +50,17 @@ import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.FetchProfile;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.PrimaryKey;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.query.internal.NamedObjectRepositoryImpl;
import org.hibernate.query.named.NamedObjectRepository;
@ -61,6 +68,8 @@ import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.spi.NamedSqmQueryMemento;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.schema.Action;
import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -370,6 +379,120 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return map;
}
@Override
public void orderColumns(boolean forceOrdering) {
final ColumnOrderingStrategy columnOrderingStrategy = metadataBuildingOptions.getColumnOrderingStrategy();
if ( columnOrderingStrategy == ColumnOrderingStrategyLegacy.INSTANCE ) {
// No need to order columns when using the no-op strategy
return;
}
final boolean shouldOrderTableColumns = forceOrdering || shouldOrderTableColumns();
for ( Namespace namespace : database.getNamespaces() ) {
if ( shouldOrderTableColumns ) {
for ( Table table : namespace.getTables() ) {
final List<Column> tableColumns = columnOrderingStrategy.orderTableColumns( table, this );
if ( tableColumns != null ) {
table.reorderColumns( tableColumns );
}
final PrimaryKey primaryKey = table.getPrimaryKey();
if ( primaryKey != null && primaryKey.getColumns()
.size() > 1 && primaryKey.getOriginalOrder() == null ) {
final List<Column> primaryKeyColumns = columnOrderingStrategy.orderConstraintColumns(
primaryKey,
this
);
if ( primaryKeyColumns != null ) {
primaryKey.reorderColumns( primaryKeyColumns );
}
}
for ( UniqueKey uniqueKey : table.getUniqueKeys().values() ) {
if ( uniqueKey.getColumns().size() > 1 ) {
final List<Column> uniqueKeyColumns = columnOrderingStrategy.orderConstraintColumns(
uniqueKey,
this
);
if ( uniqueKeyColumns != null ) {
uniqueKey.getColumns().clear();
uniqueKey.getColumns().addAll( uniqueKeyColumns );
}
}
}
for ( ForeignKey foreignKey : table.getForeignKeys().values() ) {
final List<Column> columns = foreignKey.getColumns();
if ( columns.size() > 1 ) {
if ( foreignKey.getReferencedColumns().isEmpty() ) {
final PrimaryKey foreignKeyTargetPrimaryKey = foreignKey.getReferencedTable()
.getPrimaryKey();
// Make sure we order the columns of the primary key first,
// so that foreign key ordering can rely on this
if ( foreignKeyTargetPrimaryKey.getOriginalOrder() == null ) {
final List<Column> primaryKeyColumns = columnOrderingStrategy.orderConstraintColumns(
foreignKeyTargetPrimaryKey,
this
);
if ( primaryKeyColumns != null ) {
foreignKeyTargetPrimaryKey.reorderColumns( primaryKeyColumns );
}
}
// Patch up the order of foreign keys based on new order of the target primary key
final int[] originalPrimaryKeyOrder = foreignKeyTargetPrimaryKey.getOriginalOrder();
if ( originalPrimaryKeyOrder != null ) {
final ArrayList<Column> foreignKeyColumnsCopy = new ArrayList<>( columns );
for ( int i = 0; i < foreignKeyColumnsCopy.size(); i++ ) {
columns.set( i, foreignKeyColumnsCopy.get( originalPrimaryKeyOrder[i] ) );
}
}
}
}
}
}
}
for ( UserDefinedType userDefinedType : namespace.getUserDefinedTypes() ) {
if ( userDefinedType.getColumns().size() > 1 ) {
final List<Column> userDefinedTypeColumns = columnOrderingStrategy.orderUserDefinedTypeColumns(
userDefinedType,
this
);
if ( userDefinedTypeColumns != null ) {
userDefinedType.reorderColumns( userDefinedTypeColumns );
}
}
}
}
}
private boolean shouldOrderTableColumns() {
final ConfigurationService configurationService = metadataBuildingOptions.getServiceRegistry()
.getService( ConfigurationService.class );
final Set<SchemaManagementToolCoordinator.ActionGrouping> groupings = SchemaManagementToolCoordinator.ActionGrouping.interpret(
this,
configurationService.getSettings()
);
if ( groupings.isEmpty() ) {
return false;
}
for ( SchemaManagementToolCoordinator.ActionGrouping grouping : groupings ) {
if ( isColumnOrderingRelevant( grouping.getScriptAction() ) || isColumnOrderingRelevant( grouping.getDatabaseAction() ) ) {
return true;
}
}
return false;
}
private static boolean isColumnOrderingRelevant(Action grouping) {
switch ( grouping ) {
case CREATE:
case CREATE_DROP:
case CREATE_ONLY:
return true;
default:
return false;
}
}
@Override
public void validate() throws MappingException {
for ( PersistentClass entityBinding : this.getEntityBindings() ) {

View File

@ -0,0 +1,56 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.boot.model.relational;
import java.util.List;
import org.hibernate.Incubating;
import org.hibernate.boot.Metadata;
import org.hibernate.dialect.temptable.TemporaryTableColumn;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedType;
/**
* A pluggable contract that allows ordering of columns within {@link org.hibernate.mapping.Table},
* {@link org.hibernate.mapping.Constraint} and {@link org.hibernate.mapping.UserDefinedType}.
* <p>
* Whenever reasonable, the use of a custom {@linkplain ColumnOrderingStrategy} is highly
* recommended in preference to tedious and repetitive explicit table and column name
* mappings. It's anticipated that most projects using Hibernate will feature a custom
* implementation of {@code ImplicitNamingStrategy}.
* <p>
* An {@linkplain ColumnOrderingStrategy} may be selected using the configuration property
* {@value org.hibernate.cfg.AvailableSettings#COLUMN_ORDERING_STRATEGY}.
*/
@Incubating
public interface ColumnOrderingStrategy {
/**
* Orders the columns of the table.
* May return null if columns were not ordered.
*/
List<Column> orderTableColumns(Table table, Metadata metadata);
/**
* Orders the columns of the constraint.
* May return null if columns were not ordered.
*/
List<Column> orderConstraintColumns(Constraint constraint, Metadata metadata);
/**
* Orders the columns of the user defined type.
* May return null if columns were not ordered.
*/
List<Column> orderUserDefinedTypeColumns(UserDefinedType userDefinedType, Metadata metadata);
/**
* Orders the columns of the temporary table.
*/
void orderTemporaryTableColumns(List<TemporaryTableColumn> temporaryTableColumns, Metadata metadata);
}

View File

@ -0,0 +1,42 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.boot.model.relational;
import java.util.List;
import org.hibernate.boot.Metadata;
import org.hibernate.dialect.temptable.TemporaryTableColumn;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedType;
/**
* A no-op implementation.
*/
public class ColumnOrderingStrategyLegacy implements ColumnOrderingStrategy {
public static final ColumnOrderingStrategyLegacy INSTANCE = new ColumnOrderingStrategyLegacy();
@Override
public List<Column> orderTableColumns(Table table, Metadata metadata) {
return null;
}
@Override
public List<Column> orderConstraintColumns(Constraint constraint, Metadata metadata) {
return null;
}
@Override
public List<Column> orderUserDefinedTypeColumns(UserDefinedType userDefinedType, Metadata metadata) {
return null;
}
@Override
public void orderTemporaryTableColumns(List<TemporaryTableColumn> temporaryTableColumns, Metadata metadata) {
}
}

View File

@ -0,0 +1,213 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.boot.model.relational;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import org.hibernate.boot.Metadata;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.temptable.TemporaryTableColumn;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Constraint;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedType;
import static java.lang.Math.log;
import static org.hibernate.type.SqlTypes.*;
/**
* Standard implementation that orders columns by size and name
* following roughly this ordering: <code>order by max(physicalSizeBytes, 4), physicalSizeBytes > 2048, name</code>
*/
public class ColumnOrderingStrategyStandard implements ColumnOrderingStrategy {
public static final ColumnOrderingStrategyStandard INSTANCE = new ColumnOrderingStrategyStandard();
//needed for converting precision from decimal to binary digits
private static final double DECIMAL_TO_BYTES_QUOTIENT = ( log( 10 ) / log( 2 ) ) * 8;
@Override
public List<Column> orderTableColumns(Table table, Metadata metadata) {
return orderColumns( table.getColumns(), metadata );
}
@Override
public List<Column> orderUserDefinedTypeColumns(UserDefinedType userDefinedType, Metadata metadata) {
return orderColumns( userDefinedType.getColumns(), metadata );
}
@Override
public List<Column> orderConstraintColumns(Constraint constraint, Metadata metadata) {
return orderColumns( constraint.getColumns(), metadata );
}
@Override
public void orderTemporaryTableColumns(List<TemporaryTableColumn> temporaryTableColumns, Metadata metadata) {
temporaryTableColumns.sort( new TemporaryTableColumnComparator( metadata ) );
}
protected List<Column> orderColumns(Collection<Column> columns, Metadata metadata) {
final ArrayList<Column> orderedColumns = new ArrayList<>( columns );
orderedColumns.sort( new ColumnComparator( metadata ) );
return orderedColumns;
}
protected static class ColumnComparator implements Comparator<Column> {
private final Metadata metadata;
protected ColumnComparator(Metadata metadata) {
this.metadata = metadata;
}
@Override
public int compare(Column o1, Column o2) {
final Dialect dialect = metadata.getDatabase().getDialect();
final int physicalSizeInBytes1 = physicalSizeInBytes(
o1.getSqlTypeCode( metadata ),
o1.getColumnSize( dialect, metadata ),
metadata
);
final int physicalSizeInBytes2 = physicalSizeInBytes(
o2.getSqlTypeCode( metadata ),
o2.getColumnSize( dialect, metadata ),
metadata
);
int cmp = Integer.compare( Integer.max( physicalSizeInBytes1, 4 ), Integer.max( physicalSizeInBytes2, 4 ) );
if ( cmp != 0 ) {
return cmp;
}
cmp = Boolean.compare( physicalSizeInBytes1 > 2048, physicalSizeInBytes2 > 2048 );
if ( cmp != 0 ) {
return cmp;
}
return o1.getName().compareTo( o2.getName() );
}
}
protected static class TemporaryTableColumnComparator implements Comparator<TemporaryTableColumn> {
private final Metadata metadata;
protected TemporaryTableColumnComparator(Metadata metadata) {
this.metadata = metadata;
}
@Override
public int compare(TemporaryTableColumn o1, TemporaryTableColumn o2) {
final int physicalSizeInBytes1 = physicalSizeInBytes(
o1.getJdbcMapping().getJdbcType().getDefaultSqlTypeCode(),
o1.getSize(),
metadata
);
final int physicalSizeInBytes2 = physicalSizeInBytes(
o2.getJdbcMapping().getJdbcType().getDefaultSqlTypeCode(),
o2.getSize(),
metadata
);
int cmp = Integer.compare( Integer.max( physicalSizeInBytes1, 4 ), Integer.max( physicalSizeInBytes2, 4 ) );
if ( cmp != 0 ) {
return cmp;
}
cmp = Boolean.compare( physicalSizeInBytes1 > 2048, physicalSizeInBytes2 > 2048 );
if ( cmp != 0 ) {
return cmp;
}
return o1.getColumnName().compareTo( o2.getColumnName() );
}
}
protected static int physicalSizeInBytes(int sqlTypeCode, Size columnSize, Metadata metadata) {
long length;
int precision;
switch ( sqlTypeCode ) {
case BOOLEAN:
case TINYINT:
case BIT:
return 1;
case SMALLINT:
return 2;
case FLOAT:
if ( columnSize.getPrecision() != null ) {
return (int) Math.ceil( columnSize.getPrecision() / DECIMAL_TO_BYTES_QUOTIENT );
}
case REAL:
case INTEGER:
return 4;
case BIGINT:
case DOUBLE:
return 8;
case NUMERIC:
case DECIMAL:
if ( columnSize.getPrecision() == null ) {
precision = metadata.getDatabase().getDialect().getDefaultDecimalPrecision();
}
else {
precision = columnSize.getPrecision();
}
return (int) Math.ceil( precision / DECIMAL_TO_BYTES_QUOTIENT );
case CHAR:
case NCHAR:
case VARCHAR:
case NVARCHAR:
case LONGVARCHAR:
case LONG32VARCHAR:
if ( columnSize.getLength() == null ) {
length = Size.DEFAULT_LENGTH;
}
else {
length = columnSize.getLength();
}
if ( length == Size.DEFAULT_LENGTH ) {
return metadata.getDatabase().getDialect().getMaxVarcharLength();
}
return (int) length;
case LONGNVARCHAR:
case LONG32NVARCHAR:
if ( columnSize.getLength() == null ) {
length = Size.DEFAULT_LENGTH;
}
else {
length = columnSize.getLength();
}
if ( length == Size.DEFAULT_LENGTH ) {
return metadata.getDatabase().getDialect().getMaxNVarcharLength();
}
return (int) length;
case BINARY:
case VARBINARY:
case LONGVARBINARY:
case LONG32VARBINARY:
if ( columnSize.getLength() == null ) {
length = Size.DEFAULT_LENGTH;
}
else {
length = columnSize.getLength();
}
if ( length == Size.DEFAULT_LENGTH ) {
return metadata.getDatabase().getDialect().getMaxVarbinaryLength();
}
return (int) length;
case DATE:
case TIME:
case TIME_WITH_TIMEZONE:
return 4;
case TIMESTAMP:
case TIMESTAMP_UTC:
case TIMESTAMP_WITH_TIMEZONE:
case INTERVAL_SECOND:
return 8;
case UUID:
return 16;
case INET:
return 19;
default:
return Integer.MAX_VALUE;
}
}
}

View File

@ -14,6 +14,9 @@ import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl;
import org.hibernate.boot.model.relational.ColumnOrderingStrategy;
import org.hibernate.boot.model.relational.ColumnOrderingStrategyLegacy;
import org.hibernate.boot.model.relational.ColumnOrderingStrategyStandard;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl;
import org.hibernate.boot.registry.selector.StrategyRegistration;
@ -114,6 +117,7 @@ public class StrategySelectorBuilder {
addTransactionCoordinatorBuilders( strategySelector );
addSqmMultiTableMutationStrategies( strategySelector );
addImplicitNamingStrategies( strategySelector );
addColumnOrderingStrategies( strategySelector );
addCacheKeysFactories( strategySelector );
addJsonFormatMappers( strategySelector );
addXmlFormatMappers( strategySelector );
@ -243,6 +247,19 @@ public class StrategySelectorBuilder {
);
}
private static void addColumnOrderingStrategies(StrategySelectorImpl strategySelector) {
strategySelector.registerStrategyImplementor(
ColumnOrderingStrategy.class,
"default",
ColumnOrderingStrategyStandard.class
);
strategySelector.registerStrategyImplementor(
ColumnOrderingStrategy.class,
"legacy",
ColumnOrderingStrategyLegacy.class
);
}
private static void addCacheKeysFactories(StrategySelectorImpl strategySelector) {
strategySelector.registerStrategyImplementor(
CacheKeysFactory.class,

View File

@ -213,6 +213,11 @@ public abstract class AbstractDelegatingMetadata implements MetadataImplementor
return delegate.getTypeConfiguration();
}
@Override
public void orderColumns(boolean forceOrdering) {
delegate.orderColumns( false );
}
@Override
public void validate() throws MappingException {
delegate.validate();

View File

@ -22,6 +22,7 @@ import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.model.relational.ColumnOrderingStrategy;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
@ -82,6 +83,12 @@ public abstract class AbstractDelegatingMetadataBuilderImplementor<T extends Met
return getThis();
}
@Override
public MetadataBuilder applyColumnOrderingStrategy(ColumnOrderingStrategy columnOrderingStrategy) {
delegate.applyColumnOrderingStrategy( columnOrderingStrategy );
return getThis();
}
@Override
public MetadataBuilder applySharedCacheMode(SharedCacheMode cacheMode) {
delegate.applySharedCacheMode( cacheMode );

View File

@ -13,6 +13,7 @@ import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.model.relational.ColumnOrderingStrategy;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.MetadataSourceType;
@ -84,6 +85,11 @@ public abstract class AbstractDelegatingMetadataBuildingOptions implements Metad
return delegate.getPhysicalNamingStrategy();
}
@Override
public ColumnOrderingStrategy getColumnOrderingStrategy() {
return delegate.getColumnOrderingStrategy();
}
@Override
public SharedCacheMode getSharedCacheMode() {
return delegate.getSharedCacheMode();

View File

@ -14,6 +14,7 @@ import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.model.relational.ColumnOrderingStrategy;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.MetadataSourceType;
@ -80,6 +81,8 @@ public interface MetadataBuildingOptions {
PhysicalNamingStrategy getPhysicalNamingStrategy();
ColumnOrderingStrategy getColumnOrderingStrategy();
/**
* Access to the SharedCacheMode for determining whether we should perform second level
* caching or not.

View File

@ -9,9 +9,9 @@ package org.hibernate.boot.spi;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.Incubating;
import org.hibernate.MappingException;
import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.MappedSuperclass;
@ -42,6 +42,9 @@ public interface MetadataImplementor extends Metadata {
NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory);
@Incubating
void orderColumns(boolean forceOrdering);
void validate() throws MappingException;
Set<MappedSuperclass> getMappedSuperclassMappingsCopy();

View File

@ -7,6 +7,7 @@
package org.hibernate.cfg;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
@ -22,6 +23,7 @@ import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
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.BasicValue;
@ -88,16 +90,18 @@ public class AggregateComponentSecondPass implements SecondPass {
udt.setComment( comment.value() );
}
for ( org.hibernate.mapping.Column aggregatedColumn : aggregatedColumns ) {
// Clone the column, since the column name will be changed later on,
// but we don't want the DDL to be affected by that
udt.addColumn( aggregatedColumn );
}
final UserDefinedType registeredUdt = defaultNamespace.createUserDefinedType(
udtName,
name -> udt
);
addAuxiliaryObjects = registeredUdt == udt;
if ( registeredUdt != udt ) {
if ( registeredUdt == udt ) {
addAuxiliaryObjects = true;
orderColumns( registeredUdt );
}
else {
addAuxiliaryObjects = false;
validateEqual( registeredUdt, udt );
}
}
@ -181,6 +185,67 @@ public class AggregateComponentSecondPass implements SecondPass {
propertyHolder.getTable().getColumns().removeAll( aggregatedColumns );
}
private void orderColumns(UserDefinedType userDefinedType) {
final Class<?> componentClass = component.getComponentClass();
final int[] originalOrder = component.sortProperties();
final int[] propertyMappingIndex;
if ( ReflectHelper.isRecord( componentClass ) ) {
if ( originalOrder == null ) {
propertyMappingIndex = null;
}
else {
final String[] componentNames = ReflectHelper.getRecordComponentNames( componentClass );
propertyMappingIndex = determinePropertyMappingIndex( componentNames );
}
}
else {
// At some point we could do some byte code analysis to determine the order based on a constructor
return;
}
final ArrayList<Column> orderedColumns = new ArrayList<>( userDefinedType.getColumnSpan() );
final List<Property> properties = component.getProperties();
if ( propertyMappingIndex == null ) {
for ( Property property : properties ) {
addColumns( orderedColumns, property.getValue() );
}
}
else {
for ( int newIndex = 0; newIndex < propertyMappingIndex.length; newIndex++ ) {
final int propertyIndex = propertyMappingIndex[newIndex];
addColumns( orderedColumns, properties.get( propertyIndex ).getValue() );
}
}
userDefinedType.reorderColumns( orderedColumns );
}
private static void addColumns(ArrayList<Column> orderedColumns, Value value) {
if ( value instanceof Component ) {
final Component subComponent = (Component) value;
if ( subComponent.getAggregateColumn() == null ) {
for ( Property property : subComponent.getProperties() ) {
addColumns( orderedColumns, property.getValue() );
}
}
else {
orderedColumns.add( subComponent.getAggregateColumn() );
}
}
else {
orderedColumns.addAll( value.getColumns() );
}
}
private static int[] determinePropertyMappingIndex(String[] componentNames) {
final String[] sortedComponentNames = componentNames.clone();
final int[] index = new int[componentNames.length];
Arrays.sort( sortedComponentNames );
for ( int i = 0; i < componentNames.length; i++ ) {
final int newIndex = Arrays.binarySearch( sortedComponentNames, componentNames[i] );
index[newIndex] = i;
}
return index;
}
private void validateSupportedColumnTypes(String basePath, Component component) {
for ( Property property : component.getProperties() ) {
final Value value = property.getValue();

View File

@ -851,6 +851,25 @@ public interface AvailableSettings {
@Incubating
String ID_DB_STRUCTURE_NAMING_STRATEGY = "hibernate.id.db_structure_naming_strategy";
/**
* Used to specify the {@link org.hibernate.boot.model.relational.ColumnOrderingStrategy}
* class to use. The following shortcut names are defined for this setting:
* <ul>
* <li>{@code "default"} is an abbreviations for
* {@link org.hibernate.boot.model.relational.ColumnOrderingStrategyStandard}
* <li>{@code "legacy"} is an abbreviation for
* {@link org.hibernate.boot.model.relational.ColumnOrderingStrategyLegacy}
* </ul>
* By default, the {@linkplain org.hibernate.boot.model.relational.ColumnOrderingStrategy} registered under the key
* {@code "default"} is used. If no strategy is explicitly registered under that key,
* {@link org.hibernate.boot.model.relational.ColumnOrderingStrategyStandard} is used.
*
* @see org.hibernate.boot.MetadataBuilder#applyColumnOrderingStrategy
*
* @since 6.2
*/
String COLUMN_ORDERING_STRATEGY = "hibernate.column_ordering_strategy";
/**
* Specifies the order in which metadata sources should be processed, is a delimited list
* of values defined by {@link MetadataSourceType}.

View File

@ -13,6 +13,7 @@ import java.sql.SQLException;
import java.sql.SQLXML;
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.ValueExtractor;
@ -50,9 +51,9 @@ public class DB2StructJdbcType implements AggregateJdbcType {
this( null, null );
}
public DB2StructJdbcType(String structTypeName, EmbeddableMappingType embeddableMappingType) {
this.structTypeName = structTypeName;
public DB2StructJdbcType(EmbeddableMappingType embeddableMappingType, String structTypeName) {
this.embeddableMappingType = embeddableMappingType;
this.structTypeName = structTypeName;
// We cache the extractor for Object[] here
// since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl
this.objectArrayExtractor = createBasicExtractor( new UnknownBasicJavaType<>( Object[].class ) );
@ -69,8 +70,11 @@ public class DB2StructJdbcType implements AggregateJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
return new DB2StructJdbcType( sqlType, mappingType );
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new DB2StructJdbcType( mappingType, sqlType );
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType;
@ -32,7 +33,10 @@ public class OracleJsonJdbcType extends OracleJsonBlobJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new OracleJsonJdbcType( mappingType );
}

View File

@ -16,10 +16,12 @@ import java.sql.Struct;
import java.util.Locale;
import org.hibernate.HibernateException;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
@ -54,17 +56,19 @@ public class OracleStructJdbcType implements AggregateJdbcType {
};
private final String oracleTypeName;
private final int[] orderMapping;
private final EmbeddableMappingType embeddableMappingType;
private final ValueExtractor<Object[]> objectArrayExtractor;
private OracleStructJdbcType() {
// The default instance is for reading only and will return an Object[]
this( null, null );
this( null, null, null );
}
public OracleStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName) {
this.oracleTypeName = typeName == null ? null : typeName.toUpperCase( Locale.ROOT );
public OracleStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) {
this.embeddableMappingType = embeddableMappingType;
this.oracleTypeName = typeName == null ? null : typeName.toUpperCase( Locale.ROOT );
this.orderMapping = orderMapping;
// We cache the extractor for Object[] here
// since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl
this.objectArrayExtractor = createBasicExtractor( new UnknownBasicJavaType<>( Object[].class ) );
@ -76,8 +80,19 @@ public class OracleStructJdbcType implements AggregateJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
return new OracleStructJdbcType( mappingType, sqlType );
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new OracleStructJdbcType(
mappingType,
sqlType,
creationContext.getBootModel()
.getDatabase()
.getDefaultNamespace()
.locateUserDefinedType( Identifier.toIdentifier( sqlType ) )
.getOrderMapping()
);
}
@Override
@ -126,7 +141,7 @@ public class OracleStructJdbcType implements AggregateJdbcType {
@Override
public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException {
final Object[] attributes = ( (Struct) rawJdbcValue ).getAttributes();
wrapRawJdbcValues( embeddableMappingType, attributes, 0, options );
wrapRawJdbcValues( embeddableMappingType, orderMapping, attributes, 0, options );
return attributes;
}
@ -182,13 +197,14 @@ public class OracleStructJdbcType implements AggregateJdbcType {
final Object[] values = struct.getAttributes();
final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class;
if ( jdbcRepresentation ) {
wrapRawJdbcValues( embeddableMappingType, values, 0, options );
wrapRawJdbcValues( embeddableMappingType, orderMapping, values, 0, options );
//noinspection unchecked
return (X) values;
}
assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType();
final Object[] attributeValues = getAttributeValues(
embeddableMappingType,
orderMapping,
values,
options
);
@ -203,6 +219,7 @@ public class OracleStructJdbcType implements AggregateJdbcType {
public static Object[] getAttributeValues(
EmbeddableMappingType embeddableMappingType,
int[] orderMapping,
Object[] rawJdbcValues,
WrapperOptions options) throws SQLException {
final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings();
@ -216,13 +233,22 @@ public class OracleStructJdbcType implements AggregateJdbcType {
int jdbcIndex = 0;
for ( int i = 0; i < numberOfAttributeMappings; i++ ) {
final AttributeMapping attributeMapping = embeddableMappingType.getAttributeMapping( i );
jdbcIndex += injectAttributeValue( attributeMapping, attributeValues, i, rawJdbcValues, jdbcIndex, options );
jdbcIndex += injectAttributeValue(
attributeMapping,
orderMapping,
attributeValues,
i,
rawJdbcValues,
jdbcIndex,
options
);
}
return attributeValues;
}
private static int injectAttributeValue(
AttributeMapping attributeMapping,
int[] orderMapping,
Object[] attributeValues,
int attributeIndex,
Object[] rawJdbcValues,
@ -230,17 +256,36 @@ public class OracleStructJdbcType implements AggregateJdbcType {
WrapperOptions options) throws SQLException {
final MappingType mappedType = attributeMapping.getMappedType();
final int jdbcValueCount;
final Object rawJdbcValue = rawJdbcValues[jdbcIndex];
final Object rawJdbcValue;
if ( orderMapping == null ) {
rawJdbcValue = rawJdbcValues[jdbcIndex];
}
else {
rawJdbcValue = rawJdbcValues[orderMapping[jdbcIndex]];
}
if ( mappedType instanceof EmbeddableMappingType ) {
final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType;
if ( embeddableMappingType.getAggregateMapping() != null ) {
jdbcValueCount = 1;
if ( rawJdbcValue instanceof Struct ) {
final Object[] subValues = getAttributeValues(
if ( rawJdbcValue == null ) {
attributeValues[attributeIndex] = null;
}
else {
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableMappingType.getAggregateMapping()
.getJdbcMapping()
.getJdbcType();
final Object[] subValues;
if ( aggregateJdbcType instanceof OracleStructJdbcType ) {
subValues = getAttributeValues(
embeddableMappingType,
( (OracleStructJdbcType) aggregateJdbcType ).orderMapping,
( (Struct) rawJdbcValue ).getAttributes(),
options
);
}
else {
subValues = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
}
attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy()
.getInstantiator()
.instantiate(
@ -250,15 +295,12 @@ public class OracleStructJdbcType implements AggregateJdbcType {
.getFactory()
);
}
else {
attributeValues[attributeIndex] = rawJdbcValue;
}
}
else {
jdbcValueCount = embeddableMappingType.getJdbcValueCount();
final Object[] jdbcValues = new Object[jdbcValueCount];
System.arraycopy( rawJdbcValues, jdbcIndex, jdbcValues, 0, jdbcValues.length );
final Object[] subValues = getAttributeValues( embeddableMappingType, jdbcValues, options );
final Object[] subValues = getAttributeValues( embeddableMappingType, orderMapping, jdbcValues, options );
attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy()
.getInstantiator()
.instantiate(
@ -297,6 +339,7 @@ public class OracleStructJdbcType implements AggregateJdbcType {
private static int wrapRawJdbcValues(
EmbeddableMappingType embeddableMappingType,
int[] orderMapping,
Object[] jdbcValues,
int jdbcIndex,
WrapperOptions options) throws SQLException {
@ -311,16 +354,29 @@ public class OracleStructJdbcType implements AggregateJdbcType {
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping()
.getJdbcMapping()
.getJdbcType();
jdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( jdbcValues[jdbcIndex], options );
final Object rawJdbcValue;
if ( orderMapping == null ) {
rawJdbcValue = jdbcValues[jdbcIndex];
}
else {
rawJdbcValue = jdbcValues[orderMapping[jdbcIndex]];
}
jdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options );
jdbcIndex++;
}
else {
jdbcIndex = wrapRawJdbcValues( embeddableType, jdbcValues, jdbcIndex, options );
jdbcIndex = wrapRawJdbcValues( embeddableType, orderMapping, jdbcValues, jdbcIndex, options );
}
}
else {
assert attributeMapping.getJdbcTypeCount() == 1;
final Object rawJdbcValue = jdbcValues[jdbcIndex];
final Object rawJdbcValue;
if ( orderMapping == null ) {
rawJdbcValue = jdbcValues[jdbcIndex];
}
else {
rawJdbcValue = jdbcValues[orderMapping[jdbcIndex]];
}
if ( rawJdbcValue != null ) {
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMappings().get( 0 );
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {

View File

@ -12,6 +12,7 @@ import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
@ -30,7 +31,10 @@ public class OracleXmlJdbcType extends XmlJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new OracleXmlJdbcType( mappingType );
}

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
/**
@ -21,7 +22,10 @@ public class PostgreSQLJsonJdbcType extends AbstractPostgreSQLJsonJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new PostgreSQLJsonJdbcType( mappingType );
}

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
/**
@ -21,7 +22,10 @@ public class PostgreSQLJsonbJdbcType extends AbstractPostgreSQLJsonJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new PostgreSQLJsonbJdbcType( mappingType );
}
}

View File

@ -20,6 +20,7 @@ import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.TimeZone;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.internal.util.CharSequenceHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
@ -27,6 +28,7 @@ import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
import org.hibernate.type.SqlTypes;
@ -81,17 +83,19 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
.toFormatter();
}
private final int[] orderMapping;
private final EmbeddableMappingType embeddableMappingType;
private final ValueExtractor<Object[]> objectArrayExtractor;
private PostgreSQLStructJdbcType() {
// The default instance is for reading only and will return an Object[]
this( null, null );
this( null, null, null );
}
public PostgreSQLStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName) {
public PostgreSQLStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) {
super( typeName, SqlTypes.STRUCT );
this.embeddableMappingType = embeddableMappingType;
this.orderMapping = orderMapping;
// We cache the extractor for Object[] here
// since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl
this.objectArrayExtractor = super.getExtractor( new UnknownBasicJavaType<>( Object[].class ) );
@ -103,8 +107,19 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
return new PostgreSQLStructJdbcType( mappingType, sqlType );
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new PostgreSQLStructJdbcType(
mappingType,
sqlType,
creationContext.getBootModel()
.getDatabase()
.getDefaultNamespace()
.locateUserDefinedType( Identifier.toIdentifier( sqlType ) )
.getOrderMapping()
);
}
@Override
@ -267,7 +282,7 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
continue;
}
assert repeatsChar( string, i, 1 << quoteLevel, '"' );
final JdbcMapping jdbcMapping = embeddableMappingType.getJdbcValueSelectable( column )
final JdbcMapping jdbcMapping = getJdbcValueSelectable( column )
.getJdbcMapping();
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
case SqlTypes.DATE:
@ -381,7 +396,7 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
i += expectedQuotes - 1;
if ( string.charAt( i + 1 ) == '(' ) {
// This could be a nested struct
final JdbcMapping jdbcMapping = embeddableMappingType.getJdbcValueSelectable( column )
final JdbcMapping jdbcMapping = getJdbcValueSelectable( column )
.getJdbcMapping();
if ( jdbcMapping.getJdbcType() instanceof PostgreSQLStructJdbcType ) {
final PostgreSQLStructJdbcType structJdbcType;
@ -438,7 +453,7 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
values[column] = null;
}
else {
final JdbcMapping jdbcMapping = embeddableMappingType.getJdbcValueSelectable( column ).getJdbcMapping();
final JdbcMapping jdbcMapping = getJdbcValueSelectable( column ).getJdbcMapping();
if ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() == SqlTypes.BOOLEAN ) {
values[column] = fromRawObject(
jdbcMapping,
@ -467,7 +482,6 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
}
else {
values[column] = fromString(
embeddableMappingType,
column,
string,
start,
@ -484,6 +498,13 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
throw new IllegalArgumentException( "Struct not properly formed: " + string.substring( start ) );
}
private SelectableMapping getJdbcValueSelectable(int jdbcValueSelectableIndex) {
if ( orderMapping != null ) {
jdbcValueSelectableIndex = orderMapping[jdbcValueSelectableIndex];
}
return embeddableMappingType.getJdbcValueSelectable( jdbcValueSelectableIndex );
}
private static boolean repeatsChar(String string, int start, int times, char c) {
final int end = start + times;
if ( end < string.length() ) {
@ -497,14 +518,13 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme
return false;
}
private static Object fromString(
EmbeddableMappingType embeddableMappingType,
private Object fromString(
int selectableIndex,
String string,
int start,
int end) {
return fromString(
embeddableMappingType.getJdbcValueSelectable( selectableIndex ).getJdbcMapping(),
getJdbcValueSelectable( selectableIndex ).getJdbcMapping(),
string,
start,
end

View File

@ -15,8 +15,6 @@ import jakarta.persistence.TemporalType;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.procedure.internal.PostgreSQLCallableStatementSupport;
import org.hibernate.procedure.spi.CallableStatementSupport;
import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
@ -109,11 +107,6 @@ public class PostgresPlusDialect extends PostgreSQLDialect {
return (ResultSet) ps.getObject( 1 );
}
@Override
public CallableStatementSupport getCallableStatementSupport() {
return getVersion().isSameOrAfter( 10 ) ? PostgreSQLCallableStatementSupport.INSTANCE : PostgreSQLCallableStatementSupport.V10_INSTANCE;
}
@Override
public String getSelectGUIDString() {
return "select uuid_generate_v1";

View File

@ -43,7 +43,7 @@ public class StandardTemporaryTableExporter implements TemporaryTableExporter {
buffer.append( temporaryTable.getQualifiedTableName() );
buffer.append( '(' );
for ( TemporaryTableColumn column : temporaryTable.getColumns() ) {
for ( TemporaryTableColumn column : temporaryTable.getColumnsForExport() ) {
buffer.append( column.getColumnName() ).append( ' ' );
final int sqlTypeCode = column.getJdbcMapping().getJdbcType().getDefaultSqlTypeCode();
final String databaseTypeName = column.getSqlTypeDefinition();
@ -68,7 +68,7 @@ public class StandardTemporaryTableExporter implements TemporaryTableExporter {
}
if ( dialect.supportsTemporaryTablePrimaryKey() ) {
buffer.append( "primary key (" );
for ( TemporaryTableColumn column : temporaryTable.getColumns() ) {
for ( TemporaryTableColumn column : temporaryTable.getColumnsForExport() ) {
if ( column.isPrimaryKey() ) {
buffer.append( column.getColumnName() );
buffer.append( ", " );

View File

@ -16,8 +16,8 @@ import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.Exportable;
import org.hibernate.boot.model.relational.QualifiedNameParser;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.id.OptimizableGenerator;
import org.hibernate.id.enhanced.Optimizer;
import org.hibernate.internal.CoreLogging;
@ -63,6 +63,7 @@ public class TemporaryTable implements Exportable, Contributable {
private final TemporaryTableSessionUidColumn sessionUidColumn;
private final List<TemporaryTableColumn> columns;
private final List<TemporaryTableColumn> columnsForExport;
private final Dialect dialect;
@ -70,7 +71,7 @@ public class TemporaryTable implements Exportable, Contributable {
EntityMappingType entityDescriptor,
Function<String, String> temporaryTableNameAdjuster,
Dialect dialect,
SqlStringGenerationContext sqlStringGenerationContext,
RuntimeModelCreationContext creationContext,
Function<TemporaryTable, List<TemporaryTableColumn>> columnInitializer) {
this.entityDescriptor = entityDescriptor;
final EntityPersister entityPersister = entityDescriptor.getEntityPersister();
@ -104,7 +105,7 @@ public class TemporaryTable implements Exportable, Contributable {
else {
tableNameIdentifier = new Identifier( temporaryTableName, nameParts.getObjectName().isQuoted() );
}
this.qualifiedTableName = sqlStringGenerationContext.format(
this.qualifiedTableName = creationContext.getSessionFactory().getSqlStringGenerationContext().format(
new QualifiedTableName(
adjustedNameParts.getCatalogName() != null
? adjustedNameParts.getCatalogName()
@ -123,19 +124,21 @@ public class TemporaryTable implements Exportable, Contributable {
final BasicType<UUID> uuidType = typeConfiguration.getBasicTypeRegistry().resolve(
StandardBasicTypes.UUID_CHAR
);
this.sessionUidColumn = new TemporaryTableSessionUidColumn(
this,
uuidType,
typeConfiguration.getDdlTypeRegistry().getTypeName(
uuidType.getJdbcType().getDefaultSqlTypeCode(),
dialect.getSizeStrategy().resolveSize(
final Size size = dialect.getSizeStrategy().resolveSize(
uuidType.getJdbcType(),
uuidType.getJavaTypeDescriptor(),
null,
null,
null
)
)
);
this.sessionUidColumn = new TemporaryTableSessionUidColumn(
this,
uuidType,
typeConfiguration.getDdlTypeRegistry().getTypeName(
uuidType.getJdbcType().getDefaultSqlTypeCode(),
size
),
size
);
}
else {
@ -146,6 +149,16 @@ public class TemporaryTable implements Exportable, Contributable {
columns.add( sessionUidColumn );
}
this.columns = columns;
if ( columns.size() > 1 ) {
final ArrayList<TemporaryTableColumn> columnsForExport = new ArrayList<>( columns );
creationContext.getBootModel().getMetadataBuildingOptions().getColumnOrderingStrategy()
.orderTemporaryTableColumns( columnsForExport, creationContext.getMetadata() );
this.columnsForExport = columnsForExport;
}
else {
this.columnsForExport = columns;
}
}
public static TemporaryTable createIdTable(
@ -157,7 +170,7 @@ public class TemporaryTable implements Exportable, Contributable {
entityDescriptor,
temporaryTableNameAdjuster,
dialect,
runtimeModelCreationContext.getSessionFactory().getSqlStringGenerationContext(),
runtimeModelCreationContext,
temporaryTable -> {
final List<TemporaryTableColumn> columns = new ArrayList<>();
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()
@ -178,6 +191,10 @@ public class TemporaryTable implements Exportable, Contributable {
dialect,
runtimeModelCreationContext.getMetadata()
),
column.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
column.isNullable(),
true
)
@ -192,7 +209,7 @@ public class TemporaryTable implements Exportable, Contributable {
if ( pluralAttribute.getSeparateCollectionTable() != null ) {
// Ensure that the FK target columns are available
ForeignKeyDescriptor keyDescriptor = pluralAttribute.getKeyDescriptor();
if ( keyDescriptor==null ) {
if ( keyDescriptor == null ) {
// This is expected to happen when processing a
// PostInitCallbackEntry because the callbacks
// are not ordered. The exception is caught in
@ -214,13 +231,17 @@ public class TemporaryTable implements Exportable, Contributable {
columns.add(
new TemporaryTableColumn(
temporaryTable,
selectable.getText( dialect ),
column.getText( dialect ),
selection.getJdbcMapping(),
column.getSqlType(
runtimeModelCreationContext.getTypeConfiguration(),
dialect,
runtimeModelCreationContext.getMetadata()
),
column.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
column.isNullable()
)
);
@ -246,7 +267,7 @@ public class TemporaryTable implements Exportable, Contributable {
entityDescriptor,
temporaryTableNameAdjuster,
dialect,
runtimeModelCreationContext.getSessionFactory().getSqlStringGenerationContext(),
runtimeModelCreationContext,
temporaryTable -> {
final List<TemporaryTableColumn> columns = new ArrayList<>();
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()
@ -273,8 +294,12 @@ public class TemporaryTable implements Exportable, Contributable {
runtimeModelCreationContext.getMetadata()
) + " " +
dialect.getIdentityColumnSupport().getIdentityColumnString( column.getSqlTypeCode( runtimeModelCreationContext.getMetadata() ) ),
column.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
// Always report as nullable as the identity column string usually includes the not null constraint
true, //column.isNullable()
true,//column.isNullable()
true
)
);
@ -304,6 +329,10 @@ public class TemporaryTable implements Exportable, Contributable {
dialect,
runtimeModelCreationContext.getMetadata()
),
column.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
// We have to set the identity column after the root table insert
column.isNullable() || identityColumn || hasOptimizer,
!identityColumn && !hasOptimizer
@ -324,6 +353,10 @@ public class TemporaryTable implements Exportable, Contributable {
dialect,
runtimeModelCreationContext.getMetadata()
),
discriminator.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
// We have to set the identity column after the root table insert
discriminator.isNullable()
)
@ -352,6 +385,10 @@ public class TemporaryTable implements Exportable, Contributable {
dialect,
runtimeModelCreationContext.getMetadata()
),
column.getColumnSize(
dialect,
runtimeModelCreationContext.getMetadata()
),
// Treat regular temporary table columns as nullable for simplicity
true
)
@ -411,6 +448,7 @@ public class TemporaryTable implements Exportable, Contributable {
"rn_",
integerBasicType,
rowNumberType,
Size.nil(),
false,
true
)
@ -433,6 +471,10 @@ public class TemporaryTable implements Exportable, Contributable {
return columns;
}
public List<TemporaryTableColumn> getColumnsForExport() {
return columnsForExport;
}
public TemporaryTableSessionUidColumn getSessionUidColumn() {
return sessionUidColumn;
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.dialect.temptable;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.metamodel.mapping.JdbcMapping;
/**
@ -19,6 +20,7 @@ public class TemporaryTableColumn {
private final String columnName;
private final JdbcMapping jdbcMapping;
private final String sqlTypeName;
private final Size size;
private final boolean nullable;
private final boolean primaryKey;
@ -27,8 +29,9 @@ public class TemporaryTableColumn {
String columnName,
JdbcMapping jdbcMapping,
String sqlTypeName,
Size size,
boolean nullable) {
this( containingTable, columnName, jdbcMapping, sqlTypeName, nullable, false );
this( containingTable, columnName, jdbcMapping, sqlTypeName, size, nullable, false );
}
public TemporaryTableColumn(
@ -36,12 +39,14 @@ public class TemporaryTableColumn {
String columnName,
JdbcMapping jdbcMapping,
String sqlTypeName,
Size size,
boolean nullable,
boolean primaryKey) {
this.containingTable = containingTable;
this.columnName = columnName;
this.jdbcMapping = jdbcMapping;
this.sqlTypeName = sqlTypeName;
this.size = size;
this.nullable = nullable;
this.primaryKey = primaryKey;
}
@ -66,6 +71,10 @@ public class TemporaryTableColumn {
return sqlTypeName;
}
public Size getSize() {
return size;
}
public boolean isNullable() {
return nullable;
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.dialect.temptable;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.metamodel.mapping.JdbcMapping;
/**
@ -15,12 +16,14 @@ public class TemporaryTableSessionUidColumn extends TemporaryTableColumn {
public TemporaryTableSessionUidColumn(
TemporaryTable containingTable,
JdbcMapping jdbcMapping,
String sqlTypeName) {
String sqlTypeName,
Size size) {
super(
containingTable,
TemporaryTableHelper.SESSION_ID_COLUMN_NAME,
jdbcMapping,
sqlTypeName,
size,
false,
true
);

View File

@ -300,6 +300,7 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
}
identifierGenerators.put( model.getEntityName(), generator );
} );
bootMetamodel.orderColumns( false );
bootMetamodel.validate();
LOG.debug( "Instantiated session factory" );

View File

@ -11,6 +11,7 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Internal;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.Namespace;
import org.hibernate.internal.util.collections.JoinedIterator;
@ -22,6 +23,7 @@ import org.hibernate.internal.util.collections.JoinedList;
public class DenormalizedTable extends Table {
private final Table includedTable;
private List<Column> reorderedColumns;
public DenormalizedTable(
String contributor,
@ -88,11 +90,17 @@ public class DenormalizedTable extends Table {
@Override @Deprecated
public Iterator<Column> getColumnIterator() {
if ( reorderedColumns != null ) {
return reorderedColumns.iterator();
}
return new JoinedIterator<>( includedTable.getColumnIterator(), super.getColumnIterator() );
}
@Override
public Collection<Column> getColumns() {
if ( reorderedColumns != null ) {
return reorderedColumns;
}
return new JoinedList<>( new ArrayList<>( includedTable.getColumns() ), new ArrayList<>( super.getColumns() ) );
}
@ -132,4 +140,14 @@ public class DenormalizedTable extends Table {
public Table getIncludedTable() {
return includedTable;
}
@Internal
@Override
public void reorderColumns(List<Column> columns) {
assert includedTable.getColumns().size() + super.getColumns().size() == columns.size()
&& columns.containsAll( includedTable.getColumns() )
&& columns.containsAll( super.getColumns() )
&& reorderedColumns == null;
this.reorderedColumns = columns;
}
}

View File

@ -6,6 +6,10 @@
*/
package org.hibernate.mapping;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Internal;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.StringHelper;
@ -21,6 +25,8 @@ import org.jboss.logging.Logger;
public class PrimaryKey extends Constraint {
private static final Logger log = Logger.getLogger( PrimaryKey.class );
private int[] originalOrder;
public PrimaryKey(Table table){
setTable( table );
}
@ -98,4 +104,38 @@ public class PrimaryKey extends Constraint {
public String getExportIdentifier() {
return StringHelper.qualify( getTable().getExportIdentifier(), "PK-" + getName() );
}
public List<Column> getColumnsInOriginalOrder() {
if ( originalOrder == null ) {
return getColumns();
}
final List<Column> columns = getColumns();
final Column[] columnsInOriginalOrder = new Column[columns.size()];
for ( int i = 0; i < columnsInOriginalOrder.length; i++ ) {
columnsInOriginalOrder[i] = columns.get( originalOrder[i] );
}
return Arrays.asList( columnsInOriginalOrder );
}
@Internal
public void reorderColumns(List<Column> reorderedColumns) {
if ( originalOrder != null ) {
assert getColumns().equals( reorderedColumns );
return;
}
assert getColumns().size() == reorderedColumns.size() && getColumns().containsAll( reorderedColumns );
final List<Column> columns = getColumns();
originalOrder = new int[columns.size()];
for ( int i = 0; i < reorderedColumns.size(); i++ ) {
final Column reorderedColumn = reorderedColumns.get( i );
originalOrder[i] = columns.indexOf( reorderedColumn );
}
columns.clear();
columns.addAll( reorderedColumns );
}
@Internal
public int[] getOriginalOrder() {
return originalOrder;
}
}

View File

@ -686,6 +686,15 @@ public class Table implements Serializable, ContributableDatabaseObject {
return identifier == null ? null : identifier.render();
}
@Internal
public void reorderColumns(List<Column> columns) {
assert this.columns.size() == columns.size() && this.columns.values().containsAll( columns );
this.columns.clear();
for ( Column column : columns ) {
this.columns.put( column.getCanonicalName(), column );
}
}
public static class ForeignKeyKey implements Serializable {
private final String referencedClassName;
private final Column[] columns;

View File

@ -15,6 +15,7 @@ import java.util.List;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.Internal;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.ContributableDatabaseObject;
@ -40,6 +41,7 @@ public class UserDefinedType implements Serializable, ContributableDatabaseObjec
private Identifier name;
private final Map<String, Column> columns = new LinkedHashMap<>();
private int[] orderMapping;
private String comment;
public UserDefinedType(
@ -255,4 +257,25 @@ public class UserDefinedType implements Serializable, ContributableDatabaseObjec
}
return qualifiedName.append( name.render() ).toString();
}
@Internal
public void reorderColumns(List<Column> columns) {
if ( orderMapping != null ) {
return;
}
orderMapping = new int[columns.size()];
int i = 0;
for ( Column column : this.columns.values() ) {
orderMapping[i++] = columns.indexOf( column );
}
this.columns.clear();
for ( Column column : columns ) {
this.columns.put( column.getCanonicalName(), column );
}
}
@Internal
public int[] getOrderMapping() {
return orderMapping;
}
}

View File

@ -25,19 +25,7 @@ public class EmbeddableInstantiatorRecordStandard extends AbstractPojoInstantiat
super( javaType );
final Class<?>[] componentTypes = ReflectHelper.getRecordComponentTypes( javaType );
this.constructor = resolveConstructor( javaType, componentTypes );
}
protected static Constructor<?> resolveConstructor(Class<?> recordClass, Class<?>[] componentTypes) {
try {
return recordClass.getConstructor( componentTypes );
}
catch (NoSuchMethodException e) {
throw new IllegalArgumentException(
"Could not determine the canonical record constructor for: " + recordClass.getName(),
e
);
}
this.constructor = ReflectHelper.getConstructor( javaType, componentTypes );
}
@Override

View File

@ -240,7 +240,8 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
aggregateColumn.getSqlTypeCode() == SqlTypes.STRUCT
? aggregateColumn.getSqlType()
: null,
this
this,
creationContext
)
);
// Register the resolved type under its struct name and java class name

View File

@ -292,10 +292,7 @@ public class EmbeddedAttributeMapping
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
if ( embeddableMappingType.shouldSelectAggregateMapping()
// We always want to set the whole aggregate mapping in the SET clause if a single expression is given
// This usually happens when we try to set the aggregate to e.g. null or a parameter
|| clause == Clause.SET && embeddableMappingType.getAggregateMapping() != null ) {
if ( embeddableMappingType.getAggregateMapping() != null ) {
final SelectableMapping selection = embeddableMappingType.getAggregateMapping();
final NavigablePath navigablePath = tableGroup.getNavigablePath().append( getNavigableRole().getNavigableName() );
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, getContainingTableExpression() );

View File

@ -334,7 +334,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
final String tableName = determineTableName( table );
subclassTableNames.add( tableName );
String[] key = new String[idColumnSpan];
List<Column> columns = table.getPrimaryKey().getColumns();
List<Column> columns = table.getPrimaryKey().getColumnsInOriginalOrder();
for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = columns.get(k).getQuotedName( dialect );
}
@ -354,7 +354,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
String joinTableName = determineTableName( joinTable );
subclassTableNames.add( joinTableName );
String[] key = new String[idColumnSpan];
List<Column> columns = joinTable.getPrimaryKey().getColumns();
List<Column> columns = joinTable.getPrimaryKey().getColumnsInOriginalOrder();
for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = columns.get(k).getQuotedName( dialect );
}

View File

@ -221,7 +221,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
if ( !table.isAbstractUnionTable() ) {
tableNames.add( determineTableName( table ) );
String[] key = new String[idColumnSpan];
List<Column> columns = table.getPrimaryKey().getColumns();
List<Column> columns = table.getPrimaryKey().getColumnsInOriginalOrder();
for ( int k = 0; k < idColumnSpan; k++ ) {
key[k] = columns.get(k).getQuotedName( dialect );
}

View File

@ -9,6 +9,7 @@ package org.hibernate.type.descriptor.jdbc;
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.WrapperOptions;
@ -17,7 +18,10 @@ import org.hibernate.type.descriptor.WrapperOptions;
*/
public interface AggregateJdbcType extends JdbcType {
AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType);
AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext);
EmbeddableMappingType getEmbeddableMappingType();

View File

@ -13,6 +13,7 @@ import java.sql.SQLException;
import org.hibernate.dialect.JsonHelper;
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.ValueExtractor;
@ -58,7 +59,10 @@ public class JsonJdbcType implements AggregateJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new JsonJdbcType( mappingType );
}

View File

@ -15,6 +15,7 @@ import java.sql.SQLException;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.JsonHelper;
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.ValueExtractor;
@ -65,7 +66,10 @@ public class OracleJsonBlobJdbcType implements AggregateJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new OracleJsonBlobJdbcType( mappingType );
}

View File

@ -12,6 +12,7 @@ import java.sql.ResultSet;
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.ValueExtractor;
@ -34,7 +35,10 @@ public class XmlAsStringJdbcType extends XmlJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new XmlAsStringJdbcType( mappingType );
}
@ -95,7 +99,8 @@ public class XmlAsStringJdbcType extends XmlJdbcType {
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
throws SQLException {
return getObject( statement.getString( name ), options );
}

View File

@ -14,6 +14,7 @@ import java.sql.SQLXML;
import org.hibernate.dialect.XmlHelper;
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.ValueExtractor;
@ -54,7 +55,10 @@ public class XmlJdbcType implements AggregateJdbcType {
}
@Override
public AggregateJdbcType resolveAggregateJdbcType(EmbeddableMappingType mappingType, String sqlType) {
public AggregateJdbcType resolveAggregateJdbcType(
EmbeddableMappingType mappingType,
String sqlType,
RuntimeModelCreationContext creationContext) {
return new XmlJdbcType( mappingType );
}

View File

@ -9,10 +9,9 @@ package org.hibernate.type.descriptor.jdbc.spi;
import java.io.Serializable;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.type.SqlTypes;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -121,7 +120,8 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial
public AggregateJdbcType resolveAggregateDescriptor(
int jdbcTypeCode,
String typeName,
EmbeddableMappingType embeddableMappingType) {
EmbeddableMappingType embeddableMappingType,
RuntimeModelCreationContext creationContext) {
final String registrationKey;
if ( typeName != null ) {
registrationKey = typeName.toLowerCase( Locale.ROOT );
@ -134,7 +134,11 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial
// which are prefixed with the aggregateMapping.
// Since the columnExpression is used as key for mutation parameters, this is important.
// We could get rid of this if ColumnValueParameter drops the ColumnReference
return aggregateJdbcType.resolveAggregateJdbcType( embeddableMappingType, typeName );
return aggregateJdbcType.resolveAggregateJdbcType(
embeddableMappingType,
typeName,
creationContext
);
}
return aggregateJdbcType;
}
@ -154,7 +158,8 @@ public class JdbcTypeRegistry implements JdbcTypeBaseline.BaselineTarget, Serial
final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) descriptor;
final AggregateJdbcType resolvedJdbcType = aggregateJdbcType.resolveAggregateJdbcType(
embeddableMappingType,
typeName
typeName,
creationContext
);
if ( registrationKey != null ) {
aggregateDescriptorMap.put( registrationKey, resolvedJdbcType );

View File

@ -59,6 +59,7 @@ public class EnumeratedSmokeTest extends BaseUnitTestCase {
final MetadataImplementor mappings = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( EntityWithEnumeratedAttributes.class )
.buildMetadata();
mappings.orderColumns( false );
mappings.validate();
final JdbcTypeRegistry jdbcTypeRegistry = mappings.getTypeConfiguration().getJdbcTypeRegistry();

View File

@ -8,10 +8,10 @@ package org.hibernate.orm.test.annotations.id;
import java.util.List;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.tool.schema.internal.SchemaCreatorImpl;
@ -33,10 +33,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@BaseUnitTest
public class JoinColumnOverrideTest {
private static final String expectedSqlPointyTooth = "create table PointyTooth (id numeric(128,0) not null, " +
"bunny_id numeric(128,0), primary key (id))";
private static final String expectedSqlTwinkleToes = "create table TwinkleToes (id numeric(128,0) not null, " +
"bunny_id numeric(128,0), primary key (id))";
private static final String expectedSqlPointyTooth = "create table PointyTooth (bunny_id numeric(128,0), " +
"id numeric(128,0) not null, primary key (id))";
private static final String expectedSqlTwinkleToes = "create table TwinkleToes (bunny_id numeric(128,0), " +
"id numeric(128,0) not null, primary key (id))";
@Test
@TestForIssue(jiraKey = "ANN-748")
@ -46,11 +46,13 @@ public class JoinColumnOverrideTest {
.build();
try {
Metadata metadata = new MetadataSources( ssr )
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( Bunny.class )
.addAnnotatedClass( PointyTooth.class )
.addAnnotatedClass( TwinkleToes.class )
.buildMetadata();
metadata.orderColumns( true );
metadata.validate();
boolean foundPointyToothCreate = false;
boolean foundTwinkleToesCreate = false;

View File

@ -10,10 +10,10 @@ package org.hibernate.orm.test.annotations.id.sequences;
import java.util.List;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.tool.schema.internal.SchemaCreatorImpl;
@ -36,10 +36,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@BaseUnitTest
public class JoinColumnOverrideTest {
private static final String expectedSqlPointyTooth = "create table PointyTooth (id numeric(128,0) not null, " +
"bunny_id numeric(128,0), primary key (id))";
private static final String expectedSqlTwinkleToes = "create table TwinkleToes (id numeric(128,0) not null, " +
"bunny_id numeric(128,0), primary key (id))";
private static final String expectedSqlPointyTooth = "create table PointyTooth (bunny_id numeric(128,0), " +
"id numeric(128,0) not null, primary key (id))";
private static final String expectedSqlTwinkleToes = "create table TwinkleToes (bunny_id numeric(128,0), " +
"id numeric(128,0) not null, primary key (id))";
@Test
@TestForIssue(jiraKey = "ANN-748")
@ -48,11 +48,13 @@ public class JoinColumnOverrideTest {
.applySetting( AvailableSettings.DIALECT, "SQLServer" )
.build();
try {
Metadata metadata = new MetadataSources( ssr )
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( Bunny.class )
.addAnnotatedClass( PointyTooth.class )
.addAnnotatedClass( TwinkleToes.class )
.buildMetadata();
metadata.orderColumns( true );
metadata.validate();
boolean foundPointyToothCreate = false;
boolean foundTwinkleToesCreate = false;

View File

@ -48,6 +48,7 @@ public class InheritedAttributeOverridingTest extends BaseUnitTestCase {
.addAnnotatedClass( B.class )
.buildMetadata();
( (MetadataImplementor) metadata ).orderColumns( false );
( (MetadataImplementor) metadata ).validate();
}
@ -59,6 +60,7 @@ public class InheritedAttributeOverridingTest extends BaseUnitTestCase {
.addAnnotatedClass( D.class )
.buildMetadata();
( (MetadataImplementor) metadata ).orderColumns( false );
( (MetadataImplementor) metadata ).validate();
}

View File

@ -44,6 +44,7 @@ public class DisabledForeignKeyTest extends BaseUnitTestCase {
sources.addAnnotatedClass( ManyToManyTarget.class );
final MetadataImplementor metadata = (MetadataImplementor) sources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport().execute(
@ -84,6 +85,7 @@ public class DisabledForeignKeyTest extends BaseUnitTestCase {
sources.addAnnotatedClass( ManyToManyTarget.class );
final MetadataImplementor metadata = (MetadataImplementor) sources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
// export the schema

View File

@ -150,6 +150,7 @@ public class SequenceNamingStrategyTest {
metadataSources.addAnnotatedClass( entityClass );
final MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
consumer.accept( metadata );

View File

@ -131,6 +131,7 @@ public class TableNamingStrategyTest {
metadataSources.addAnnotatedClass( entityClass );
final MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
consumer.accept( metadata );

View File

@ -53,6 +53,7 @@ public class SequenceExportTest extends BaseUnitTestCase {
.addAnnotatedClass( Entity1.class )
.addAnnotatedClass( Entity2.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
int namespaceCount = 0;
@ -76,6 +77,7 @@ public class SequenceExportTest extends BaseUnitTestCase {
.addAnnotatedClass( Entity3.class )
.addAnnotatedClass( Entity4.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
int namespaceCount = 0;

View File

@ -15,11 +15,10 @@ import jakarta.persistence.Table;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.internal.MetadataImpl;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerator;
@ -46,7 +45,8 @@ public class GeneratedValueTest {
.applySetting( AvailableSettings.HBM2DDL_AUTO, "create-drop" )
.build();
try {
MetadataImpl metadata = (MetadataImpl) new MetadataSources( ssr ).addAnnotatedClass( TheEntity.class ).buildMetadata();
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ).addAnnotatedClass( TheEntity.class ).buildMetadata();
metadata.orderColumns( false );
metadata.validate();
PersistentClass entityBinding = metadata.getEntityBinding( TheEntity.class.getName() );

View File

@ -15,9 +15,9 @@ import jakarta.persistence.Table;
import org.hibernate.annotations.Nationalized;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.internal.MetadataImpl;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.mapping.PersistentClass;
@ -42,7 +42,8 @@ public class AndNationalizedTests extends BaseUnitTestCase {
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build();
try {
Metadata metadata = new MetadataSources( ssr ).addAnnotatedClass( TestEntity.class ).buildMetadata();
( (MetadataImpl) metadata ).validate();
( (MetadataImplementor) metadata ).orderColumns( false );
( (MetadataImplementor) metadata ).validate();
final PersistentClass entityBinding = metadata.getEntityBinding( TestEntity.class.getName() );
final Dialect dialect = metadata.getDatabase().getDialect();

View File

@ -64,6 +64,7 @@ public class CollectionCompositeElementExplicitConversionTest {
.addAnnotatedClass( Traits.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
final PersistentClass entityBinding = metadata.getEntityBinding( Disguise.class.getName() );

View File

@ -31,6 +31,7 @@ public class CompositeNaturalIdMappingTest {
.addAnnotatedClass( PostalCarrier.class )
.addAnnotatedClass( PostalCode.class )
.buildMetadata();
( (MetadataImplementor) meta ).orderColumns( false );
( (MetadataImplementor) meta ).validate();
}
finally {

View File

@ -8,7 +8,6 @@ package org.hibernate.orm.test.mapping.naturalid.compound;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
@ -18,13 +17,10 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.TestForIssue;
import org.junit.jupiter.api.Test;
import org.hamcrest.Matchers;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@ -44,6 +40,7 @@ public class CompoundNaturalIdMappingTest {
.addAnnotatedClass( PostalCarrier.class )
.addAnnotatedClass( Country.class )
.buildMetadata();
( (MetadataImplementor) meta ).orderColumns( false );
( (MetadataImplementor) meta ).validate();
final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) meta.buildSessionFactory();

View File

@ -55,6 +55,7 @@ public class Tests {
metadataBuilder.applyPhysicalNamingStrategy( PhysicalNamingStrategyImpl.INSTANCE );
final Metadata metadata = metadataBuilder.build();
( (MetadataImplementor) metadata ).orderColumns( false );
( (MetadataImplementor) metadata ).validate();
final PersistentClass languageBinding = metadata.getEntityBinding( Language.class.getName() );

View File

@ -46,6 +46,7 @@ public class ColumnDefinitionQuotingTest {
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( E1.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
PersistentClass entityBinding = metadata.getEntityBinding( E1.class.getName() );
@ -72,6 +73,7 @@ public class ColumnDefinitionQuotingTest {
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( E1.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
PersistentClass entityBinding = metadata.getEntityBinding( E1.class.getName() );
@ -108,6 +110,7 @@ public class ColumnDefinitionQuotingTest {
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( E2.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
PersistentClass entityBinding = metadata.getEntityBinding( E2.class.getName() );
@ -134,6 +137,7 @@ public class ColumnDefinitionQuotingTest {
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( E2.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
PersistentClass entityBinding = metadata.getEntityBinding( E2.class.getName() );

View File

@ -172,6 +172,7 @@ public class TestExtraPhysicalTableTypes {
}
metadata = (MetadataImplementor) new MetadataSources( ssr )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -112,6 +112,7 @@ public class AlterTableQuoteDefaultSchemaTest extends AbstractAlterTableQuoteSch
metadataSources.addAnnotatedClass( MyEntity.class );
final MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()
@ -154,6 +155,7 @@ public class AlterTableQuoteDefaultSchemaTest extends AbstractAlterTableQuoteSch
metadataSources.addAnnotatedClass( MyEntityUpdated.class );
final MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -103,6 +103,7 @@ public class AlterTableQuoteSpecifiedSchemaTest extends AbstractAlterTableQuoteS
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( MyEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()
@ -133,6 +134,7 @@ public class AlterTableQuoteSpecifiedSchemaTest extends AbstractAlterTableQuoteS
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( MyEntityUpdated.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -48,6 +48,7 @@ public class CommentGenerationTest {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addResource( resource )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -67,6 +67,7 @@ public class ConnectionsReleaseTest extends BaseUnitTestCase {
metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( Thing.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -86,6 +86,7 @@ public class HANASchemaMigrationTargetScriptCreationTest extends BaseCoreFunctio
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
.addAnnotatedClass( TestEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport().drop( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata );

View File

@ -66,6 +66,7 @@ public class QuotedTableNameSchemaUpdateTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( QuotedTable.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport()

View File

@ -35,6 +35,7 @@ public class QuotedTableNameWithForeignKeysSchemaUpdateTest extends BaseUnitTest
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addResource( "org/hibernate/orm/test/schemaupdate/UserGroup.hbm.xml" )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), metadata );
}

View File

@ -91,6 +91,7 @@ public class SchemaCreationToOutputScriptTest {
.addAnnotatedClass( MyEntity.class )
.addAnnotatedClass( MySecondEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -55,6 +55,7 @@ public class SchemaDropTest extends BaseUnitTestCase implements ExecutionOptions
serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( Environment.getProperties() );
metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
.addAnnotatedClass( MyEntity.class ).buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -89,6 +89,7 @@ public class SchemaDropToOutputScriptTest {
.addAnnotatedClass( MyEntity.class )
.addAnnotatedClass( MySecondEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -52,6 +52,7 @@ public class SchemaExportTest extends BaseUnitTestCase {
metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
.addResource( "org/hibernate/orm/test/schemaupdate/mapping.hbm.xml" )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport().drop( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata );
@ -154,6 +155,7 @@ public class SchemaExportTest extends BaseUnitTestCase {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
.addResource( "org/hibernate/orm/test/schemaupdate/mapping2.hbm.xml" )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
final SchemaExport schemaExport = new SchemaExport();

View File

@ -72,6 +72,7 @@ public class SchemaMigrationTargetScriptCreationTest extends BaseCoreFunctionalT
MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
.addAnnotatedClass( TestEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport().drop( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata );

View File

@ -104,6 +104,7 @@ public class SchemaMigrationToOutputScriptTest {
.addAnnotatedClass( MyEntity.class )
.addAnnotatedClass( MySecondEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -49,6 +49,7 @@ public class SchemaUpdateDelimiterTest {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( TestEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -49,6 +49,7 @@ public class SchemaUpdateFormatterTest extends BaseUnitTestCase {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( TestEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -48,6 +48,7 @@ public class SchemaUpdateGeneratingOnlyScriptFileTest {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( TestEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -13,8 +13,6 @@ import jakarta.persistence.ConstraintMode;
import jakarta.persistence.Entity;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SecondaryTable;
import org.hibernate.boot.MetadataSources;
@ -66,6 +64,7 @@ public class SchemaUpdateJoinColumnNoConstraintSecondaryTableTest extends BaseUn
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( Parent.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -64,6 +64,7 @@ public class SchemaUpdateJoinColumnNoConstraintSecondaryTablesTest extends BaseU
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( Parent.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -56,6 +56,7 @@ public class SchemaUpdateJoinColumnNoConstraintTest extends BaseUnitTestCase {
.addAnnotatedClass( Parent.class )
.addAnnotatedClass( Child.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -124,6 +124,7 @@ public class SchemaUpdateSQLServerTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( InheritanceSecondChildEntity.class );
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -111,6 +111,7 @@ public class SchemaUpdateTest {
metadataSources.addAnnotatedClass( InheritanceSecondChildEntity.class );
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
// Databases that use case-insensitive quoted identifiers need to be skipped.

View File

@ -62,6 +62,7 @@ public class SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameT
metadataSources.addAnnotatedClass( AnotherTestEntity.class );
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -63,6 +63,7 @@ public class SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest {
metadataSources.addAnnotatedClass( TestEntity.class );
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -61,6 +61,7 @@ public class SchemaUpdateWithViewsTest extends BaseNonConfigCoreFunctionalTestCa
metadata = (MetadataImplementor) new MetadataSources( serviceRegistry )
.addAnnotatedClass( MyEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -48,6 +48,7 @@ public class SequenceReadingTest extends BaseCoreFunctionalTestCase {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( MyEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
try {

View File

@ -54,6 +54,7 @@ public class SpannerSchemaCreationColumnTypesTest {
metadataSources.addAnnotatedClass( TestEntity.class );
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

View File

@ -106,6 +106,7 @@ public class SqlServerQuoteSchemaTest extends BaseCoreFunctionalTestCase {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( MyEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()
@ -136,6 +137,7 @@ public class SqlServerQuoteSchemaTest extends BaseCoreFunctionalTestCase {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( MyEntityUpdated.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -60,6 +60,7 @@ public class ColumnLengthTest extends BaseUnitTestCase {
.addAnnotatedClass( Employee.class )
.addAnnotatedClass( Dependent.class )
.buildMetadata();
metadata.orderColumns( true );
metadata.validate();
}
@ -80,7 +81,7 @@ public class ColumnLengthTest extends BaseUnitTestCase {
assertTrue( checkCommandIsGenerated(
commands,
"create table DEPENDENT (name varchar(255) not null, FK1 varchar(32) not null, FK2 varchar(10) not null, primary key (FK1, FK2, name));"
"create table DEPENDENT (FK2 varchar(10) not null, FK1 varchar(32) not null, name varchar(255) not null, primary key (FK1, FK2, name));"
) );
}

View File

@ -65,6 +65,7 @@ public class ForeignKeyDropTest extends BaseUnitTestCase {
.addAnnotatedClass( ParentEntity.class )
.addAnnotatedClass( ChildEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
schemaExport = new SchemaExport().setHaltOnError( false ).setOutputFile( output.getAbsolutePath() );
}

View File

@ -158,6 +158,7 @@ public class ForeignKeyGenerationTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( c );
}
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport()
.setHaltOnError( true )

View File

@ -42,6 +42,7 @@ public class ForeignKeyMigrationTest extends BaseUnitTestCase {
.addAnnotatedClass( Box.class )
.addAnnotatedClass( Thing.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
// first create the schema...

View File

@ -122,6 +122,7 @@ public class JoinedInheritanceForeignKeyTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( c );
}
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport()
.setHaltOnError( true )

View File

@ -50,6 +50,7 @@ public class SchemaUpdateWithKeywordAutoQuotingEnabledTest extends BaseUnitTestC
final MetadataSources metadataSources = new MetadataSources( ssr );
metadataSources.addAnnotatedClass( Match.class );
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
try {
createSchema();

View File

@ -87,6 +87,7 @@ public class CrossSchemaForeignKeyGenerationTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport().setHaltOnError( true )
@ -110,6 +111,7 @@ public class CrossSchemaForeignKeyGenerationTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport()
@ -136,6 +138,7 @@ public class CrossSchemaForeignKeyGenerationTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
final Database database = metadata.getDatabase();
@ -205,6 +208,7 @@ public class CrossSchemaForeignKeyGenerationTest extends BaseUnitTestCase {
metadataSources.addAnnotatedClass( SchemaTwoEntity.class );
MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
final HibernateSchemaManagementTool tool = (HibernateSchemaManagementTool) ssr.getService( SchemaManagementTool.class );

View File

@ -58,6 +58,7 @@ public abstract class AbstractForeignKeyDefinitionTest extends BaseUnitTestCase
metadataSources.addAnnotatedClass( c );
}
metadata = (MetadataImplementor) metadataSources.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaExport()
.setHaltOnError( true )

View File

@ -46,6 +46,7 @@ public class IdBagSequenceTest extends BaseUnitTestCase {
final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr )
.addResource( "org/hibernate/orm/test/schemaupdate/idbag/Mappings.hbm.xml" )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
new SchemaUpdate()

View File

@ -56,6 +56,7 @@ public class SequenceGenerationTest extends BaseUnitTestCase {
metadata = (MetadataImplementor) new MetadataSources( ssr )
.addAnnotatedClass( TestEntity.class )
.buildMetadata();
metadata.orderColumns( false );
metadata.validate();
}

Some files were not shown because too many files have changed in this diff Show More