diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java index 9b27ddfc1a12..96ebf9a071f6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java @@ -4,6 +4,9 @@ */ package org.hibernate.metamodel.mapping; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.hibernate.engine.jdbc.Size; + import java.util.function.BiConsumer; import java.util.function.IntFunction; @@ -25,7 +28,7 @@ public interface SelectableConsumer { /** * Simple form of visitation over a number of columns by name, using - * a separate {@link SelectableMappings} as a base for additional details. + * a separate {@link JdbcMappingContainer} as a base for additional details. *

* Intended for use in visiting table keys, where we know JdbcMappings, etc. * from the identifier. @@ -44,6 +47,144 @@ default void accept(String tableName, JdbcMappingContainer base, String[] column mutableSelectableMapping.forEach( this::accept ); } + /** + * Simple form of visitation over a number of columns by name, using + * a separate {@link SelectableMappings} as a base for additional details. + *

+ * Intended for use in visiting table keys, where we know JdbcMappings, etc. + * from the identifier. + *

+ * The expectation here is for the following details to be available:

+ */ + default void accept(SelectableMappings base, String tableName, String[] columnNames) { + class SelectableMappingIterator implements SelectableMapping { + private final String tableName; + private final SelectableMappings delegate; + private final String[] columnNames; + + private int index; + + public SelectableMappingIterator(String tableName, SelectableMappings delegate, String[] columnNames) { + this.tableName = tableName; + this.delegate = delegate; + this.columnNames = columnNames; + assert delegate.getJdbcTypeCount() == columnNames.length; + } + + private void forEach(BiConsumer consumer) { + for ( index = 0; index < columnNames.length; index++ ) { + consumer.accept( index, this ); + } + } + + @Override + public String getContainingTableExpression() { + return tableName; + } + + @Override + public String getSelectionExpression() { + return columnNames[index]; + } + + @Override + public @Nullable String getCustomReadExpression() { + return null; + } + + @Override + public @Nullable String getCustomWriteExpression() { + return null; + } + + private SelectableMapping getDelegate() { + return delegate.getSelectable( index ); + } + + @Override + public String getSelectableName() { + return getDelegate().getSelectableName(); + } + + @Override + public SelectablePath getSelectablePath() { + return getDelegate().getSelectablePath(); + } + + @Override + public boolean isFormula() { + return getDelegate().isFormula(); + } + + @Override + public boolean isNullable() { + return getDelegate().isNullable(); + } + + @Override + public boolean isInsertable() { + return getDelegate().isInsertable(); + } + + @Override + public boolean isUpdateable() { + return getDelegate().isUpdateable(); + } + + @Override + public boolean isPartitioned() { + return getDelegate().isPartitioned(); + } + + @Override + public @Nullable String getColumnDefinition() { + return getDelegate().getColumnDefinition(); + } + + @Override + public @Nullable Long getLength() { + return getDelegate().getLength(); + } + + @Override + public @Nullable Integer getPrecision() { + return getDelegate().getPrecision(); + } + + @Override + public @Nullable Integer getScale() { + return getDelegate().getScale(); + } + + @Override + public @Nullable Integer getTemporalPrecision() { + return getDelegate().getTemporalPrecision(); + } + + @Override + public boolean isLob() { + return getDelegate().isLob(); + } + + @Override + public JdbcMapping getJdbcMapping() { + return getDelegate().getJdbcMapping(); + } + + @Override + public Size toSize() { + return getDelegate().toSize(); + } + } + + final SelectableMappingIterator mutableSelectableMapping = new SelectableMappingIterator( tableName, base, columnNames ); + mutableSelectableMapping.forEach( this::accept ); + } class MutableSelectableMapping implements SelectableMapping { private final String tableName; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java index fb43a87ec780..2a8444061068 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java @@ -25,8 +25,8 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select private final String containingTableExpression; private final String selectionExpression; private final SelectablePath selectablePath; - private final String customReadExpression; - private final String customWriteExpression; + private final @Nullable String customReadExpression; + private final @Nullable String customWriteExpression; private final boolean isLob; private final boolean nullable; private final boolean insertable; @@ -37,14 +37,14 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select public SelectableMappingImpl( String containingTableExpression, String selectionExpression, - SelectablePath selectablePath, - String customReadExpression, - String customWriteExpression, - String columnDefinition, - Long length, - Integer precision, - Integer scale, - Integer temporalPrecision, + @Nullable SelectablePath selectablePath, + @Nullable String customReadExpression, + @Nullable String customWriteExpression, + @Nullable String columnDefinition, + @Nullable Long length, + @Nullable Integer precision, + @Nullable Integer scale, + @Nullable Integer temporalPrecision, boolean isLob, boolean nullable, boolean insertable, @@ -55,7 +55,7 @@ public SelectableMappingImpl( super( columnDefinition, length, precision, scale, temporalPrecision, jdbcMapping ); assert selectionExpression != null; // Save memory by using interned strings. Probability is high that we have multiple duplicate strings - this.containingTableExpression = containingTableExpression == null ? null : containingTableExpression.intern(); + this.containingTableExpression = containingTableExpression.intern(); this.selectionExpression = selectionExpression.intern(); this.selectablePath = selectablePath == null ? new SelectablePath( selectionExpression ) : selectablePath; this.customReadExpression = customReadExpression == null ? null : customReadExpression.intern(); @@ -241,7 +241,7 @@ public String getSelectionExpression() { @Override public String getSelectableName() { - return selectablePath == null ? null : selectablePath.getSelectableName(); + return selectablePath.getSelectableName(); } @Override @@ -250,17 +250,12 @@ public SelectablePath getSelectablePath() { } @Override - public String getCustomReadExpression() { + public @Nullable String getCustomReadExpression() { return customReadExpression; } @Override - public String getCustomWriteExpression() { - return customWriteExpression; - } - - @Override - public String getWriteExpression() { + public @Nullable String getCustomWriteExpression() { return customWriteExpression; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SoftDeleteMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SoftDeleteMappingImpl.java index 6a985eec49dd..d54f5471a3cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SoftDeleteMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SoftDeleteMappingImpl.java @@ -214,41 +214,19 @@ public Predicate createNonDeletedRestriction(TableReference tableReference, SqlE @Override public ColumnValueBinding createNonDeletedValueBinding(ColumnReference softDeleteColumnReference) { - final ColumnWriteFragment nonDeletedFragment; - if ( strategy == SoftDeleteType.TIMESTAMP ) { - nonDeletedFragment = new ColumnWriteFragment( - null, - Collections.emptyList(), - jdbcMapping - ); - } - else { - nonDeletedFragment = new ColumnWriteFragment( - nonDeletedLiteralText, - Collections.emptyList(), - jdbcMapping - ); - } + final var nonDeletedFragment = + strategy == SoftDeleteType.TIMESTAMP + ? new ColumnWriteFragment( null, Collections.emptyList(), this ) + : new ColumnWriteFragment( nonDeletedLiteralText, Collections.emptyList(), this ); return new ColumnValueBinding( softDeleteColumnReference, nonDeletedFragment ); } @Override public ColumnValueBinding createDeletedValueBinding(ColumnReference softDeleteColumnReference) { - final ColumnWriteFragment deletedFragment; - if ( strategy == SoftDeleteType.TIMESTAMP ) { - deletedFragment = new ColumnWriteFragment( - currentTimestampFunctionName, - Collections.emptyList(), - getJdbcMapping() - ); - } - else { - deletedFragment = new ColumnWriteFragment( - deletedLiteralText, - Collections.emptyList(), - jdbcMapping - ); - } + final ColumnWriteFragment deletedFragment = + strategy == SoftDeleteType.TIMESTAMP + ? new ColumnWriteFragment( currentTimestampFunctionName, Collections.emptyList(), this ) + : new ColumnWriteFragment( deletedLiteralText, Collections.emptyList(), this ); return new ColumnValueBinding( softDeleteColumnReference, deletedFragment ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index e15310d71a18..e10581830d46 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -98,7 +98,6 @@ import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.expression.AliasedExpression; -import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.predicate.Predicate; @@ -109,7 +108,6 @@ import org.hibernate.sql.model.TableMapping; import org.hibernate.sql.model.TableMapping.MutationDetails; import org.hibernate.sql.model.ast.ColumnValueBinding; -import org.hibernate.sql.model.ast.ColumnValueParameter; import org.hibernate.sql.model.ast.ColumnValueParameterList; import org.hibernate.sql.model.ast.ColumnWriteFragment; import org.hibernate.sql.model.ast.MutatingTableReference; @@ -134,6 +132,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -1753,7 +1752,7 @@ public RestrictedTableMutation generateDeleteAllAst(Mutat final ColumnValueParameterList parameterBinders = new ColumnValueParameterList( tableReference, ParameterUsage.RESTRICT, keyColumnCount ); final java.util.List restrictionBindings = arrayList( keyColumnCount ); - applyKeyRestrictions( tableReference, parameterBinders, restrictionBindings ); + applyKeyRestrictions( parameterBinders, restrictionBindings ); //noinspection unchecked,rawtypes return (RestrictedTableMutation) new TableDeleteStandard( @@ -1768,27 +1767,24 @@ public RestrictedTableMutation generateDeleteAllAst(Mutat } protected void applyKeyRestrictions( - MutatingTableReference tableReference, ColumnValueParameterList parameterList, - java.util.List restrictionBindings) { - - final ForeignKeyDescriptor fkDescriptor = getAttributeMapping().getKeyDescriptor(); - assert fkDescriptor != null; - - fkDescriptor.getKeyPart().forEachSelectable( parameterList ); - for ( ColumnValueParameter columnValueParameter : parameterList ) { - final ColumnReference columnReference = columnValueParameter.getColumnReference(); + List restrictionBindings) { + final var foreignKeyDescriptor = getAttributeMapping().getKeyDescriptor(); + assert foreignKeyDescriptor != null; + foreignKeyDescriptor.getKeyPart().forEachSelectable( (selectionIndex, selectableMapping) -> { + final var columnValueParameter = parameterList.addColumValueParameter( selectableMapping ); + final var columnReference = columnValueParameter.getColumnReference(); restrictionBindings.add( new ColumnValueBinding( columnReference, new ColumnWriteFragment( "?", columnValueParameter, - columnReference.getJdbcMapping() + selectableMapping ) ) ); - } + }); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java index 8f8a2a2ac690..d53f7e0503dd 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java @@ -217,7 +217,7 @@ public RestrictedTableMutation generateDeleteAllAst(Mutat keyColumnCount ); final java.util.List restrictionBindings = arrayList( keyColumnCount ); - applyKeyRestrictions( tableReference, parameterBinders, restrictionBindings ); + applyKeyRestrictions( parameterBinders, restrictionBindings ); final ColumnReference softDeleteColumn = new ColumnReference( tableReference, softDeleteMapping ); final ColumnValueBinding nonDeletedBinding = softDeleteMapping.createNonDeletedValueBinding( softDeleteColumn ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java index 87210cbb1c6c..f492340d2f19 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java @@ -61,7 +61,6 @@ import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.MutationType; import org.hibernate.sql.model.ast.ColumnValueBinding; -import org.hibernate.sql.model.ast.ColumnValueParameter; import org.hibernate.sql.model.ast.ColumnValueParameterList; import org.hibernate.sql.model.ast.ColumnWriteFragment; import org.hibernate.sql.model.ast.MutatingTableReference; @@ -307,26 +306,26 @@ public RestrictedTableMutation generateDeleteAllAst(Mutat ); final List keyRestrictionBindings = arrayList( keyColumnCount ); final List valueBindings = arrayList( valuesCount ); - fkDescriptor.getKeyPart().forEachSelectable( parameterBinders ); - for ( ColumnValueParameter columnValueParameter : parameterBinders ) { - final ColumnReference columnReference = columnValueParameter.getColumnReference(); + fkDescriptor.getKeyPart().forEachSelectable( (selectionIndex, selectableMapping) -> { + final var columnValueParameter = parameterBinders.addColumValueParameter( selectableMapping ); + final var columnReference = columnValueParameter.getColumnReference(); keyRestrictionBindings.add( new ColumnValueBinding( columnReference, new ColumnWriteFragment( "?", columnValueParameter, - columnReference.getJdbcMapping() + selectableMapping ) ) ); valueBindings.add( new ColumnValueBinding( columnReference, - new ColumnWriteFragment( "null", columnReference.getJdbcMapping() ) + new ColumnWriteFragment( "null", selectableMapping ) ) ); - } + } ); if ( hasIndex() && !indexContainsFormula ) { getAttributeMapping().getIndexDescriptor().forEachSelectable( (selectionIndex, selectableMapping) -> { @@ -335,7 +334,7 @@ public RestrictedTableMutation generateDeleteAllAst(Mutat } valueBindings.add( new ColumnValueBinding( new ColumnReference( tableReference, selectableMapping ), - new ColumnWriteFragment( "null", selectableMapping.getJdbcMapping() ) + new ColumnWriteFragment( "null", selectableMapping ) ) ); } ); } @@ -494,10 +493,8 @@ public RestrictedTableMutation generateDeleteRowAst(Mutat if ( selectable.isUpdateable() ) { // set null updateBuilder.addValueColumn( - selectable.getSelectionExpression(), NULL, - selectable.getJdbcMapping(), - selectable.isLob() + selectable ); } // restrict @@ -514,10 +511,8 @@ public RestrictedTableMutation generateDeleteRowAst(Mutat final SelectableMapping selectable = indexDescriptor.getSelectable( i ); if ( selectable.isUpdateable() ) { updateBuilder.addValueColumn( - selectable.getSelectionExpression(), NULL, - selectable.getJdbcMapping(), - selectable.isLob() + selectable ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 3217e9650e34..908842325eb3 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -3342,10 +3342,7 @@ protected EntityTableMapping[] buildTableMappings() { .accept( (selectionIndex, selectableMapping) -> { keyColumns.add( new EntityTableMapping.KeyColumn( tableExpression, - selectableMapping.getSelectionExpression(), - selectableMapping.getWriteExpression(), - selectableMapping.isFormula(), - selectableMapping.getJdbcMapping() + selectableMapping ) ); } ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 99d45013dc7a..705af81539ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -680,8 +680,8 @@ protected void visitMutabilityOrderedTables(MutabilityOrderedTableConsumer consu tableName, tableIndex, () -> (columnConsumer) -> columnConsumer.accept( - tableName, getIdentifierMapping(), + tableName, naturalOrderTableKeyColumns[tableIndex] ) ); @@ -749,24 +749,25 @@ public String getDiscriminatorAlias() { public void addDiscriminatorToInsertGroup(MutationGroupBuilder insertGroupBuilder) { if ( explicitDiscriminatorColumnName != null ) { final TableInsertBuilder tableInsertBuilder = insertGroupBuilder.getTableDetailsBuilder( getRootTableName() ); - final String discriminatorValueToUse; - if ( discriminatorValue == NULL_DISCRIMINATOR ) { - discriminatorValueToUse = "null"; - } - else if ( discriminatorValue == NOT_NULL_DISCRIMINATOR ) { - discriminatorValueToUse = "not null"; - } - else { - discriminatorValueToUse = discriminatorSQLString; - } tableInsertBuilder.addValueColumn( - explicitDiscriminatorColumnName, - discriminatorValueToUse, - getDiscriminatorMapping().getJdbcMapping() + getDiscriminatorValueString(), + getDiscriminatorMapping() ); } } + private String getDiscriminatorValueString() { + if ( discriminatorValue == NULL_DISCRIMINATOR ) { + return "null"; + } + else if ( discriminatorValue == NOT_NULL_DISCRIMINATOR ) { + return "not null"; + } + else { + return discriminatorSQLString; + } + } + @Override public String[] getPropertySpaces() { return spaces; // don't need subclass tables, because they can't appear in conditions diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index 28cf8e4fcd48..22ad424db7a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -480,9 +480,8 @@ public void addDiscriminatorToInsertGroup(MutationGroupBuilder insertGroupBuilde if ( discriminatorInsertable ) { final TableInsertBuilder tableInsertBuilder = insertGroupBuilder.getTableDetailsBuilder( getRootTableName() ); tableInsertBuilder.addValueColumn( - discriminatorColumnName, discriminatorValue == NULL_DISCRIMINATOR ? NULL : discriminatorSQLValue, - getDiscriminatorMapping().getJdbcMapping() + getDiscriminatorMapping() ); } } @@ -620,8 +619,8 @@ protected void visitMutabilityOrderedTables(MutabilityOrderedTableConsumer consu tableName, tableIndex, () -> columnConsumer -> columnConsumer.accept( - tableName, getIdentifierMapping(), + tableName, keyColumnNames[tableIndex] ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index 8608ecc1ff14..47ad69c3f843 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -387,7 +387,11 @@ protected void visitMutabilityOrderedTables(MutabilityOrderedTableConsumer consu consumer.consume( tableName, 0, - () -> columnConsumer -> columnConsumer.accept( tableName, getIdentifierMapping(), getIdentifierColumnNames() ) + () -> columnConsumer -> columnConsumer.accept( + getIdentifierMapping(), + tableName, + getIdentifierColumnNames() + ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java index 240af8e19dd5..4f9e650bb124 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java @@ -134,10 +134,8 @@ protected void handleValueGeneration( final String tableName = entityPersister.physicalTableNameForMutation( mapping ); final ColumnValuesTableMutationBuilder tableUpdateBuilder = mutationGroupBuilder.findTableDetailsBuilder( tableName ); tableUpdateBuilder.addValueColumn( - mapping.getSelectionExpression(), writePropertyValue ? "?" : columnValues[j], - mapping.getJdbcMapping(), - mapping.isLob() + mapping ); } ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java index 6e3d99c6e706..6e70ce3141b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java @@ -12,12 +12,12 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.jdbc.Expectation; -import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMappings; import org.hibernate.metamodel.mapping.TableDetails; +import org.hibernate.metamodel.mapping.internal.SelectableMappingImpl; import org.hibernate.sql.model.MutationType; import org.hibernate.sql.model.TableMapping; @@ -302,113 +302,33 @@ public int forEachSelectable(int offset, SelectableConsumer consumer) { } } - public static class KeyColumn implements TableDetails.KeyColumn { - private final String tableName; - private final String columnName; - private final String writeExpression; - - private final boolean formula; - - private final JdbcMapping jdbcMapping; - - public KeyColumn( - String tableName, - String columnName, - String writeExpression, - boolean formula, - JdbcMapping jdbcMapping) { - this.tableName = tableName; - this.columnName = columnName; - this.writeExpression = writeExpression; - this.formula = formula; - this.jdbcMapping = jdbcMapping; - } - - public String getColumnName() { - return columnName; - } - - @Override - public String getContainingTableExpression() { - return tableName; - } - - @Override - public String getWriteExpression() { - return writeExpression; - } - - @Override - public String getSelectionExpression() { - return columnName; - } - - @Override - public JdbcMapping getJdbcMapping() { - return jdbcMapping; - } - - @Override - public boolean isFormula() { - return formula; - } - - @Override - public boolean isNullable() { - // keys are never nullable - return false; - } - - @Override - public boolean isInsertable() { - // keys are always insertable, unless this "column" is a formula - return !formula; - } - - @Override - public boolean isUpdateable() { - // keys are never updateable - return false; - } - - @Override - public boolean isPartitioned() { - return false; - } - - @Override - public String getColumnDefinition() { - return null; - } - - @Override - public Long getLength() { - return null; - } - - @Override - public Integer getPrecision() { - return null; - } - - @Override - public Integer getScale() { - return null; - } - - @Override - public Integer getTemporalPrecision() { - return null; - } - - @Override - public String getCustomReadExpression() { - return null; + public static class KeyColumn extends SelectableMappingImpl implements TableDetails.KeyColumn { + + public KeyColumn(String tableName, SelectableMapping originalMapping) { + super( + tableName, + originalMapping.getSelectionExpression(), + null, // Leads to construction of a fresh path based on selection expression + originalMapping.getCustomReadExpression(), + originalMapping.getCustomWriteExpression(), + originalMapping.getColumnDefinition(), + originalMapping.getLength(), + originalMapping.getPrecision(), + originalMapping.getScale(), + originalMapping.getTemporalPrecision(), + originalMapping.isLob(), + originalMapping.isNullable(), + originalMapping.isInsertable(), + originalMapping.isUpdateable(), + originalMapping.isPartitioned(), + originalMapping.isFormula(), + originalMapping.getJdbcMapping() + ); } @Override - public String getCustomWriteExpression() { - return null; + public String getColumnName() { + return getSelectionExpression(); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java index 887435ece2d4..d946be24f32f 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java @@ -26,8 +26,8 @@ import org.hibernate.generator.values.GeneratedValuesMutationDelegate; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMappingsList; -import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.metamodel.mapping.TableDetails; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.MutationOperationGroup; @@ -431,19 +431,16 @@ else if ( isValueGenerationInSql( generator, factory.getJdbcServices().getDialec assert entityPersister().getInsertDelegate() != null; final OnExecutionGenerator generator = (OnExecutionGenerator) entityPersister().getGenerator(); if ( generator.referenceColumnsInSql( dialect ) ) { - final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping(); final String[] columnValues = generator.getReferencedColumnValues( dialect ); if ( columnValues != null ) { - tableMapping.getKeyMapping().forEachKeyColumn( (i, column) -> tableInsertBuilder.addKeyColumn( - column.getColumnName(), - columnValues[i], - identifierMapping.getJdbcMapping() - ) ); + assert columnValues.length == 1; + assert tableMapping.getKeyMapping().getColumnCount() == 1; + tableInsertBuilder.addKeyColumn( columnValues[0], tableMapping.getKeyMapping().getKeyColumn( 0 ) ); } } } else { - tableMapping.getKeyMapping().forEachKeyColumn( tableInsertBuilder::addKeyColumn ); + tableMapping.getKeyMapping().forEachKeyColumn( (TableDetails.KeyColumnConsumer) tableInsertBuilder::addKeyColumn ); } } ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java index c12d8967f235..6b3f33a5e013 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java @@ -135,7 +135,6 @@ import org.hibernate.sql.exec.internal.AbstractJdbcParameter; import org.hibernate.sql.exec.internal.JdbcOperationQueryInsertImpl; import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl; -import org.hibernate.sql.exec.internal.SqlTypedMappingJdbcParameter; import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.JdbcLockStrategy; import org.hibernate.sql.exec.spi.JdbcOperation; @@ -5595,10 +5594,10 @@ protected void renderCasted(Expression expression) { final List arguments = new ArrayList<>( 2 ); arguments.add( expression ); final CastTarget castTarget; - if ( expression instanceof SqlTypedMappingJdbcParameter parameter ) { - final SqlTypedMapping sqlTypedMapping = parameter.getSqlTypedMapping(); + if ( expression instanceof SqlTypedExpression sqlTypedExpression ) { + final SqlTypedMapping sqlTypedMapping = sqlTypedExpression.getSqlTypedMapping(); castTarget = new CastTarget( - parameter.getJdbcMapping(), + sqlTypedMapping.getJdbcMapping(), sqlTypedMapping.getColumnDefinition(), sqlTypedMapping.getLength(), sqlTypedMapping.getTemporalPrecision() != null diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTypedExpression.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTypedExpression.java new file mode 100644 index 000000000000..3099bb357ed5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTypedExpression.java @@ -0,0 +1,14 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.sql.ast.tree.expression; + +import org.hibernate.metamodel.mapping.SqlTypedMapping; + +/** + * An expression that has SQL type information. + */ +public interface SqlTypedExpression extends Expression { + SqlTypedMapping getSqlTypedMapping(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/SqlTypedMappingJdbcParameter.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/SqlTypedMappingJdbcParameter.java index 5e80bc9e9c8b..87bdad615f62 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/SqlTypedMappingJdbcParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/SqlTypedMappingJdbcParameter.java @@ -6,11 +6,12 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.metamodel.mapping.SqlTypedMapping; +import org.hibernate.sql.ast.tree.expression.SqlTypedExpression; /** * @author Steve Ebersole */ -public class SqlTypedMappingJdbcParameter extends AbstractJdbcParameter { +public class SqlTypedMappingJdbcParameter extends AbstractJdbcParameter implements SqlTypedExpression { private final SqlTypedMapping sqlTypedMapping; @@ -24,6 +25,7 @@ public SqlTypedMappingJdbcParameter(SqlTypedMapping sqlTypedMapping, @Nullable I this.sqlTypedMapping = sqlTypedMapping; } + @Override public SqlTypedMapping getSqlTypedMapping() { return sqlTypedMapping; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueBindingList.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueBindingList.java index 9a87e85e1560..10aa1a9e42ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueBindingList.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueBindingList.java @@ -6,6 +6,7 @@ import java.util.ArrayList; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.Incubating; import org.hibernate.Internal; import org.hibernate.engine.jdbc.mutation.ParameterUsage; @@ -38,12 +39,12 @@ public Object clone() { @Override public void consume(int valueIndex, Object value, SelectableMapping jdbcValueMapping) { - final ColumnValueBinding columnValueBinding = createValueBinding( - jdbcValueMapping.getSelectionExpression(), - value == null ? null : jdbcValueMapping.getWriteExpression(), - jdbcValueMapping.getJdbcMapping() - ); - add( columnValueBinding ); + if ( value == null ) { + addNullRestriction( jdbcValueMapping ); + } + else { + addRestriction( jdbcValueMapping ); + } } @Internal @Incubating @@ -51,22 +52,18 @@ public void addRestriction(ColumnValueBinding valueBinding) { add( valueBinding ); } - public void addNullRestriction(SelectableMapping column) { - add( createValueBinding( column.getSelectionExpression(), null, column.getJdbcMapping() ) ); + public void addRestriction(SelectableMapping column) { + add( createValueBinding( column, column.getWriteExpression() ) ); } - public void addRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { - add( createValueBinding( columnName, columnWriteFragment, jdbcMapping ) ); + public void addNullRestriction(SelectableMapping column) { + add( createValueBinding( column, null ) ); } - protected ColumnValueBinding createValueBinding( - String columnName, - String customWriteExpression, - JdbcMapping jdbcMapping) { + protected ColumnValueBinding createValueBinding(SelectableMapping column, @Nullable String customWriteExpression) { return ColumnValueBindingBuilder.createValueBinding( - columnName, customWriteExpression, - jdbcMapping, + column, mutatingTable, parameterUsage, parameters::apply diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueParameterList.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueParameterList.java index 9d1a6b885fbc..56e58f77eab8 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueParameterList.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnValueParameterList.java @@ -35,12 +35,14 @@ public Object clone() { @Override public void accept(int selectionIndex, SelectableMapping selectableMapping) { - add( - new ColumnValueParameter( - new ColumnReference( tableReference, selectableMapping ), - parameterUsage - ) - ); + addColumValueParameter( selectableMapping ); + } + + public ColumnValueParameter addColumValueParameter(SelectableMapping selectableMapping) { + final ColumnValueParameter columnValueParameter = + new ColumnValueParameter( new ColumnReference( tableReference, selectableMapping ), parameterUsage ); + add( columnValueParameter ); + return columnValueParameter; } public void apply(Object parameterRef) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnWriteFragment.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnWriteFragment.java index b43df4d58281..10413ab8fb93 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnWriteFragment.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/ColumnWriteFragment.java @@ -11,8 +11,10 @@ import org.hibernate.annotations.ColumnTransformer; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.SelectableMapping; +import org.hibernate.metamodel.mapping.SqlTypedMapping; import org.hibernate.sql.ast.SqlAstWalker; -import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.sql.ast.tree.expression.SqlTypedExpression; /** * Models a column's value expression within the SQL AST. Used to model:
    @@ -24,24 +26,24 @@ * * @author Steve Ebersole */ -public class ColumnWriteFragment implements Expression { +public class ColumnWriteFragment implements SqlTypedExpression { private final String fragment; private final List parameters; - private final JdbcMapping jdbcMapping; + private final SelectableMapping selectableMapping; - public ColumnWriteFragment(String fragment, JdbcMapping jdbcMapping) { - this( fragment, Collections.emptyList(), jdbcMapping ); + public ColumnWriteFragment(String fragment, SelectableMapping selectableMapping) { + this( fragment, Collections.emptyList(), selectableMapping ); } - public ColumnWriteFragment(String fragment, ColumnValueParameter parameter, JdbcMapping jdbcMapping) { - this( fragment, Collections.singletonList( parameter ), jdbcMapping ); + public ColumnWriteFragment(String fragment, ColumnValueParameter parameter, SelectableMapping selectableMapping) { + this( fragment, Collections.singletonList( parameter ), selectableMapping ); assert !fragment.contains( "?" ) || parameter != null; } - public ColumnWriteFragment(String fragment, List parameters, JdbcMapping jdbcMapping) { + public ColumnWriteFragment(String fragment, List parameters, SelectableMapping selectableMapping) { this.fragment = fragment; this.parameters = parameters; - this.jdbcMapping = jdbcMapping; + this.selectableMapping = selectableMapping; } public String getFragment() { @@ -52,9 +54,14 @@ public Collection getParameters() { return parameters; } + @Override + public SqlTypedMapping getSqlTypedMapping() { + return selectableMapping; + } + @Override public JdbcMapping getExpressionType() { - return jdbcMapping; + return selectableMapping.getJdbcMapping(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractRestrictedTableMutationBuilder.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractRestrictedTableMutationBuilder.java index 8142d1f30acc..5a634ad1dbb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractRestrictedTableMutationBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractRestrictedTableMutationBuilder.java @@ -6,7 +6,6 @@ import org.hibernate.engine.jdbc.mutation.ParameterUsage; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.MutationTarget; @@ -66,8 +65,8 @@ public void addNonKeyRestriction(ColumnValueBinding valueBinding) { } @Override - public void addKeyRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { - keyRestrictionBindings.addRestriction( columnName, columnWriteFragment, jdbcMapping ); + public void addKeyRestrictionBinding(SelectableMapping selectableMapping) { + keyRestrictionBindings.addRestriction( selectableMapping ); } @Override @@ -76,13 +75,8 @@ public void addNullOptimisticLockRestriction(SelectableMapping column) { } @Override - public void addOptimisticLockRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { - optimisticLockBindings.addRestriction( columnName, columnWriteFragment, jdbcMapping ); - } - - @Override - public void addLiteralRestriction(String columnName, String sqlLiteralText, JdbcMapping jdbcMapping) { - keyRestrictionBindings.addRestriction( columnName, sqlLiteralText, jdbcMapping ); + public void addOptimisticLockRestriction(SelectableMapping selectableMapping) { + optimisticLockBindings.addRestriction( selectableMapping ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableInsertBuilder.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableInsertBuilder.java index cfe663d2bbbf..5e0dcadd1591 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableInsertBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableInsertBuilder.java @@ -8,7 +8,7 @@ import java.util.List; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.model.MutationTarget; import org.hibernate.sql.model.MutationType; import org.hibernate.sql.model.TableMapping; @@ -67,10 +67,10 @@ protected List getLobValueBindingList() { } @Override - public void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping, boolean isLob) { - final ColumnValueBinding valueBinding = createValueBinding( columnName, columnWriteFragment, jdbcMapping ); + public void addValueColumn(String columnWriteFragment, SelectableMapping selectableMapping) { + final ColumnValueBinding valueBinding = createValueBinding( columnWriteFragment, selectableMapping ); - if ( isLob && getJdbcServices().getDialect().forceLobAsLastValue() ) { + if ( selectableMapping.isLob() && getJdbcServices().getDialect().forceLobAsLastValue() ) { if ( lobValueBindingList == null ) { lobValueBindingList = new ArrayList<>(); } @@ -87,7 +87,7 @@ public void addValueColumn(ColumnValueBinding valueBinding) { } @Override - public void addKeyColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { - addColumn( columnName, columnWriteFragment, jdbcMapping, keyBindingList ); + public void addKeyColumn(String columnWriteFragment, SelectableMapping selectableMapping) { + addColumn( columnWriteFragment, selectableMapping, keyBindingList ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableMutationBuilder.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableMutationBuilder.java index 74b45f7a0471..6255c8a60d72 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableMutationBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableMutationBuilder.java @@ -10,7 +10,7 @@ import org.hibernate.engine.jdbc.mutation.ParameterUsage; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.model.MutationTarget; import org.hibernate.sql.model.MutationType; import org.hibernate.sql.model.TableMapping; @@ -76,39 +76,25 @@ protected JdbcServices getJdbcServices() { } protected void addColumn( - String columnName, String columnWriteFragment, - JdbcMapping jdbcMapping, + SelectableMapping selectableMapping, List list) { - final ColumnValueBinding valueBinding = createValueBinding( columnName, columnWriteFragment, jdbcMapping ); - list.add( valueBinding ); - } - - protected void addColumn( - String columnName, - String columnWriteFragment, - JdbcMapping jdbcMapping, - ParameterUsage parameterUsage, - List list) { - final ColumnValueBinding valueBinding = createValueBinding( columnName, columnWriteFragment, jdbcMapping, parameterUsage ); + final ColumnValueBinding valueBinding = createValueBinding( columnWriteFragment, selectableMapping ); list.add( valueBinding ); } protected ColumnValueBinding createValueBinding( - String columnName, String columnWriteFragment, - JdbcMapping jdbcMapping) { - return createValueBinding( columnName, columnWriteFragment, jdbcMapping, ParameterUsage.SET ); + SelectableMapping selectableMapping) { + return createValueBinding( columnWriteFragment, selectableMapping, ParameterUsage.SET ); } protected ColumnValueBinding createValueBinding( - String columnName, String customWriteExpression, - JdbcMapping jdbcMapping, + SelectableMapping selectableMapping, ParameterUsage parameterUsage) { return ColumnValueBindingBuilder.createValueBinding( - columnName, customWriteExpression, - jdbcMapping, + selectableMapping, getMutatingTable(), parameterUsage, parameters::apply diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableUpdateBuilder.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableUpdateBuilder.java index fd447542885a..5e5d0af8d8e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableUpdateBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/AbstractTableUpdateBuilder.java @@ -8,7 +8,7 @@ import java.util.List; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.MutationTarget; import org.hibernate.sql.model.MutationType; @@ -85,14 +85,10 @@ protected List getLobValueBindings() { } @Override - public void addValueColumn( - String columnName, - String columnWriteFragment, - JdbcMapping jdbcMapping, - boolean isLob) { - final ColumnValueBinding valueBinding = createValueBinding( columnName, columnWriteFragment, jdbcMapping ); + public void addValueColumn(String columnWriteFragment, SelectableMapping selectableMapping) { + final ColumnValueBinding valueBinding = createValueBinding( columnWriteFragment, selectableMapping ); - if ( isLob && getJdbcServices().getDialect().forceLobAsLastValue() ) { + if ( selectableMapping.isLob() && getJdbcServices().getDialect().forceLobAsLastValue() ) { if ( lobValueBindings == null ) { lobValueBindings = new ArrayList<>(); } @@ -109,10 +105,7 @@ public void addValueColumn(ColumnValueBinding valueBinding) { } @Override - public void addKeyColumn( - String columnName, - String columnWriteFragment, - JdbcMapping jdbcMapping) { - addColumn( columnName, columnWriteFragment, jdbcMapping, keyBindings ); + public void addKeyColumn(String columnWriteFragment, SelectableMapping selectableMapping) { + addColumn( columnWriteFragment, selectableMapping, keyBindings ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValueBindingBuilder.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValueBindingBuilder.java index 239e5f1ed57b..90f9164f5812 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValueBindingBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValueBindingBuilder.java @@ -8,9 +8,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.engine.jdbc.mutation.ParameterUsage; import org.hibernate.metamodel.mapping.EmbeddableMappingType; -import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.model.ast.ColumnValueBinding; import org.hibernate.sql.model.ast.ColumnValueParameter; @@ -35,16 +36,19 @@ public class ColumnValueBindingBuilder { public static ColumnValueBinding createValueBinding( - String columnName, - String writeExpression, - JdbcMapping jdbcMapping, + @Nullable String writeExpression, + SelectableMapping selectableMapping, MutatingTableReference mutatingTableReference, ParameterUsage parameterUsage, Consumer parameterConsumer) { - final ColumnReference columnReference = new ColumnReference( mutatingTableReference, columnName, jdbcMapping ); + final ColumnReference columnReference = new ColumnReference( + mutatingTableReference, + selectableMapping.getSelectionExpression(), + selectableMapping.getJdbcMapping() + ); final ColumnWriteFragment columnWriteFragment = buildWriteFragment( writeExpression, - jdbcMapping, + selectableMapping, mutatingTableReference, columnReference, parameterUsage, @@ -54,8 +58,8 @@ public static ColumnValueBinding createValueBinding( } public static ColumnWriteFragment buildWriteFragment( - String writeExpression, - JdbcMapping jdbcMapping, + @Nullable String writeExpression, + SelectableMapping selectableMapping, MutatingTableReference mutatingTableReference, ColumnReference columnReference, ParameterUsage parameterUsage, @@ -66,28 +70,28 @@ public static ColumnWriteFragment buildWriteFragment( if ( writeExpression.equals( "?" ) || ( writeExpression.contains( "?" ) && !writeExpression.contains( "'" ) ) ) { - return buildParameterizedWriteFragment( writeExpression, jdbcMapping, mutatingTableReference, columnReference, parameterUsage, parameterConsumer ); + return buildParameterizedWriteFragment( writeExpression, selectableMapping, mutatingTableReference, columnReference, parameterUsage, parameterConsumer ); } if ( !writeExpression.contains( "?" ) ) { - return new ColumnWriteFragment( writeExpression, jdbcMapping ); + return new ColumnWriteFragment( writeExpression, selectableMapping ); } if ( containsParameter( writeExpression ) ) { - return buildParameterizedWriteFragment( writeExpression, jdbcMapping, mutatingTableReference, columnReference, parameterUsage, parameterConsumer ); + return buildParameterizedWriteFragment( writeExpression, selectableMapping, mutatingTableReference, columnReference, parameterUsage, parameterConsumer ); } - return new ColumnWriteFragment( writeExpression, jdbcMapping ); + return new ColumnWriteFragment( writeExpression, selectableMapping ); } private static ColumnWriteFragment buildParameterizedWriteFragment( String writeExpression, - JdbcMapping jdbcMapping, + SelectableMapping selectableMapping, MutatingTableReference mutatingTableReference, ColumnReference columnReference, ParameterUsage parameterUsage, Consumer parameterConsumer) { - final JdbcType jdbcType = jdbcMapping.getJdbcType(); + final JdbcType jdbcType = selectableMapping.getJdbcMapping().getJdbcType(); final EmbeddableMappingType aggregateMappingType = jdbcType instanceof AggregateJdbcType aggregateJdbcType ? aggregateJdbcType.getEmbeddableMappingType() @@ -101,12 +105,12 @@ private static ColumnWriteFragment buildParameterizedWriteFragment( aggregateMappingType.forEachSelectable( parameters ); parameterConsumer.accept( parameters ); - return new ColumnWriteFragment( writeExpression, parameters, jdbcMapping ); + return new ColumnWriteFragment( writeExpression, parameters, selectableMapping ); } else { final ColumnValueParameter parameter = new ColumnValueParameter( columnReference, parameterUsage ); parameterConsumer.accept( parameter ); - return new ColumnWriteFragment( writeExpression, parameter, jdbcMapping ); + return new ColumnWriteFragment( writeExpression, parameter, selectableMapping ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValuesTableMutationBuilder.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValuesTableMutationBuilder.java index aa875efce2d5..9d8dd341f162 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValuesTableMutationBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/ColumnValuesTableMutationBuilder.java @@ -6,7 +6,6 @@ import org.hibernate.Incubating; import org.hibernate.Internal; -import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.model.ast.ColumnValueBinding; import org.hibernate.sql.model.ast.TableMutation; @@ -31,39 +30,40 @@ public interface ColumnValuesTableMutationBuilder> ex /** * Add a column as part of the values list */ - void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping, boolean isLob); - /** - * Add a column as part of the values list - */ - default void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { - addValueColumn( columnName, columnWriteFragment, jdbcMapping, jdbcMapping.getJdbcType().isLob() ); - } + void addValueColumn(String columnWriteFragment, SelectableMapping selectableMapping); /** * Add a column as part of the values list */ default void addValueColumn(SelectableMapping selectableMapping) { addValueColumn( - selectableMapping.getSelectionExpression(), selectableMapping.getWriteExpression(), - selectableMapping.getJdbcMapping(), - selectableMapping.isLob() + selectableMapping ); } /** * Add a key column */ - void addKeyColumn(String columnName, String valueExpression, JdbcMapping jdbcMapping); + void addKeyColumn(String valueExpression, SelectableMapping selectableMapping); /** * Add a key column */ default void addKeyColumn(SelectableMapping selectableMapping) { addKeyColumn( - selectableMapping.getSelectionExpression(), selectableMapping.getWriteExpression(), - selectableMapping.getJdbcMapping() + selectableMapping + ); + } + + /** + * Add a key column + */ + default void addKeyColumn(int index, SelectableMapping selectableMapping) { + addKeyColumn( + selectableMapping.getWriteExpression(), + selectableMapping ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/RestrictedTableMutationBuilder.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/RestrictedTableMutationBuilder.java index 0530a792d77c..32c46ff2f781 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/RestrictedTableMutationBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/RestrictedTableMutationBuilder.java @@ -6,7 +6,6 @@ import org.hibernate.Incubating; import org.hibernate.Internal; -import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMappings; import org.hibernate.sql.model.MutationOperation; @@ -80,17 +79,13 @@ default void addKeyRestrictionLeniently(SelectableMapping selectableMapping) { if ( selectableMapping.isFormula() ) { return; } - addKeyRestriction( - selectableMapping.getSelectionExpression(), - selectableMapping.getWriteExpression(), - selectableMapping.getJdbcMapping() - ); + addKeyRestrictionBinding( selectableMapping ); } /** - * Add restriction based on the column in the table's key + * Add a restriction as long as the selectable is not a formula and is not nullable */ - void addKeyRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping); + void addKeyRestrictionBinding(SelectableMapping selectableMapping); void addNullOptimisticLockRestriction(SelectableMapping column); @@ -101,20 +96,7 @@ default void addNullRestriction(SelectableMapping column) { /** * Add restriction based on non-version optimistically-locked column */ - default void addOptimisticLockRestriction(SelectableMapping selectableMapping) { - addOptimisticLockRestriction( - selectableMapping.getSelectionExpression(), - selectableMapping.getWriteExpression(), - selectableMapping.getJdbcMapping() - ); - } - - /** - * Add restriction based on non-version optimistically-locked column - */ - void addOptimisticLockRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping); - - void addLiteralRestriction(String columnName, String sqlLiteralText, JdbcMapping jdbcMapping); + void addOptimisticLockRestriction(SelectableMapping selectableMapping); ColumnValueBindingList getKeyRestrictionBindings(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderSkipped.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderSkipped.java index 63402bf8960d..4afd557d6d71 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderSkipped.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderSkipped.java @@ -4,7 +4,6 @@ */ package org.hibernate.sql.model.ast.builder; -import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.model.TableMapping; import org.hibernate.sql.model.ast.ColumnValueBinding; @@ -27,7 +26,7 @@ public void addNonKeyRestriction(ColumnValueBinding valueBinding) { } @Override - public void addKeyRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { + public void addKeyRestrictionBinding(SelectableMapping selectableMapping) { } @Override @@ -35,11 +34,7 @@ public void addNullOptimisticLockRestriction(SelectableMapping column) { } @Override - public void addOptimisticLockRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { - } - - @Override - public void addLiteralRestriction(String columnName, String sqlLiteralText, JdbcMapping jdbcMapping) { + public void addOptimisticLockRestriction(SelectableMapping selectableMapping) { } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderSkipped.java b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderSkipped.java index ba525bd65b60..645bace17596 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderSkipped.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableUpdateBuilderSkipped.java @@ -4,7 +4,6 @@ */ package org.hibernate.sql.model.ast.builder; -import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.sql.model.ast.ColumnValueBinding; import org.hibernate.sql.model.ast.ColumnValueBindingList; @@ -38,7 +37,7 @@ public void addNonKeyRestriction(ColumnValueBinding valueBinding) { } @Override - public void addKeyRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { + public void addKeyRestrictionBinding(SelectableMapping selectableMapping) { // nothing to do } @@ -48,14 +47,10 @@ public void addNullOptimisticLockRestriction(SelectableMapping column) { } @Override - public void addOptimisticLockRestriction(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping) { + public void addOptimisticLockRestriction(SelectableMapping selectableMapping) { // nothing to do } - @Override - public void addLiteralRestriction(String columnName, String sqlLiteralText, JdbcMapping jdbcMapping) { - } - @Override public ColumnValueBindingList getKeyRestrictionBindings() { return null; @@ -72,7 +67,7 @@ public void addWhereFragment(String fragment) { } @Override - public void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping, boolean isLob) { + public void addValueColumn(String columnWriteFragment, SelectableMapping selectableMapping) { // nothing to do } @@ -82,7 +77,7 @@ public void addValueColumn(ColumnValueBinding valueBinding) { } @Override - public void addKeyColumn(String columnName, String valueExpression, JdbcMapping jdbcMapping) { + public void addKeyColumn(String valueExpression, SelectableMapping selectableMapping) { // nothing to do } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DoubleJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DoubleJavaType.java index 3901cb158e5b..fff166f2d591 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DoubleJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DoubleJavaType.java @@ -15,6 +15,9 @@ import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; +import static java.lang.Math.ceil; +import static java.lang.Math.log; + /** * Descriptor for {@link Double} handling. * @@ -23,6 +26,8 @@ public class DoubleJavaType extends AbstractClassJavaType implements PrimitiveJavaType { public static final DoubleJavaType INSTANCE = new DoubleJavaType(); + //needed for converting precision from binary to decimal digits + private static final double LOG_BASE10OF2 = log(2)/log(10); public DoubleJavaType() { super( Double.class ); @@ -151,9 +156,14 @@ public long getDefaultSqlLength(Dialect dialect, JdbcType jdbcType) { @Override public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) { - //this is the number of *binary* digits - //in a double-precision FP number - return dialect.getDoublePrecision(); + if ( jdbcType.isFloat() ) { + //this is the number of *binary* digits + //in a double-precision FP number + return dialect.getDoublePrecision(); + } + else { + return Math.min( dialect.getDefaultDecimalPrecision(), (int) ceil( dialect.getDoublePrecision() * LOG_BASE10OF2 ) ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/FloatJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/FloatJavaType.java index aec3e11d7e0a..e65e1a24deb6 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/FloatJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/FloatJavaType.java @@ -15,6 +15,9 @@ import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; +import static java.lang.Math.ceil; +import static java.lang.Math.log; + /** * Descriptor for {@link Float} handling. * @@ -22,6 +25,8 @@ */ public class FloatJavaType extends AbstractClassJavaType implements PrimitiveJavaType { public static final FloatJavaType INSTANCE = new FloatJavaType(); + //needed for converting precision from binary to decimal digits + private static final double LOG_BASE10OF2 = log(2)/log(10); public FloatJavaType() { super( Float.class ); @@ -149,9 +154,14 @@ public long getDefaultSqlLength(Dialect dialect, JdbcType jdbcType) { @Override public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) { - //this is the number of *binary* digits - //in a single-precision FP number - return dialect.getFloatPrecision(); + if ( jdbcType.isFloat() ) { + //this is the number of *binary* digits + //in a single-precision FP number + return dialect.getFloatPrecision(); + } + else { + return Math.min( dialect.getDefaultDecimalPrecision(), (int) ceil( dialect.getFloatPrecision() * LOG_BASE10OF2 ) ); + } } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/write/OptionalTableUpdateTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/write/OptionalTableUpdateTests.java index 9c745976e197..fb027fa7d0db 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/write/OptionalTableUpdateTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/write/OptionalTableUpdateTests.java @@ -4,9 +4,11 @@ */ package org.hibernate.orm.test.write; +import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.type.SqlTypes; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -17,6 +19,8 @@ import jakarta.persistence.SecondaryTable; import jakarta.persistence.Table; +import java.math.BigDecimal; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -102,6 +106,13 @@ public static class TheEntity { @Basic @Column( table = "supplements" ) private String details; + // Used to provoke https://hibernate.atlassian.net/browse/HHH-19749 + @Column( precision = 6, scale = 2, table = "supplements" ) + private BigDecimal theBigDecimal; + // Used to provoke https://hibernate.atlassian.net/browse/HHH-18860 + @JdbcTypeCode( SqlTypes.NUMERIC ) + @Column( precision = 6, scale = 2, table = "supplements" ) + private Double theDoubleDecimal; private TheEntity() { // for use by Hibernate @@ -132,5 +143,21 @@ public String getDetails() { public void setDetails(String details) { this.details = details; } + + public BigDecimal getTheBigDecimal() { + return theBigDecimal; + } + + public void setTheBigDecimal(BigDecimal discount) { + this.theBigDecimal = discount; + } + + public Double getTheDoubleDecimal() { + return theDoubleDecimal; + } + + public void setTheDoubleDecimal(Double theDoubleDecimal) { + this.theDoubleDecimal = theDoubleDecimal; + } } }