Skip to content

Commit

Permalink
HHH-16382 Fix resolving table references especially for self-referent…
Browse files Browse the repository at this point in the history
…ial associations
  • Loading branch information
beikov committed Apr 24, 2023
1 parent b754325 commit e96402a
Show file tree
Hide file tree
Showing 103 changed files with 2,573 additions and 822 deletions.
Expand Up @@ -26,7 +26,7 @@ public String getAlias(String table) {
if ( table == null ) {
table = defaultTable;
}
final TableReference tableReference = tableGroup.getTableReference( null, table, true, true );
final TableReference tableReference = tableGroup.getTableReference( null, table, true );
return tableReference == null ? null : tableReference.getIdentificationVariable();
}

Expand Down
Expand Up @@ -291,4 +291,8 @@ public boolean hasPartitionedSelectionMapping() {
return false;
}

@Override
public boolean containsTableReference(String tableExpression) {
return entityMapping.containsTableReference( tableExpression );
}
}
Expand Up @@ -21,7 +21,7 @@
* @author Steve Ebersole
*/
public interface AttributeMapping
extends ValuedModelPart, Fetchable, DatabaseSnapshotContributor, PropertyBasedMapping, MutabilityPlanExposer {
extends OwnedValuedModelPart, Fetchable, DatabaseSnapshotContributor, PropertyBasedMapping, MutabilityPlanExposer {
/**
* The name of the mapped attribute
*/
Expand Down
Expand Up @@ -18,4 +18,11 @@ public interface BasicEntityIdentifierMapping extends SingleAttributeIdentifierM
default int getFetchableKey() {
return -1;
}

@Override
boolean isNullable();

@Override
boolean isInsertable();

}
Expand Up @@ -10,6 +10,7 @@

import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.mapping.internal.VirtualIdEmbeddable;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.from.TableGroup;
Expand Down Expand Up @@ -42,7 +43,9 @@ default String getPartName() {

ValuedModelPart getTargetPart();

default ModelPart getPart(Nature nature) {
boolean isKeyPart(ValuedModelPart modelPart);

default ValuedModelPart getPart(Nature nature) {
if ( nature == Nature.KEY ) {
return getKeyPart();
}
Expand Down Expand Up @@ -76,27 +79,45 @@ default String getContainingTableExpression() {

/**
* Create a DomainResult for the referring-side of the fk
* The table group must be the one containing the target.
*/
DomainResult<?> createKeyDomainResult(
NavigablePath navigablePath,
TableGroup targetTableGroup,
FetchParent fetchParent,
DomainResultCreationState creationState);

/**
* Create a DomainResult for the referring-side of the fk
* The table group must be the one containing the target.
* The {@link Nature} is the association side of the foreign key i.e. {@link Association#getSideNature()}.
*/
DomainResult<?> createKeyDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
TableGroup targetTableGroup,
Nature fromSide,
FetchParent fetchParent,
DomainResultCreationState creationState);

/**
* Create a DomainResult for the target-side of the fk
* The table group must be the one containing the target
*/
DomainResult<?> createTargetDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
TableGroup targetTableGroup,
FetchParent fetchParent,
DomainResultCreationState creationState);

DomainResult<?> createDomainResult(
/**
* Create a DomainResult for the referring-side of the fk
* The table group must be the one containing the target.
*/
@Override
<T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
Nature side,
FetchParent fetchParent,
TableGroup targetTableGroup,
String resultVariable,
DomainResultCreationState creationState);

Predicate generateJoinPredicate(
Expand Down
@@ -0,0 +1,14 @@
/*
* 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.metamodel.mapping;

/**
* Marker interface for valued model parts that have a declaring/owner type.
*/
public interface OwnedValuedModelPart extends ValuedModelPart {
MappingType getDeclaringType();
}
Expand Up @@ -121,7 +121,7 @@ default Fetchable getFetchable(int position) {
@Override
default <T> DomainResult<T> createSnapshotDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
TableGroup parentTableGroup,
String resultVariable,
DomainResultCreationState creationState) {
return new BasicResult( 0, null, getJavaType() );
Expand Down
Expand Up @@ -63,7 +63,11 @@ public Expression resolve(
SqlAstCreationState creationState) {
if ( referenceModelPart instanceof BasicValuedModelPart ) {
final BasicValuedModelPart selection = (BasicValuedModelPart) referenceModelPart;
final TableReference tableReference = tableGroup.resolveTableReference( getNavigablePath(), selection.getContainingTableExpression() );
final TableReference tableReference = tableGroup.resolveTableReference(
getNavigablePath(),
selection,
selection.getContainingTableExpression()
);
return creationState.getSqlExpressionResolver().resolveSqlExpression(
createColumnReferenceKey( tableReference, selection.getSelectionExpression() ),
processingState -> new ColumnReference(
Expand Down
Expand Up @@ -308,7 +308,7 @@ public String getSqlAliasStem() {

@Override
public boolean containsTableReference(String tableExpression) {
return getCollectionDescriptor().getAttributeMapping().containsTableReference( tableExpression );
return getAssociatedEntityMappingType().containsTableReference( tableExpression );
}

public TableGroup createTableGroupInternal(
Expand All @@ -319,7 +319,6 @@ public TableGroup createTableGroupInternal(
final SqlAliasBase sqlAliasBase,
SqlAstCreationState creationState) {
final SqlAstCreationContext creationContext = creationState.getCreationContext();
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlExpressionResolver();
final TableReference primaryTableReference = getEntityMappingType().createPrimaryTableReference(
sqlAliasBase,
creationState
Expand Down Expand Up @@ -389,47 +388,35 @@ private static Set<String> resolveTargetKeyPropertyNames(
final CompositeType compositeType;
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {
ToOneAttributeMapping.addPrefixedPropertyNames(
ToOneAttributeMapping.addPrefixedPropertyPaths(
targetKeyPropertyNames,
compositeType.getPropertyNames()[0],
compositeType.getSubtypes()[0],
creationProcess.getCreationContext().getSessionFactory()
);
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
ForeignKeyDescriptor.PART_NAME,
compositeType.getSubtypes()[0],
EntityIdentifierMapping.ROLE_LOCAL_NAME,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
}
else {
ToOneAttributeMapping.addPrefixedPropertyNames(
ToOneAttributeMapping.addPrefixedPropertyPaths(
targetKeyPropertyNames,
null,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
ForeignKeyDescriptor.PART_NAME,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
}
}
else {
ToOneAttributeMapping.addPrefixedPropertyNames(
ToOneAttributeMapping.addPrefixedPropertyPaths(
targetKeyPropertyNames,
entityBinding.getIdentifierProperty().getName(),
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
ForeignKeyDescriptor.PART_NAME,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
}
return targetKeyPropertyNames;
}
Expand All @@ -442,18 +429,12 @@ else if ( bootModelValue instanceof OneToMany ) {
// todo (PropertyMapping) : the problem here is timing. this needs to be delayed.
final Type propertyType = ( (PropertyMapping) elementTypeDescriptor.getEntityPersister() )
.toType( referencedPropertyName );
ToOneAttributeMapping.addPrefixedPropertyNames(
ToOneAttributeMapping.addPrefixedPropertyPaths(
targetKeyPropertyNames,
referencedPropertyName,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
ForeignKeyDescriptor.PART_NAME,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
return targetKeyPropertyNames;
}
else {
Expand All @@ -462,42 +443,42 @@ else if ( bootModelValue instanceof OneToMany ) {
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
ToOneAttributeMapping.addPrefixedPropertyNames(
ToOneAttributeMapping.addPrefixedPropertyPaths(
targetKeyPropertyNames,
compositeType.getPropertyNames()[0],
compositeType.getSubtypes()[0],
creationProcess.getCreationContext().getSessionFactory()
);
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
ForeignKeyDescriptor.PART_NAME,
compositeType.getSubtypes()[0],
EntityIdentifierMapping.ROLE_LOCAL_NAME,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
return targetKeyPropertyNames;
}
else {
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
targetKeyPropertyNames.add( EntityIdentifierMapping.ROLE_LOCAL_NAME );
targetKeyPropertyNames.add( referencedPropertyName );
final String mapsIdAttributeName;
if ( ( mapsIdAttributeName = ToOneAttributeMapping.findMapsIdPropertyName( elementTypeDescriptor, referencedPropertyName ) ) != null ) {
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
targetKeyPropertyNames.add( referencedPropertyName );
ToOneAttributeMapping.addPrefixedPropertyNames(
ToOneAttributeMapping.addPrefixedPropertyPaths(
targetKeyPropertyNames,
mapsIdAttributeName,
elementTypeDescriptor.getEntityPersister().getIdentifierType(),
creationProcess.getCreationContext().getSessionFactory()
);
ToOneAttributeMapping.addPrefixedPropertyNames(
}
else {
ToOneAttributeMapping.addPrefixedPropertyPaths(
targetKeyPropertyNames,
ForeignKeyDescriptor.PART_NAME,
elementTypeDescriptor.getEntityPersister().getIdentifierType(),
null,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
return targetKeyPropertyNames;
}
else {
return Set.of( referencedPropertyName, ForeignKeyDescriptor.PART_NAME );
}
return targetKeyPropertyNames;
}
}
}
Expand Down
Expand Up @@ -6,7 +6,6 @@
*/
package org.hibernate.metamodel.mapping.internal;

import java.io.Serializable;
import java.util.function.BiConsumer;

import org.hibernate.engine.FetchStyle;
Expand Down Expand Up @@ -147,7 +146,15 @@ public static BasicAttributeMapping withSelectableMapping(
if ( original instanceof SingleAttributeIdentifierMapping ) {
final SingleAttributeIdentifierMapping mapping = (SingleAttributeIdentifierMapping) original;
attributeName = mapping.getAttributeName();
attributeMetadata = null;
attributeMetadata = new SimpleAttributeMetadata(
propertyAccess,
mapping.getExpressibleJavaType().getMutabilityPlan(),
selectableMapping.isNullable(),
insertable,
updateable,
false,
true
);
}
else if ( original instanceof SingularAttributeMapping ) {
final SingularAttributeMapping mapping = (SingularAttributeMapping) original;
Expand Down Expand Up @@ -297,7 +304,7 @@ public <T> DomainResult<T> createDomainResult(
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, null, creationState );

//noinspection unchecked
return new BasicResult(
Expand All @@ -311,14 +318,13 @@ public <T> DomainResult<T> createDomainResult(
private SqlSelection resolveSqlSelection(
NavigablePath navigablePath,
TableGroup tableGroup,
@SuppressWarnings("SameParameterValue") boolean allowFkOptimization,
FetchParent fetchParent,
DomainResultCreationState creationState) {
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
final TableReference tableReference = tableGroup.resolveTableReference(
navigablePath,
getContainingTableExpression(),
allowFkOptimization
this,
getContainingTableExpression()
);

return expressionResolver.resolveSqlSelection(
Expand All @@ -337,7 +343,7 @@ public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
resolveSqlSelection( navigablePath, tableGroup, null, creationState );
}

@Override
Expand All @@ -346,7 +352,7 @@ public void applySqlSelections(
TableGroup tableGroup,
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, true, null, creationState ), getJdbcMapping() );
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, null, creationState ), getJdbcMapping() );
}

@Override
Expand Down Expand Up @@ -375,7 +381,12 @@ public Fetch generateFetch(

assert tableGroup != null;

final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, fetchParent, creationState );
final SqlSelection sqlSelection = resolveSqlSelection(
fetchablePath,
tableGroup,
fetchParent,
creationState
);
valuesArrayPosition = sqlSelection.getValuesArrayPosition();
if ( sqlSelection.getExpressionType() != null) {
// if the expression type is different that the expected type coerce the value
Expand Down

0 comments on commit e96402a

Please sign in to comment.