fixed references to same column, but from different TableReferences (different qualifiers)
This commit is contained in:
parent
39391c86f2
commit
63b22c4c6b
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface BasicEntityIdentifierMapping extends EntityIdentifierMapping, BasicValuedModelPart {
|
||||
}
|
|
@ -26,6 +26,7 @@ import org.hibernate.sql.ast.Clause;
|
|||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
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.results.internal.domain.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
|
||||
import org.hibernate.sql.results.spi.DomainResult;
|
||||
|
@ -109,10 +110,13 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
|||
|
||||
private SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
||||
|
||||
return expressionResolver.resolveSqlSelection(
|
||||
expressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
getContainingTableExpression(),
|
||||
tableReference,
|
||||
getMappedColumnExpression()
|
||||
),
|
||||
sqlAstProcessingState -> tableGroup.resolveColumnReference(
|
||||
|
@ -120,7 +124,7 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
|||
getMappedColumnExpression(),
|
||||
() -> new ColumnReference(
|
||||
getMappedColumnExpression(),
|
||||
tableGroup.resolveTableReference( getContainingTableExpression() ).getIdentificationVariable(),
|
||||
tableReference.getIdentificationVariable(),
|
||||
jdbcMapping,
|
||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
||||
)
|
||||
|
@ -136,18 +140,20 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
|
||||
// the act of resolving the selection creates the selection if it not already part of the collected selections
|
||||
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
||||
|
||||
expressionResolver.resolveSqlSelection(
|
||||
expressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
getContainingTableExpression(),
|
||||
tableReference,
|
||||
getMappedColumnExpression()
|
||||
),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
getMappedColumnExpression(),
|
||||
tableGroup.resolveTableReference( getContainingTableExpression() ).getIdentificationVariable(),
|
||||
tableReference.getIdentificationVariable(),
|
||||
jdbcMapping,
|
||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
||||
)
|
||||
|
|
|
@ -184,7 +184,7 @@ public class EmbeddedAttributeMapping
|
|||
|
||||
final Expression columnReference = sqlAstCreationState.getSqlExpressionResolver().resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
getContainingTableExpression(),
|
||||
tableReference,
|
||||
attrColumnExpr
|
||||
),
|
||||
sqlAstProcessingState -> tableGroup.resolveColumnReference(
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.metamodel.mapping.internal;
|
|||
import java.io.Serializable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
|
@ -19,6 +20,7 @@ import org.hibernate.mapping.BasicValue;
|
|||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
|
@ -39,9 +41,13 @@ import org.hibernate.sql.ast.spi.SqlSelection;
|
|||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
|
||||
import org.hibernate.sql.results.spi.DomainResult;
|
||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.spi.Fetch;
|
||||
import org.hibernate.sql.results.spi.FetchParent;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
||||
|
@ -63,12 +69,15 @@ public class MappingModelCreationHelper {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// EntityIdentifier
|
||||
|
||||
public static EntityIdentifierMapping buildSimpleIdentifierMapping(
|
||||
public static BasicEntityIdentifierMapping buildSimpleIdentifierMapping(
|
||||
EntityPersister entityPersister,
|
||||
String rootTable,
|
||||
String pkColumnName,
|
||||
BasicType idType,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
assert entityPersister.hasIdentifierProperty();
|
||||
assert entityPersister.getIdentifierPropertyName() != null;
|
||||
|
||||
final PersistentClass bootEntityDescriptor = creationProcess.getCreationContext()
|
||||
.getBootModel()
|
||||
.getEntityBinding( entityPersister.getEntityName() );
|
||||
|
@ -76,7 +85,7 @@ public class MappingModelCreationHelper {
|
|||
final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy()
|
||||
.resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() );
|
||||
|
||||
return new EntityIdentifierMapping() {
|
||||
return new BasicEntityIdentifierMapping() {
|
||||
@Override
|
||||
public PropertyAccess getPropertyAccess() {
|
||||
return propertyAccess;
|
||||
|
@ -121,12 +130,13 @@ public class MappingModelCreationHelper {
|
|||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
final TableReference rootTableReference = tableGroup.resolveTableReference( rootTable );
|
||||
|
||||
final Expression expression = expressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey( rootTable, pkColumnName ),
|
||||
SqlExpressionResolver.createColumnReferenceKey( rootTableReference, pkColumnName ),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
pkColumnName,
|
||||
tableGroup.resolveTableReference( rootTable ).getIdentificationVariable(),
|
||||
rootTableReference.getIdentificationVariable(),
|
||||
( (BasicValuedMapping) entityPersister.getIdentifierType() ).getJdbcMapping(),
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
)
|
||||
|
@ -152,14 +162,10 @@ public class MappingModelCreationHelper {
|
|||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
|
||||
// todo (6.0) : in the original 6.0 work `#resolveSqlExpression` worked based on an overload to handle qualifiable versus un-qualifiable expressables.
|
||||
// - that gets awkward in terms of managing which overloaded form to call. Perhaps a better
|
||||
// option would be to use heterogeneous keys - e.g. an array for a qualifiable expressable (alias + expressable)
|
||||
// or a String concatenation
|
||||
final TableReference rootTableReference = tableGroup.resolveTableReference( rootTable );
|
||||
|
||||
final Expression expression = expressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey( rootTable, pkColumnName ),
|
||||
SqlExpressionResolver.createColumnReferenceKey( rootTableReference, pkColumnName ),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
pkColumnName,
|
||||
rootTable,
|
||||
|
@ -176,7 +182,58 @@ public class MappingModelCreationHelper {
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingTableExpression() {
|
||||
return rootTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValueConverter getConverter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMappedColumnExpression() {
|
||||
return pkColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMapping getJdbcMapping() {
|
||||
return idType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFetchableName() {
|
||||
return entityPersister.getIdentifierPropertyName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchStrategy getMappedFetchStrategy() {
|
||||
return FetchStrategy.IMMEDIATE_JOIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new BasicFetch<>(
|
||||
0,
|
||||
fetchParent,
|
||||
fetchablePath,
|
||||
this,
|
||||
false,
|
||||
null,
|
||||
FetchTiming.IMMEDIATE,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public static EntityIdentifierMapping buildEncapsulatedCompositeIdentifierMapping(
|
||||
|
|
|
@ -1270,7 +1270,7 @@ public abstract class AbstractEntityPersister
|
|||
final String rootPkColumnName = rootPkColumnNames[ columnIndex ];
|
||||
final Expression pkColumnExpression = sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
rootTableReference.getTableExpression(),
|
||||
rootTableReference,
|
||||
rootPkColumnName
|
||||
),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
|
@ -1284,7 +1284,7 @@ public abstract class AbstractEntityPersister
|
|||
final String fkColumnName = fkColumnNames[ columnIndex ];
|
||||
final Expression fkColumnExpression = sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
joinedTableReference.getTableExpression(),
|
||||
joinedTableReference,
|
||||
fkColumnName
|
||||
),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
|
@ -6310,6 +6310,10 @@ public abstract class AbstractEntityPersister
|
|||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||
LOG.tracef( "#findSubPart(`%s`)", name );
|
||||
|
||||
if ( isIdentifierReference( name ) ) {
|
||||
return identifierMapping;
|
||||
}
|
||||
|
||||
final AttributeMapping declaredAttribute = declaredAttributeMappings.get( name );
|
||||
if ( declaredAttribute != null ) {
|
||||
return declaredAttribute;
|
||||
|
@ -6335,6 +6339,23 @@ public abstract class AbstractEntityPersister
|
|||
return null;
|
||||
}
|
||||
|
||||
private boolean isIdentifierReference(String name) {
|
||||
if ( EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
|
||||
if ( hasIdentifierProperty() ) {
|
||||
final String identifierPropertyName = getIdentifierPropertyName();
|
||||
if ( identifierPropertyName.equals( name ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "id".equals( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubParts(
|
||||
Consumer<ModelPart> consumer,
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.function.Function;
|
|||
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
|
@ -39,6 +40,17 @@ public interface SqlExpressionResolver {
|
|||
static String createColumnReferenceKey(String tableExpression, String columnExpression) {
|
||||
return tableExpression + columnExpression;
|
||||
}
|
||||
/**
|
||||
* Helper for generating an expression key for a column reference.
|
||||
*
|
||||
* @see #resolveSqlExpression
|
||||
*/
|
||||
static String createColumnReferenceKey(TableReference tableReference, String columnExpression) {
|
||||
final String qualifier = tableReference.getIdentificationVariable() == null
|
||||
? tableReference.getTableExpression()
|
||||
: tableReference.getIdentificationVariable();
|
||||
return qualifier + columnExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a qualifier + a qualifiable SqlExpressable, resolve the
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.sql.ast.spi.SqlAstWalker;
|
|||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.update.Assignment;
|
||||
import org.hibernate.sql.results.spi.DomainResult;
|
||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||
|
@ -43,15 +44,16 @@ public class BasicValuedPathInterpretation<T> implements AssignableSqmPathInterp
|
|||
null
|
||||
);
|
||||
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( mapping.getContainingTableExpression() );
|
||||
|
||||
final ColumnReference columnReference = (ColumnReference) sqlAstCreationState.getSqlExpressionResolver().resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
mapping.getContainingTableExpression(),
|
||||
tableReference,
|
||||
mapping.getMappedColumnExpression()
|
||||
),
|
||||
sacs -> new ColumnReference(
|
||||
mapping.getMappedColumnExpression(),
|
||||
tableGroup.resolveTableReference( mapping.getContainingTableExpression() )
|
||||
.getIdentificationVariable(),
|
||||
tableReference.getIdentificationVariable(),
|
||||
mapping.getJdbcMapping(),
|
||||
sqlAstCreationState.getCreationContext().getSessionFactory()
|
||||
)
|
||||
|
|
|
@ -68,7 +68,7 @@ public abstract class AbstractColumnReferenceQualifier implements ColumnReferenc
|
|||
String columnExpression,
|
||||
Supplier<ColumnReference> creator) {
|
||||
return columnReferenceMap.computeIfAbsent(
|
||||
SqlExpressionResolver.createColumnReferenceKey( tableExpression, columnExpression ),
|
||||
SqlExpressionResolver.createColumnReferenceKey( resolveTableReference( tableExpression ), columnExpression ),
|
||||
s -> creator.get()
|
||||
);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public abstract class AbstractColumnReferenceQualifier implements ColumnReferenc
|
|||
@Override
|
||||
public ColumnReference resolveColumnReference(String tableExpression, String columnExpression) {
|
||||
return columnReferenceMap.get(
|
||||
SqlExpressionResolver.createColumnReferenceKey( tableExpression, columnExpression )
|
||||
SqlExpressionResolver.createColumnReferenceKey( resolveTableReference( tableExpression ), columnExpression )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.junit.jupiter.api.AfterEach;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -198,6 +199,40 @@ public class SmokeTests {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColumnQualification(SessionFactoryScope scope) {
|
||||
// make sure column references to the same column qualified by different table references works properly
|
||||
|
||||
// first, let's create a second entity
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
SimpleEntity simpleEntity = new SimpleEntity();
|
||||
simpleEntity.setId( 2 );
|
||||
simpleEntity.setGender( MALE );
|
||||
simpleEntity.setName( "Andrea" );
|
||||
simpleEntity.setGender2( FEMALE );
|
||||
simpleEntity.setComponent( new Component( "b1", "b2" ) );
|
||||
session.save( simpleEntity );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final Object[] result = session.createQuery( "select e, e2 from SimpleEntity e, SimpleEntity e2 where e.id = 1 and e2.id = 2", Object[].class )
|
||||
.uniqueResult();
|
||||
assertThat( result, notNullValue() );
|
||||
|
||||
assertThat( result[0], instanceOf( SimpleEntity.class ) );
|
||||
assertThat( ( (SimpleEntity) result[0] ).getId(), is( 1 ) );
|
||||
assertThat( ( (SimpleEntity) result[0] ).getComponent().getAttribute1(), is( "a1" ) );
|
||||
|
||||
assertThat( result[1], instanceOf( SimpleEntity.class ) );
|
||||
assertThat( ( (SimpleEntity) result[1] ).getId(), is( 2 ) );
|
||||
assertThat( ( (SimpleEntity) result[1] ).getComponent().getAttribute1(), is( "b1" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHqlQueryReuseWithDiffParameterBinds(SessionFactoryScope scope) {
|
||||
// first, let's create a second entity
|
||||
|
|
Loading…
Reference in New Issue