Various fixes and move tests from test.jpa

* Implement parameter list expansion for native queries
* Fix empty subselect fetched collection initialization
* Implement support for nested table group joins to allow joins on the map-key
* Replace `getTableReference` with `resolveTableReference` where appropriate to distinguish which calls can cause table reference joins to be created
* Fix some table reference resolving issues with inverse embeddable model parts
* Use a Fetch for entity ids instead of a DomainResult
* Fix bidirectional fetching for collection initializtion
* Implement table reference join pruning for treat usages
* Implement strict JPA compliance for different parameter styles
* Ensure From nodes in Criteria are unique
* Add unique key support to DelayedEntityFetch
* Check if FetchParent is enhanced for lazy loading for DelayedEntityFetch
* Register entity instances under all possible EntityUniqueKey
* Introduce EntityJavaTypeDescriptor that implements equality based on object identity
This commit is contained in:
Christian Beikov 2021-11-04 16:24:50 +01:00
parent 24c758c2e9
commit 38d1c122eb
173 changed files with 2927 additions and 1469 deletions

View File

@ -1052,6 +1052,7 @@ identifier
| UPDATE
| UPPER
| VALUE
| VALUES
| VERSION
| VERSIONED
| WEEK

View File

@ -35,7 +35,7 @@ public class NativeQueryInterpreterStandardImpl implements NativeQueryInterprete
return new NativeSelectQueryPlanImpl<>(
queryDefinition.getSqlString(),
queryDefinition.getAffectedTableNames(),
queryDefinition.getQueryParameterList(),
queryDefinition.getQueryParameterOccurrences(),
queryDefinition.getResultSetMapping(),
sessionFactory
);

View File

@ -44,7 +44,7 @@ public interface NativeQueryInterpreter extends Service {
return new NativeSelectQueryPlanImpl<>(
queryDefinition.getSqlString(),
queryDefinition.getAffectedTableNames(),
queryDefinition.getQueryParameterList(),
queryDefinition.getQueryParameterOccurrences(),
queryDefinition.getResultSetMapping(),
sessionFactory
);

View File

@ -26,7 +26,7 @@ public class TableGroupFilterAliasGenerator implements FilterAliasGenerator {
if ( table == null ) {
table = defaultTable;
}
final TableReference tableReference = tableGroup.getTableReference( table );
final TableReference tableReference = tableGroup.getTableReference( null, table, true, true );
return tableReference == null ? null : tableReference.getIdentificationVariable();
}

View File

@ -33,6 +33,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.ResultsHelper;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;
@ -163,13 +164,22 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
);
if ( subSelectFetchedCollections != null && ! subSelectFetchedCollections.isEmpty() ) {
subSelectFetchedCollections.forEach( (c) -> {
if ( c.wasInitialized() ) {
return;
}
subSelectFetchedCollections.forEach(
c -> {
if ( c.wasInitialized() ) {
return;
}
c.initializeEmptyCollection( getLoadable().getCollectionDescriptor() );
} );
c.initializeEmptyCollection( getLoadable().getCollectionDescriptor() );
ResultsHelper.finalizeCollectionLoading(
persistenceContext,
getLoadable().getCollectionDescriptor(),
c,
c.getKey(),
true
);
}
);
subSelectFetchedCollections.clear();
}

View File

@ -60,9 +60,9 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
@ -401,21 +401,9 @@ public class LoaderSelectBuilder {
for ( ModelPart part : partsToSelect ) {
final NavigablePath navigablePath = rootNavigablePath.append( part.getPartName() );
final TableGroup tableGroup;
if ( part instanceof RootTableGroupProducer ) {
tableGroup = ( (RootTableGroupProducer) part ).createRootTableGroup(
true,
navigablePath,
null,
() -> rootQuerySpec::applyPredicate,
sqlAstCreationState,
creationContext
);
rootQuerySpec.getFromClause().addRoot( tableGroup );
sqlAstCreationState.getFromClauseAccess().registerTableGroup( navigablePath, tableGroup );
}
else if ( part instanceof ToOneAttributeMapping ) {
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) part;
final TableGroupJoin tableGroupJoin = toOneAttributeMapping.createTableGroupJoin(
if ( part instanceof TableGroupJoinProducer ) {
final TableGroupJoinProducer tableGroupJoinProducer = (TableGroupJoinProducer) part;
final TableGroupJoin tableGroupJoin = tableGroupJoinProducer.createTableGroupJoin(
navigablePath,
rootTableGroup,
null,
@ -613,8 +601,18 @@ public class LoaderSelectBuilder {
tableGroup
);
if ( manyToManyFilterPredicate != null ) {
assert tableGroup.getTableReferenceJoins().size() == 1;
tableGroup.getTableReferenceJoins().get( 0 ).applyPredicate( manyToManyFilterPredicate );
TableGroupJoin elementTableGroupJoin = null;
for ( TableGroupJoin nestedTableGroupJoin : tableGroup.getNestedTableGroupJoins() ) {
final NavigablePath navigablePath = nestedTableGroupJoin.getNavigablePath();
if ( navigablePath.getParent() == tableGroup.getNavigablePath()
&& CollectionPart.Nature.ELEMENT.getName().equals( navigablePath.getUnaliasedLocalName() ) ) {
elementTableGroupJoin = nestedTableGroupJoin;
break;
}
}
assert elementTableGroupJoin != null;
elementTableGroupJoin.applyPredicate( manyToManyFilterPredicate );
}
}
}

View File

@ -16,6 +16,7 @@ import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.Predicate;
@ -42,7 +43,8 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
NavigablePath navigablePath,
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAstCreationState creationState, SqlAstCreationContext creationContext) {
SqlAstCreationState creationState,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@ -53,7 +55,8 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlAstCreationState creationState, SqlAstCreationContext creationContext) {
SqlExpressionResolver expressionResolver,
SqlAstCreationContext creationContext) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}

View File

@ -159,7 +159,6 @@ public abstract class AbstractCompositeIdentifierMapping
fetchParent,
fetchTiming,
selected,
attributeMetadataAccess.resolveAttributeMetadata( null ).isNullable(),
creationState
);
}

View File

@ -87,7 +87,7 @@ public class EntityRepresentationStrategyPojoStandard implements EntityRepresent
.getJavaTypeDescriptorRegistry();
final Class<?> mappedJavaType = bootDescriptor.getMappedClass();
this.mappedJtd = jtdRegistry.resolveManagedTypeDescriptor( mappedJavaType );
this.mappedJtd = jtdRegistry.resolveEntityTypeDescriptor( mappedJavaType );
final Class<?> proxyJavaType = bootDescriptor.getProxyInterface();
if ( proxyJavaType != null ) {

View File

@ -38,6 +38,7 @@ import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.mapping.internal.SelectableMappingsImpl;
@ -52,6 +53,7 @@ import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetchable;
@ -176,7 +178,8 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
}
private EmbeddableMappingType(
EmbeddableValuedModelPart valueMapping,
EmbeddedAttributeMapping valueMapping,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
EmbeddableMappingType inverseMappingType,
MappingModelCreationProcess creationProcess) {
@ -186,6 +189,7 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
this.valueMapping = valueMapping;
this.createEmptyCompositesEnabled = inverseMappingType.isCreateEmptyCompositesEnabled();
this.selectableMappings = selectableMappings;
final ManagedMappingType declaringType = valueMapping.getDeclaringType();
creationProcess.registerInitializationCallback(
"EmbeddableMappingType(" + inverseMappingType.getNavigableRole().getFullPath() + ".{inverse})#finishInitialization",
() -> {
@ -201,6 +205,7 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
final BasicAttributeMapping original = (BasicAttributeMapping) attributeMapping;
final SelectableMapping selectableMapping = selectableMappings.getSelectable( currentIndex );
attributeMapping = BasicAttributeMapping.withSelectableMapping(
declaringType,
original,
original.getPropertyAccess(),
original.getValueGeneration(),
@ -210,13 +215,18 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
}
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
final ToOneAttributeMapping original = (ToOneAttributeMapping) attributeMapping;
final ToOneAttributeMapping toOne = original.copy();
final ToOneAttributeMapping toOne = original.copy(
declaringType,
declaringTableGroupProducer
);
final int offset = currentIndex;
toOne.setIdentifyingColumnsTableExpression(
selectableMappings.getSelectable( offset ).getContainingTableExpression()
);
toOne.setForeignKeyDescriptor(
original.getForeignKeyDescriptor().withKeySelectionMapping(
declaringType,
declaringTableGroupProducer,
index -> selectableMappings.getSelectable( offset + index ),
creationProcess
)
@ -237,10 +247,17 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
}
public EmbeddableMappingType createInverseMappingType(
EmbeddableValuedModelPart valueMapping,
EmbeddedAttributeMapping valueMapping,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess) {
return new EmbeddableMappingType( valueMapping, selectableMappings, this, creationProcess );
return new EmbeddableMappingType(
valueMapping,
declaringTableGroupProducer,
selectableMappings,
this,
creationProcess
);
}
private boolean finishInitialization(

View File

@ -9,6 +9,7 @@ package org.hibernate.metamodel.mapping;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -195,8 +196,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
return superMappingType.getRootEntityDescriptor();
}
default TableReference locateTableReference(TableGroup tableGroup) {
return tableGroup.getPrimaryTableReference();
default void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
}
default boolean isAbstract() {
@ -296,7 +296,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
explicitSourceAlias,
additionalPredicateCollectorAccess,
creationState.getSqlAliasBaseGenerator().createSqlAliasBase( getSqlAliasStem() ),
creationState,
creationState.getSqlExpressionResolver(),
creationContext
);
}
@ -308,7 +308,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlAstCreationState creationState,
SqlExpressionResolver expressionResolver,
SqlAstCreationContext creationContext) {
return getEntityPersister().createRootTableGroup(
canUseInnerJoins,
@ -316,7 +316,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
explicitSourceAlias,
additionalPredicateCollectorAccess,
sqlAliasBase,
creationState,
expressionResolver,
creationContext
);
}

View File

@ -15,6 +15,7 @@ import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult;
@ -102,15 +103,15 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
DomainResultCreationState creationState);
Predicate generateJoinPredicate(
TableGroup lhs,
TableGroup tableGroup,
TableGroup targetSideTableGroup,
TableGroup keySideTableGroup,
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext);
Predicate generateJoinPredicate(
TableReference lhs,
TableReference rhs,
TableReference targetSideReference,
TableReference keySideReference,
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext);
@ -149,6 +150,8 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
* Return a copy of this foreign key descriptor with the selectable mappings as provided by the given accessor.
*/
ForeignKeyDescriptor withKeySelectionMapping(
ManagedMappingType declaringType,
TableGroupProducer declaringTableGroupProducer,
IntFunction<SelectableMapping> selectableMappingAccess,
MappingModelCreationProcess creationProcess);

View File

@ -46,7 +46,7 @@ public class MappingModelHelper {
qualifier = selection.getContainingTableExpression();
}
else {
qualifier = tableGroup.getTableReference( selection.getContainingTableExpression() ).getIdentificationVariable();
qualifier = tableGroup.resolveTableReference( selection.getContainingTableExpression() ).getIdentificationVariable();
}
if ( sqlExpressionResolver == null ) {
colRef = new ColumnReference(
@ -78,7 +78,7 @@ public class MappingModelHelper {
qualifier = basicPart.getContainingTableExpression();
}
else {
qualifier = tableGroup.getTableReference( basicPart.getContainingTableExpression() ).getIdentificationVariable();
qualifier = tableGroup.resolveTableReference( basicPart.getContainingTableExpression() ).getIdentificationVariable();
}
if ( sqlExpressionResolver == null ) {
return new ColumnReference(

View File

@ -177,7 +177,6 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
fetchParent,
fetchablePath,
this,
false,
null,
fetchTiming,
creationState

View File

@ -188,7 +188,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchablePath.getParent().getParent() );
final TableReference tableReference = tableGroup.getTableReference( fetchablePath, table );
final TableReference tableReference = tableGroup.resolveTableReference( fetchablePath, table );
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey( tableReference, column ),
processingState -> new ColumnReference(
@ -212,7 +212,6 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
fetchParent,
fetchablePath,
this,
nullable,
null,
fetchTiming,
creationState

View File

@ -151,7 +151,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
.getSessionFactory();
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath().getParent() );
final TableReference tableReference = tableGroup.getTableReference( fetchablePath, table );
final TableReference tableReference = tableGroup.resolveTableReference( fetchablePath, table );
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( tableReference, column ),
@ -177,7 +177,6 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
fetchParent,
fetchablePath,
this,
nullable,
null,
fetchTiming,
creationState

View File

@ -106,6 +106,7 @@ public class BasicAttributeMapping
}
public static BasicAttributeMapping withSelectableMapping(
ManagedMappingType declaringType,
BasicValuedModelPart original,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration,
@ -114,19 +115,16 @@ public class BasicAttributeMapping
int stateArrayPosition = 0;
StateArrayContributorMetadataAccess attributeMetadataAccess = null;
BasicValueConverter<?, ?> valueConverter = null;
ManagedMappingType declaringType = null;
if ( original instanceof SingleAttributeIdentifierMapping ) {
final SingleAttributeIdentifierMapping mapping = (SingleAttributeIdentifierMapping) original;
attributeName = mapping.getAttributeName();
attributeMetadataAccess = null;
declaringType = mapping.findContainingEntityMapping();
}
else if ( original instanceof SingularAttributeMapping ) {
final SingularAttributeMapping mapping = (SingularAttributeMapping) original;
attributeName = mapping.getAttributeName();
stateArrayPosition = mapping.getStateArrayPosition();
attributeMetadataAccess = mapping.getAttributeMetadataAccess();
declaringType = mapping.getDeclaringType();
}
if ( original instanceof ConvertibleModelPart ) {
valueConverter = ( (ConvertibleModelPart) original ).getValueConverter();
@ -212,7 +210,7 @@ public class BasicAttributeMapping
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, true, creationState );
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, true, creationState );
//noinspection unchecked
return new BasicResult(
@ -225,12 +223,13 @@ public class BasicAttributeMapping
}
private SqlSelection resolveSqlSelection(
NavigablePath navigablePath,
TableGroup tableGroup,
boolean allowFkOptimization,
DomainResultCreationState creationState) {
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
final TableReference tableReference = tableGroup.resolveTableReference(
tableGroup.getNavigablePath().append( getNavigableRole().getNavigableName() ),
navigablePath,
getContainingTableExpression(),
allowFkOptimization
);
@ -257,7 +256,7 @@ public class BasicAttributeMapping
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
resolveSqlSelection( tableGroup, true, creationState );
resolveSqlSelection( navigablePath, tableGroup, true, creationState );
}
@Override
@ -266,7 +265,7 @@ public class BasicAttributeMapping
TableGroup tableGroup,
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
selectionConsumer.accept( resolveSqlSelection( tableGroup, true, creationState ), getJdbcMapping() );
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, true, creationState ), getJdbcMapping() );
}
@Override
@ -293,7 +292,7 @@ public class BasicAttributeMapping
assert tableGroup != null;
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, false, creationState );
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, creationState );
valuesArrayPosition = sqlSelection.getValuesArrayPosition();
}
@ -302,7 +301,6 @@ public class BasicAttributeMapping
fetchParent,
fetchablePath,
this,
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
valueConverter,
fetchTiming,
creationState

View File

@ -31,6 +31,7 @@ import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
@ -326,12 +327,19 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
boolean selected,
String resultVariable,
DomainResultCreationState creationState) {
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup(
fetchParent.getNavigablePath()
);
assert tableGroup != null;
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, false, creationState );
return new BasicFetch<>(
0,
sqlSelection.getValuesArrayPosition(),
fetchParent,
fetchablePath,
this,
false,
null,
FetchTiming.IMMEDIATE,
creationState

View File

@ -230,7 +230,6 @@ public class BasicValuedCollectionPart
fetchParent,
fetchablePath,
this,
false,
valueConverter,
FetchTiming.IMMEDIATE,
creationState

View File

@ -9,20 +9,29 @@ package org.hibernate.metamodel.mapping.internal;
import java.util.LinkedHashMap;
import java.util.Map;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.persister.entity.DiscriminatorType;
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
@ -69,6 +78,31 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
}
}
@Override
public BasicFetch generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,
boolean selected,
String resultVariable,
DomainResultCreationState creationState) {
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup(
fetchParent.getNavigablePath()
);
// Since the expression is lazy, based on the available table reference joins,
// we need to force the initialization in case this is a fetch
tableDiscriminatorDetailsMap.forEach(
(tableName, tableDiscriminatorDetails) -> tableGroup.getTableReference(
fetchablePath,
tableName,
false,
true
)
);
return super.generateFetch( fetchParent, fetchablePath, fetchTiming, selected, resultVariable, creationState );
}
@Override
public Expression resolveSqlExpression(
NavigablePath navigablePath,
@ -82,37 +116,63 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
);
}
private CaseSearchedExpression createCaseSearchedExpression(TableGroup entityTableGroup) {
final CaseSearchedExpression caseSearchedExpression = new CaseSearchedExpression( this );
private Expression createCaseSearchedExpression(TableGroup entityTableGroup) {
return new SelfRenderingExpression() {
CaseSearchedExpression caseSearchedExpression;
tableDiscriminatorDetailsMap.forEach( (tableName, tableDiscriminatorDetails) -> {
final TableReference tableReference = entityTableGroup.getTableReference( entityTableGroup.getNavigablePath(), tableName );
@Override
public void renderToSql(
SqlAppender sqlAppender,
SqlAstTranslator<?> walker,
SessionFactoryImplementor sessionFactory) {
if ( caseSearchedExpression == null ) {
// todo (6.0): possible optimization is to omit cases for table reference joins, that touch a super class, where a subclass is inner joined due to pruning
caseSearchedExpression = new CaseSearchedExpression( CaseStatementDiscriminatorMappingImpl.this );
tableDiscriminatorDetailsMap.forEach(
(tableName, tableDiscriminatorDetails) -> {
final TableReference tableReference = entityTableGroup.getTableReference(
entityTableGroup.getNavigablePath(),
tableName,
false,
false
);
if ( tableReference == null ) {
// assume this is because it is a table that is not part of the processing entity's sub-hierarchy
return;
if ( tableReference == null ) {
// assume this is because it is a table that is not part of the processing entity's sub-hierarchy
return;
}
final Predicate predicate = new NullnessPredicate(
new ColumnReference(
tableReference,
tableDiscriminatorDetails.getCheckColumnName(),
false,
null,
null,
getJdbcMapping(),
getSessionFactory()
),
true
);
caseSearchedExpression.when(
predicate,
new QueryLiteral<>(
tableDiscriminatorDetails.getDiscriminatorValue(),
getUnderlyingJdbcMappingType()
)
);
}
);
}
caseSearchedExpression.accept( walker );
}
final Predicate predicate = new NullnessPredicate(
new ColumnReference(
tableReference,
tableDiscriminatorDetails.getCheckColumnName(),
false,
null,
null,
getJdbcMapping(),
getSessionFactory()
),
true
);
caseSearchedExpression.when( predicate, new QueryLiteral<>(
tableDiscriminatorDetails.getDiscriminatorValue(),
getUnderlyingJdbcMappingType()
) );
} );
return caseSearchedExpression;
@Override
public JdbcMappingContainer getExpressionType() {
return CaseStatementDiscriminatorMappingImpl.this;
}
};
}
@Override

View File

@ -180,7 +180,6 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
fetchParent,
fetchablePath,
this,
! selected,
null,
FetchTiming.IMMEDIATE,
creationState

View File

@ -43,6 +43,7 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult;
@ -110,6 +111,8 @@ public class EmbeddedAttributeMapping
// Constructor is only used for creating the inverse attribute mapping
private EmbeddedAttributeMapping(
ManagedMappingType keyDeclaringType,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
EmbeddableValuedModelPart inverseModelPart,
MappingModelCreationProcess creationProcess) {
@ -118,11 +121,7 @@ public class EmbeddedAttributeMapping
-1,
null,
inverseModelPart.getMappedFetchOptions(),
inverseModelPart instanceof AttributeMapping
? ( (AttributeMapping) inverseModelPart ).getDeclaringType()
: inverseModelPart instanceof EntityIdentifierMapping
? inverseModelPart.findContainingEntityMapping()
: null,
keyDeclaringType,
null,
null
);
@ -132,6 +131,7 @@ public class EmbeddedAttributeMapping
this.tableExpression = selectableMappings.getSelectable( 0 ).getContainingTableExpression();
this.embeddableMappingType = inverseModelPart.getEmbeddableTypeDescriptor().createInverseMappingType(
this,
declaringTableGroupProducer,
selectableMappings,
creationProcess
);
@ -140,9 +140,17 @@ public class EmbeddedAttributeMapping
public static EmbeddableValuedModelPart createInverseModelPart(
EmbeddableValuedModelPart modelPart,
ManagedMappingType keyDeclaringType,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess) {
return new EmbeddedAttributeMapping( selectableMappings, modelPart, creationProcess );
return new EmbeddedAttributeMapping(
keyDeclaringType,
declaringTableGroupProducer,
selectableMappings,
modelPart,
creationProcess
);
}
@Override
@ -225,7 +233,6 @@ public class EmbeddedAttributeMapping
fetchParent,
fetchTiming,
selected,
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
creationState
);
}

View File

@ -159,7 +159,6 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
fetchParent,
FetchTiming.IMMEDIATE,
selected,
true,
creationState
);
}

View File

@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
@ -27,6 +28,7 @@ import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.Clause;
@ -36,6 +38,7 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction;
@ -101,6 +104,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
private EmbeddedForeignKeyDescriptor(
EmbeddedForeignKeyDescriptor original,
String keyTable,
ManagedMappingType keyDeclaringType,
TableGroupProducer keyDeclaringTableGroupProducer,
SelectableMappings keySelectableMappings,
MappingModelCreationProcess creationProcess) {
this.keyTable = keyTable;
@ -112,6 +117,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
Nature.KEY,
EmbeddedAttributeMapping.createInverseModelPart(
original.targetSide.getModelPart(),
keyDeclaringType,
keyDeclaringTableGroupProducer,
keySelectableMappings,
creationProcess
)
@ -158,6 +165,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
@Override
public ForeignKeyDescriptor withKeySelectionMapping(
ManagedMappingType declaringType,
TableGroupProducer declaringTableGroupProducer,
IntFunction<SelectableMapping> selectableMappingAccess,
MappingModelCreationProcess creationProcess) {
SelectableMapping[] selectionMappings = new SelectableMapping[keySelectableMappings.getJdbcTypeCount()];
@ -167,6 +176,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
return new EmbeddedForeignKeyDescriptor(
this,
selectionMappings[0].getContainingTableExpression(),
declaringType,
declaringTableGroupProducer,
new SelectableMappingsImpl( selectionMappings ),
creationProcess
);
@ -340,11 +351,11 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
final TableReference lhsTableReference = targetSideTableGroup.resolveTableReference(
targetSideTableGroup.getNavigablePath(),
targetTable
);
final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference( keyTable );
final TableReference rhsTableKeyReference = keySideTableGroup.resolveTableReference( keyTable );
return generateJoinPredicate(
lhsTableReference,

View File

@ -6,42 +6,66 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
import org.hibernate.sql.ast.tree.from.OneToManyTableGroup;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.collection.internal.EntityCollectionPartTableGroup;
import org.hibernate.sql.results.graph.entity.EntityFetch;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl;
import org.hibernate.tuple.IdentifierProperty;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -53,8 +77,10 @@ public class EntityCollectionPart
private final CollectionPersister collectionDescriptor;
private final Nature nature;
private final EntityMappingType entityMappingType;
private final Set<String> targetKeyPropertyNames;
private ModelPart fkTargetModelPart;
private ForeignKeyDescriptor fkDescriptor;
@SuppressWarnings("WeakerAccess")
public EntityCollectionPart(
@ -67,6 +93,81 @@ public class EntityCollectionPart
this.collectionDescriptor = collectionDescriptor;
this.nature = nature;
this.entityMappingType = entityMappingType;
final String referencedPropertyName;
if ( bootModelValue instanceof OneToMany ) {
referencedPropertyName = null;
}
else {
referencedPropertyName = ( (ToOne) bootModelValue ).getReferencedPropertyName();
}
if ( referencedPropertyName == null ) {
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
targetKeyPropertyNames.add( EntityIdentifierMapping.ROLE_LOCAL_NAME );
final IdentifierProperty identifierProperty = getEntityMappingType()
.getEntityPersister()
.getEntityMetamodel()
.getIdentifierProperty();
final Type propertyType = identifierProperty.getType();
if ( identifierProperty.getName() == null ) {
final CompositeType compositeType;
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
compositeType.getPropertyNames()[0],
compositeType.getSubtypes()[0],
creationProcess.getCreationContext().getSessionFactory()
);
}
else {
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
null,
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
}
}
else {
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
identifierProperty.getName(),
propertyType,
creationProcess.getCreationContext().getSessionFactory()
);
}
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else if ( bootModelValue instanceof OneToMany ) {
this.targetKeyPropertyNames = Collections.singleton( referencedPropertyName );
}
else {
final EntityMetamodel entityMetamodel = entityMappingType.getEntityPersister().getEntityMetamodel();
final int propertyIndex = entityMetamodel.getPropertyIndex( referencedPropertyName );
final Type propertyType = entityMetamodel.getPropertyTypes()[propertyIndex];
final CompositeType compositeType;
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {
this.targetKeyPropertyNames = Collections.singleton( compositeType.getPropertyNames()[0] );
}
else {
final String mapsIdAttributeName;
if ( ( mapsIdAttributeName = ToOneAttributeMapping.mapsId( entityMappingType, referencedPropertyName ) ) != null ) {
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
targetKeyPropertyNames.add( referencedPropertyName );
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
mapsIdAttributeName,
entityMappingType.getEntityPersister().getIdentifierType(),
creationProcess.getCreationContext().getSessionFactory()
);
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else {
this.targetKeyPropertyNames = Collections.singleton( referencedPropertyName );
}
}
}
}
@SuppressWarnings("WeakerAccess")
@ -81,8 +182,80 @@ public class EntityCollectionPart
else {
fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null );
}
if ( nature == Nature.ELEMENT ) {
fkDescriptor = createForeignKeyDescriptor(
bootValueMapping.getElement(),
(EntityType) collectionDescriptor.getElementType(),
creationProcess,
collectionDescriptor.getFactory().getJdbcServices().getDialect()
);
}
else {
fkDescriptor = createForeignKeyDescriptor(
( (IndexedCollection) bootValueMapping).getIndex(),
(EntityType) collectionDescriptor.getIndexType(),
creationProcess,
collectionDescriptor.getFactory().getJdbcServices().getDialect()
);
}
}
private ForeignKeyDescriptor createForeignKeyDescriptor(
Value fkBootDescriptorSource,
EntityType entityType,
MappingModelCreationProcess creationProcess,
Dialect dialect) {
final EntityPersister associatedEntityDescriptor = creationProcess.getEntityPersister( entityType.getAssociatedEntityName() );
final ModelPart fkTargetPart = entityType.isReferenceToPrimaryKey()
? associatedEntityDescriptor.getIdentifierMapping()
: associatedEntityDescriptor.findSubPart( entityType.getRHSUniqueKeyPropertyName() );
if ( fkTargetPart instanceof BasicValuedModelPart ) {
final BasicValuedModelPart basicFkTargetPart = (BasicValuedModelPart) fkTargetPart;
final Joinable collectionDescriptorAsJoinable = (Joinable) collectionDescriptor;
final SelectableMapping keySelectableMapping = SelectableMappingImpl.from(
collectionDescriptorAsJoinable.getTableName(),
fkBootDescriptorSource.getColumnIterator().next(),
basicFkTargetPart.getJdbcMapping(),
dialect,
creationProcess.getSqmFunctionRegistry()
);
final boolean hasConstraint;
if ( fkBootDescriptorSource instanceof SimpleValue ) {
hasConstraint = ( (SimpleValue) fkBootDescriptorSource ).isConstrained();
}
else {
// We assume there is a constraint if the key is not nullable
hasConstraint = !fkBootDescriptorSource.isNullable();
}
return new SimpleForeignKeyDescriptor(
associatedEntityDescriptor,
basicFkTargetPart,
null,
keySelectableMapping,
basicFkTargetPart,
entityType.isReferenceToPrimaryKey(),
hasConstraint
);
}
else if ( fkTargetPart instanceof EmbeddableValuedModelPart ) {
return MappingModelCreationHelper.buildEmbeddableForeignKeyDescriptor(
(EmbeddableValuedModelPart) fkTargetPart,
fkBootDescriptorSource,
findContainingEntityMapping(),
collectionDescriptor.getAttributeMapping(),
false,
dialect,
creationProcess
);
}
else {
throw new NotYetImplementedFor6Exception(
"Support for composite foreign keys not yet implemented : " + collectionDescriptor
.getRole()
);
}
}
@Override
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
@ -146,22 +319,24 @@ public class EntityCollectionPart
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
creationState.registerVisitedAssociationKey( getForeignKeyDescriptor().getAssociationKey() );
TableGroup tableGroup = fromClauseAccess.resolveTableGroup(
final TableGroup partTableGroup = fromClauseAccess.resolveTableGroup(
fetchablePath,
np -> {
// We need to create one. The Result will be able to find it later by path
final TableGroup parentTableGroup = fromClauseAccess.getTableGroup( np.getParent() );
if ( collectionDescriptor.isOneToMany() && nature == Nature.ELEMENT ) {
return ( (OneToManyTableGroup) parentTableGroup ).getElementTableGroup();
}
for ( TableGroupJoin nestedTableGroupJoin : parentTableGroup.getNestedTableGroupJoins() ) {
if ( nestedTableGroupJoin.getNavigablePath().equals( np ) ) {
return nestedTableGroupJoin.getJoinedGroup();
}
}
// first, find the collection's TableGroup
final TableGroup collectionTableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath() );
assert collectionTableGroup != null;
// create a "wrapper" around the collection TableGroup adding in the entity's table references
return new EntityCollectionPartTableGroup( fetchablePath, collectionTableGroup, this );
throw new IllegalStateException( "Could not find table group for: " + np );
}
);
return new EntityFetchJoinedImpl( fetchParent, this, tableGroup, selected, fetchablePath, creationState );
return new EntityFetchJoinedImpl( fetchParent, this, partTableGroup, selected, fetchablePath, creationState );
}
@Override
@ -184,15 +359,20 @@ public class EntityCollectionPart
final TableGroup partTableGroup = fromClauseAccess.resolveTableGroup(
navigablePath,
np -> {
// We need to create one. The Result will be able to find it later by path
// first, find the collection's TableGroup
final TableGroup collectionTableGroup = fromClauseAccess.getTableGroup( np.getParent() );
assert collectionTableGroup != null;
// create a "wrapper" around the collection TableGroup adding in the entity's table references
return new EntityCollectionPartTableGroup( np, collectionTableGroup, this );
final TableGroup parentTableGroup = fromClauseAccess.getTableGroup( np.getParent() );
if ( collectionDescriptor.isOneToMany() && nature == Nature.ELEMENT ) {
return ( (OneToManyTableGroup) parentTableGroup ).getElementTableGroup();
}
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
navigablePath,
parentTableGroup,
resultVariable,
SqlAstJoinType.INNER,
true,
creationState.getSqlAstCreationState()
);
parentTableGroup.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin.getJoinedGroup();
}
);
@ -247,8 +427,7 @@ public class EntityCollectionPart
@Override
public ForeignKeyDescriptor getForeignKeyDescriptor() {
// todo (6.0) : this will not strictly work - we'd want a new ForeignKeyDescriptor that points the other direction
return collectionDescriptor.getAttributeMapping().getKeyDescriptor();
return fkDescriptor;
}
@Override
@ -269,27 +448,60 @@ public class EntityCollectionPart
@Override
public TableGroupJoin createTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
TableGroup collectionTableGroup,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return collectionDescriptor.getAttributeMapping().createTableGroupJoin(
if ( collectionDescriptor.isOneToMany() && nature == Nature.ELEMENT ) {
// If this is a one-to-many, the element part is already available, so we return a TableGroupJoin "hull"
return new TableGroupJoin(
navigablePath,
sqlAstJoinType,
( (OneToManyTableGroup) collectionTableGroup ).getElementTableGroup(),
null
);
}
final LazyTableGroup lazyTableGroup = createRootTableGroupJoin(
navigablePath,
lhs,
collectionTableGroup,
explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
final TableGroupJoin join = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
lazyTableGroup,
null
);
final TableReference keySideTableReference = collectionTableGroup.getPrimaryTableReference();
lazyTableGroup.setTableGroupInitializerCallback(
tableGroup -> join.applyPredicate(
fkDescriptor.generateJoinPredicate(
tableGroup.getPrimaryTableReference(),
keySideTableReference,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
)
);
return join;
}
@Override
public TableGroup createRootTableGroupJoin(
public LazyTableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
@ -299,17 +511,101 @@ public class EntityCollectionPart
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return collectionDescriptor.getAttributeMapping().createRootTableGroupJoin(
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
final boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins();
final LazyTableGroup lazyTableGroup = new LazyTableGroup(
canUseInnerJoin,
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
predicateConsumer,
aliasBaseGenerator,
() -> createTableGroupInternal(
canUseInnerJoin,
navigablePath,
fetched,
null,
sqlAliasBase,
sqlExpressionResolver,
creationContext
),
(np, tableExpression) -> {
NavigablePath path = np.getParent();
// Fast path
if ( path != null && navigablePath.equals( path ) ) {
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() )
&& fkDescriptor.getKeyTable().equals( tableExpression );
}
final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
sb.append( np.getUnaliasedLocalName() );
while ( path != null && !navigablePath.equals( path ) ) {
sb.insert( 0, '.' );
sb.insert( 0, path.getUnaliasedLocalName() );
path = path.getParent();
}
return path != null && navigablePath.equals( path )
&& targetKeyPropertyNames.contains( sb.toString() )
&& fkDescriptor.getKeyTable().equals( tableExpression );
},
this,
explicitSourceAlias,
sqlAliasBase,
creationContext.getSessionFactory(),
lhs
);
if ( predicateConsumer != null ) {
final TableReference keySideTableReference = lhs.resolveTableReference(
navigablePath,
fkDescriptor.getKeyTable()
);
lazyTableGroup.setTableGroupInitializerCallback(
tableGroup -> predicateConsumer.accept(
fkDescriptor.generateJoinPredicate(
tableGroup.getPrimaryTableReference(),
keySideTableReference,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
)
);
}
return lazyTableGroup;
}
public TableGroup createTableGroupInternal(
boolean canUseInnerJoins,
NavigablePath navigablePath,
boolean fetched,
String sourceAlias,
final SqlAliasBase sqlAliasBase,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableReference primaryTableReference = getEntityMappingType().createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
return new StandardTableGroup(
canUseInnerJoins,
navigablePath,
this,
fetched,
sourceAlias,
primaryTableReference,
false,
sqlAliasBase,
(tableExpression) -> getEntityMappingType().containsTableReference( tableExpression ),
(tableExpression, tg) -> getEntityMappingType().createTableReferenceJoin(
tableExpression,
sqlAliasBase,
primaryTableReference,
sqlExpressionResolver,
creationContext
),
creationContext.getSessionFactory()
);
}
@Override

View File

@ -200,7 +200,6 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
fetchParent,
fetchablePath,
this,
false,
null,
fetchTiming,
creationState

View File

@ -76,6 +76,7 @@ import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.collection.SQLLoadableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
@ -84,6 +85,7 @@ import org.hibernate.property.access.internal.ChainedPropertyAccessImpl;
import org.hibernate.property.access.internal.PropertyAccessStrategyMapImpl;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.type.AnyType;
import org.hibernate.type.AssociationType;
@ -908,6 +910,17 @@ public class MappingModelCreationHelper {
final ModelPart fkTarget;
final String lhsPropertyName = collectionDescriptor.getCollectionType().getLHSPropertyName();
final boolean isReferenceToPrimaryKey = lhsPropertyName == null;
final ManagedMappingType keyDeclaringType;
if ( collectionDescriptor.getElementType().isEntityType() ) {
keyDeclaringType = ( (QueryableCollection) collectionDescriptor ).getElementPersister();
}
else {
// This is not "really correct" but it is as good as it gets.
// The key declaring type serves as declaring type for the inverse model part of a FK.
// Most of the time, there is a proper managed type, but not for basic collections.
// Since the declaring type is needed for certain operations, we use the one from the target side of the FK
keyDeclaringType = declaringType;
}
if ( isReferenceToPrimaryKey ) {
fkTarget = collectionDescriptor.getOwnerEntityPersister().getIdentifierMapping();
}
@ -929,6 +942,7 @@ public class MappingModelCreationHelper {
);
attributeMapping.setForeignKeyDescriptor(
new SimpleForeignKeyDescriptor(
keyDeclaringType,
simpleFkTarget,
null,
keySelectableMapping,
@ -943,6 +957,9 @@ public class MappingModelCreationHelper {
buildEmbeddableForeignKeyDescriptor(
(EmbeddableValuedModelPart) fkTarget,
bootValueMapping,
keyDeclaringType,
collectionDescriptor.getAttributeMapping(),
false,
dialect,
creationProcess
);
@ -1025,6 +1042,8 @@ public class MappingModelCreationHelper {
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor(
(EmbeddableValuedModelPart) modelPart,
bootValueMapping,
attributeMapping.getDeclaringType(),
attributeMapping.findContainingEntityMapping(),
true,
dialect,
creationProcess
@ -1058,12 +1077,15 @@ public class MappingModelCreationHelper {
if ( inversePropertyAccess == null ) {
// So far, OneToOne mappings are only supported based on the owner's PK
if ( bootValueMapping instanceof OneToOne ) {
declaringKeyPart = (BasicValuedModelPart) attributeMapping.findContainingEntityMapping().getIdentifierMapping();
declaringKeyPart = simpleFkTarget;
final EntityIdentifierMapping identifierMapping = attributeMapping.findContainingEntityMapping()
.getIdentifierMapping();
declaringKeyPropertyAccess = ( (PropertyBasedMapping) identifierMapping ).getPropertyAccess();
}
else {
declaringKeyPart = simpleFkTarget;
declaringKeyPropertyAccess = ( (PropertyBasedMapping) declaringKeyPart ).getPropertyAccess();
}
declaringKeyPropertyAccess = ( (PropertyBasedMapping) declaringKeyPart ).getPropertyAccess();
}
else {
declaringKeyPart = simpleFkTarget;
@ -1094,6 +1116,7 @@ public class MappingModelCreationHelper {
}
final ForeignKeyDescriptor foreignKeyDescriptor = new SimpleForeignKeyDescriptor(
attributeMapping.getDeclaringType(),
declaringKeyPart,
declaringKeyPropertyAccess,
keySelectableMapping,
@ -1108,6 +1131,8 @@ public class MappingModelCreationHelper {
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor(
(EmbeddableValuedModelPart) fkTarget,
bootValueMapping,
attributeMapping.getDeclaringType(),
attributeMapping.findContainingEntityMapping(),
swapDirection,
dialect,
creationProcess
@ -1179,20 +1204,8 @@ public class MappingModelCreationHelper {
public static EmbeddedForeignKeyDescriptor buildEmbeddableForeignKeyDescriptor(
EmbeddableValuedModelPart embeddableValuedModelPart,
Value bootValueMapping,
Dialect dialect,
MappingModelCreationProcess creationProcess) {
return buildEmbeddableForeignKeyDescriptor(
embeddableValuedModelPart,
bootValueMapping,
false,
dialect,
creationProcess
);
}
private static EmbeddedForeignKeyDescriptor buildEmbeddableForeignKeyDescriptor(
EmbeddableValuedModelPart embeddableValuedModelPart,
Value bootValueMapping,
ManagedMappingType keyDeclaringType,
TableGroupProducer keyDeclaringTableGroupProducer,
boolean inverse,
Dialect dialect,
MappingModelCreationProcess creationProcess) {
@ -1241,6 +1254,8 @@ public class MappingModelCreationHelper {
embeddableValuedModelPart,
EmbeddedAttributeMapping.createInverseModelPart(
embeddableValuedModelPart,
keyDeclaringType,
keyDeclaringTableGroupProducer,
keySelectableMappings,
creationProcess
),
@ -1256,6 +1271,8 @@ public class MappingModelCreationHelper {
return new EmbeddedForeignKeyDescriptor(
EmbeddedAttributeMapping.createInverseModelPart(
embeddableValuedModelPart,
keyDeclaringType,
keyDeclaringTableGroupProducer,
keySelectableMappings,
creationProcess
),

View File

@ -19,6 +19,7 @@ import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
@ -175,7 +176,7 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
@Override
public String getFetchableName() {
return "id";
return EntityIdentifierMapping.ROLE_LOCAL_NAME;
}
@Override

View File

@ -6,14 +6,11 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.ArrayList;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
@ -21,31 +18,24 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.mapping.List;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.CollectionMappingType;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
import org.hibernate.metamodel.mapping.ordering.OrderByFragmentTranslator;
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
@ -58,11 +48,11 @@ import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.CollectionTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.from.OneToManyTableGroup;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
@ -74,7 +64,6 @@ import org.hibernate.sql.results.graph.collection.internal.DelayedCollectionFetc
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
import org.hibernate.sql.results.graph.collection.internal.SelectEagerCollectionFetch;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.type.EntityType;
import org.jboss.logging.Logger;
@ -113,45 +102,10 @@ public class PluralAttributeMappingImpl
private final IndexMetadata indexMetadata;
private ForeignKeyDescriptor fkDescriptor;
private ForeignKeyDescriptor elementFkDescriptor;
private ForeignKeyDescriptor indexFkDescriptor;
private OrderByFragment orderByFragment;
private OrderByFragment manyToManyOrderByFragment;
@SuppressWarnings({"WeakerAccess", "rawtypes"})
public PluralAttributeMappingImpl(
String attributeName,
Collection bootDescriptor,
PropertyAccess propertyAccess,
StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess,
CollectionMappingType collectionMappingType,
int stateArrayPosition,
CollectionPart elementDescriptor,
CollectionPart indexDescriptor,
CollectionIdentifierDescriptor identifierDescriptor,
FetchOptions fetchOptions,
CascadeStyle cascadeStyle,
ManagedMappingType declaringType,
CollectionPersister collectionDescriptor) {
this(
attributeName,
bootDescriptor,
propertyAccess,
stateArrayContributorMetadataAccess,
collectionMappingType,
stateArrayPosition,
elementDescriptor,
indexDescriptor,
identifierDescriptor,
fetchOptions.getTiming(),
fetchOptions.getStyle(),
cascadeStyle,
declaringType,
collectionDescriptor
);
}
@SuppressWarnings({"WeakerAccess", "rawtypes"})
public PluralAttributeMappingImpl(
String attributeName,
@ -243,40 +197,6 @@ public class PluralAttributeMappingImpl
Property bootProperty,
Collection bootDescriptor,
MappingModelCreationProcess creationProcess) {
final Dialect dialect = creationProcess.getCreationContext()
.getSessionFactory()
.getJdbcServices()
.getDialect();
if ( collectionDescriptor.getElementType() instanceof EntityType ) {
creationProcess.registerForeignKeyPostInitCallbacks(
"To-many key - " + getNavigableRole(),
() -> {
elementFkDescriptor = createForeignKeyDescriptor(
bootDescriptor.getElement(),
(EntityType) collectionDescriptor.getElementType(),
creationProcess,
dialect
);
return true;
}
);
}
if ( collectionDescriptor.getIndexType() instanceof EntityType ) {
creationProcess.registerForeignKeyPostInitCallbacks(
"To-many index - " + getNavigableRole(),
() -> {
indexFkDescriptor = createForeignKeyDescriptor(
( (IndexedCollection) bootDescriptor ).getIndex(),
(EntityType) collectionDescriptor.getIndexType(),
creationProcess,
dialect
);
return true;
}
);
}
final boolean hasOrder = bootDescriptor.getOrderBy() != null;
final boolean hasManyToManyOrder = bootDescriptor.getManyToManyOrdering() != null;
@ -315,59 +235,6 @@ public class PluralAttributeMappingImpl
}
}
private ForeignKeyDescriptor createForeignKeyDescriptor(
Value fkBootDescriptorSource,
EntityType entityType,
MappingModelCreationProcess creationProcess,
Dialect dialect) {
final EntityPersister associatedEntityDescriptor = creationProcess.getEntityPersister( entityType.getAssociatedEntityName() );
final ModelPart fkTargetPart = entityType.isReferenceToPrimaryKey()
? associatedEntityDescriptor.getIdentifierMapping()
: associatedEntityDescriptor.findSubPart( entityType.getRHSUniqueKeyPropertyName() );
if ( fkTargetPart instanceof BasicValuedModelPart ) {
final BasicValuedModelPart basicFkTargetPart = (BasicValuedModelPart) fkTargetPart;
final Joinable collectionDescriptorAsJoinable = (Joinable) collectionDescriptor;
final SelectableMapping keySelectableMapping = SelectableMappingImpl.from(
collectionDescriptorAsJoinable.getTableName(),
fkBootDescriptorSource.getColumnIterator().next(),
basicFkTargetPart.getJdbcMapping(),
dialect,
creationProcess.getSqmFunctionRegistry()
);
final boolean hasConstraint;
if ( fkBootDescriptorSource instanceof SimpleValue ) {
hasConstraint = ( (SimpleValue) fkBootDescriptorSource ).isConstrained();
}
else {
// We assume there is a constraint if the key is not nullable
hasConstraint = !fkBootDescriptorSource.isNullable();
}
return new SimpleForeignKeyDescriptor(
basicFkTargetPart,
null,
keySelectableMapping,
basicFkTargetPart,
entityType.isReferenceToPrimaryKey(),
hasConstraint
);
}
else if ( fkTargetPart instanceof EmbeddableValuedModelPart ) {
return MappingModelCreationHelper.buildEmbeddableForeignKeyDescriptor(
(EmbeddableValuedModelPart) fkTargetPart,
fkBootDescriptorSource,
dialect,
creationProcess
);
}
else {
throw new NotYetImplementedFor6Exception(
"Support for composite foreign keys not yet implemented : " + collectionDescriptor
.getRole()
);
}
}
@Override
public NavigableRole getNavigableRole() {
return getCollectionDescriptor().getNavigableRole();
@ -482,6 +349,10 @@ public class PluralAttributeMappingImpl
assert collectionTableGroup != null;
// This is only used for collection initialization where we know the owner is available, so we mark it as visited
// which will cause bidirectional to-one associations to be treated as such and avoid a join
creationState.registerVisitedAssociationKey( fkDescriptor.getAssociationKey() );
//noinspection unchecked
return new CollectionDomainResult( navigablePath, this, resultVariable, tableGroup, creationState );
}
@ -498,7 +369,7 @@ public class PluralAttributeMappingImpl
creationState.registerVisitedAssociationKey( fkDescriptor.getAssociationKey() );
if ( fetchTiming == FetchTiming.IMMEDIATE) {
if ( fetchTiming == FetchTiming.IMMEDIATE ) {
if ( selected ) {
final TableGroup collectionTableGroup = resolveCollectionTableGroup(
fetchParent,
@ -628,29 +499,26 @@ public class PluralAttributeMappingImpl
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final java.util.List<Predicate> predicates = new ArrayList<>( 2 );
final TableGroup tableGroup = createRootTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
predicates::add,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
return new TableGroupJoin(
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
tableGroup,
getKeyDescriptor().generateJoinPredicate(
lhs,
tableGroup,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
null
);
predicates.forEach( tableGroupJoin::applyPredicate );
return tableGroupJoin;
}
@Override
@ -715,125 +583,36 @@ public class PluralAttributeMappingImpl
SqlAliasBase sqlAliasBase,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final EntityMappingType elementDescriptorEntityMappingType;
if ( elementDescriptor instanceof EntityCollectionPart ) {
elementDescriptorEntityMappingType = ( (EntityCollectionPart) elementDescriptor ).getEntityMappingType();
}
else {
assert indexDescriptor instanceof EntityCollectionPart;
elementDescriptorEntityMappingType = null;
}
final EntityMappingType indexDescriptorEntityMappingType;
if ( indexDescriptor instanceof EntityCollectionPart ) {
indexDescriptorEntityMappingType = ( (EntityCollectionPart) indexDescriptor ).getEntityMappingType();
}
else {
indexDescriptorEntityMappingType = null;
}
if ( indexDescriptorEntityMappingType == null || elementDescriptorEntityMappingType == null ) {
final EntityMappingType entityMappingType;
if ( indexDescriptorEntityMappingType == null ) {
entityMappingType = elementDescriptorEntityMappingType.getEntityMappingType();
}
else {
entityMappingType = indexDescriptorEntityMappingType.getEntityMappingType();
}
final TableReference primaryTableReference = entityMappingType
.createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
return new StandardTableGroup(
canUseInnerJoins,
navigablePath,
this,
fetched,
sourceAlias,
primaryTableReference,
true,
sqlAliasBase,
entityMappingType::containsTableReference,
(tableExpression, tg) -> entityMappingType.createTableReferenceJoin(
tableExpression,
sqlAliasBase,
primaryTableReference,
sqlExpressionResolver,
creationContext
),
creationContext.getSessionFactory()
);
}
final TableReference primaryTableReference = elementDescriptorEntityMappingType
.createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
final BiFunction<String, TableGroup, TableReferenceJoin> tableReferenceJoinCreator;
final java.util.function.Predicate<String> tableReferenceJoinNameChecker = createTableReferenceJoinNameChecker(
elementDescriptorEntityMappingType,
indexDescriptorEntityMappingType
);
final TableReference indexAssociatedPrimaryTable = indexDescriptorEntityMappingType.createPrimaryTableReference(
final TableGroup elementTableGroup = ( (EntityCollectionPart) elementDescriptor ).createTableGroupInternal(
canUseInnerJoins,
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
fetched,
sourceAlias,
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
final Function<TableGroup, TableReferenceJoin> indexTableGroupFinalizer = createTableGroupFinalizer(
sqlExpressionResolver,
creationContext,
primaryTableReference,
indexAssociatedPrimaryTable,
SqlAstJoinType.INNER,
indexFkDescriptor
);
tableReferenceJoinCreator = (tableExpression, tableGroup) -> {
if ( elementDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
return elementDescriptorEntityMappingType.createTableReferenceJoin(
tableExpression,
sqlAliasBase,
primaryTableReference,
sqlExpressionResolver,
creationContext
);
}
else if ( indexDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
return createTableReferenceJoin(
sqlExpressionResolver,
creationContext,
sqlAliasBase,
indexDescriptorEntityMappingType,
indexAssociatedPrimaryTable,
indexTableGroupFinalizer,
tableExpression,
tableGroup
);
}
throw new IllegalStateException( "could not create join for table `" + tableExpression + "`" );
};
return new StandardTableGroup(
canUseInnerJoins,
navigablePath,
final OneToManyTableGroup tableGroup = new OneToManyTableGroup(
this,
fetched,
sourceAlias,
primaryTableReference,
true,
sqlAliasBase,
tableReferenceJoinNameChecker,
tableReferenceJoinCreator,
elementTableGroup,
creationContext.getSessionFactory()
);
if ( indexDescriptor instanceof EntityCollectionPart ) {
final TableGroupJoin tableGroupJoin = ( (EntityCollectionPart) indexDescriptor ).createTableGroupJoin(
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
elementTableGroup,
null,
SqlAstJoinType.INNER,
fetched,
stem -> sqlAliasBase,
sqlExpressionResolver,
creationContext
);
tableGroup.registerIndexTableGroup( tableGroupJoin );
}
return tableGroup;
}
private TableGroup createCollectionTableGroup(
@ -854,116 +633,7 @@ public class PluralAttributeMappingImpl
creationContext.getSessionFactory()
);
final EntityMappingType elementDescriptorEntityMappingType;
if ( elementDescriptor instanceof EntityCollectionPart ) {
elementDescriptorEntityMappingType = ( (EntityCollectionPart) elementDescriptor ).getEntityMappingType();
}
else {
elementDescriptorEntityMappingType = null;
}
final EntityMappingType indexDescriptorEntityMappingType;
if ( indexDescriptor instanceof EntityCollectionPart ) {
indexDescriptorEntityMappingType = ( (EntityCollectionPart) indexDescriptor ).getEntityMappingType();
}
else {
indexDescriptorEntityMappingType = null;
}
final BiFunction<String, TableGroup, TableReferenceJoin> tableReferenceJoinCreator;
final java.util.function.Predicate<String> tableReferenceJoinNameChecker = createTableReferenceJoinNameChecker(
elementDescriptorEntityMappingType,
indexDescriptorEntityMappingType
);
final TableReference elementAssociatedPrimaryTable;
final Function<TableGroup, TableReferenceJoin> elementTableGroupFinalizer;
// todo (6.0) : not sure it is
if ( elementDescriptorEntityMappingType != null ) {
elementAssociatedPrimaryTable = elementDescriptorEntityMappingType.createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
elementTableGroupFinalizer = createTableGroupFinalizer(
sqlExpressionResolver,
creationContext,
collectionTableReference,
elementAssociatedPrimaryTable,
SqlAstJoinType.INNER,
elementFkDescriptor
);
}
else {
elementAssociatedPrimaryTable = null;
elementTableGroupFinalizer = null;
}
TableReference indexAssociatedPrimaryTable;
final Function<TableGroup, TableReferenceJoin> indexTableGroupFinalizer;
if ( indexDescriptorEntityMappingType != null ) {
indexAssociatedPrimaryTable = indexDescriptorEntityMappingType.createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
indexTableGroupFinalizer = createTableGroupFinalizer(
sqlExpressionResolver,
creationContext,
collectionTableReference,
indexAssociatedPrimaryTable,
SqlAstJoinType.INNER,
indexFkDescriptor
);
}
else {
indexAssociatedPrimaryTable = null;
indexTableGroupFinalizer = null;
}
if ( elementDescriptorEntityMappingType != null || indexDescriptorEntityMappingType != null ) {
tableReferenceJoinCreator = (tableExpression, tableGroup) -> {
if ( elementDescriptorEntityMappingType != null
&& elementDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
return createTableReferenceJoin(
sqlExpressionResolver,
creationContext,
sqlAliasBase,
elementDescriptorEntityMappingType,
elementAssociatedPrimaryTable,
elementTableGroupFinalizer,
tableExpression,
tableGroup
);
}
else if ( indexDescriptorEntityMappingType != null
&& indexDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
return createTableReferenceJoin(
sqlExpressionResolver,
creationContext,
sqlAliasBase,
indexDescriptorEntityMappingType,
indexAssociatedPrimaryTable,
indexTableGroupFinalizer,
tableExpression,
tableGroup
);
}
throw new IllegalStateException( "could not create join for table `" + tableExpression + "`" );
};
}
else {
tableReferenceJoinCreator = (tableExpression, tableGroup) -> {
throw new UnsupportedOperationException(
"element-collection cannot contain joins : " + collectionTableReference.getTableExpression() + " -> " + tableExpression
);
};
}
final StandardTableGroup tableGroup = new StandardTableGroup(
final CollectionTableGroup tableGroup = new CollectionTableGroup(
canUseInnerJoins,
navigablePath,
this,
@ -972,86 +642,39 @@ public class PluralAttributeMappingImpl
collectionTableReference,
true,
sqlAliasBase,
tableReferenceJoinNameChecker,
tableReferenceJoinCreator,
s -> false,
null,
creationContext.getSessionFactory()
);
return tableGroup;
}
private TableReferenceJoin createTableReferenceJoin(
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext,
SqlAliasBase sqlAliasBase,
EntityMappingType elementDescriptorEntityMappingType,
TableReference elementAssociatedPrimaryTable,
Function<TableGroup, TableReferenceJoin> elementTableGroupFinalizer,
String tableExpression, TableGroup tableGroup) {
TableReferenceJoin elementTableReferenceJoin;
if ( elementAssociatedPrimaryTable.getTableExpression().equals( tableExpression ) ) {
return elementTableGroupFinalizer.apply( tableGroup );
}
else {
StandardTableGroup standardTableGroup = (StandardTableGroup) tableGroup;
if ( standardTableGroup.getTableReferenceJoins().isEmpty() ) {
elementTableReferenceJoin = elementTableGroupFinalizer.apply( tableGroup );
}
else {
elementTableReferenceJoin = null;
}
}
final TableReferenceJoin tableReferenceJoin = elementDescriptorEntityMappingType.createTableReferenceJoin(
tableExpression,
sqlAliasBase,
elementAssociatedPrimaryTable,
sqlExpressionResolver,
creationContext
);
if ( tableReferenceJoin != null && elementTableReferenceJoin != null ) {
( (StandardTableGroup) tableGroup ).addTableReferenceJoin( elementTableReferenceJoin );
return tableReferenceJoin;
}
return elementTableReferenceJoin == null ? tableReferenceJoin : elementTableReferenceJoin;
}
private Function<TableGroup, TableReferenceJoin> createTableGroupFinalizer(
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext,
TableReference collectionTableReference,
TableReference elementAssociatedPrimaryTable,
SqlAstJoinType joinType,
ForeignKeyDescriptor elementFkDescriptor) {
return tableGroup -> {
final TableReferenceJoin associationJoin = new TableReferenceJoin(
joinType,
elementAssociatedPrimaryTable,
elementFkDescriptor.generateJoinPredicate(
elementAssociatedPrimaryTable,
collectionTableReference,
joinType,
sqlExpressionResolver,
creationContext
)
if ( indexDescriptor instanceof EntityCollectionPart ) {
final TableGroupJoin tableGroupJoin = ( (EntityCollectionPart) indexDescriptor ).createTableGroupJoin(
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
tableGroup,
null,
SqlAstJoinType.INNER,
fetched,
stem -> sqlAliasBase,
sqlExpressionResolver,
creationContext
);
return associationJoin;
};
}
tableGroup.registerIndexTableGroup( tableGroupJoin );
}
if ( elementDescriptor instanceof EntityCollectionPart ) {
final TableGroupJoin tableGroupJoin = ( (EntityCollectionPart) elementDescriptor ).createTableGroupJoin(
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
tableGroup,
null,
SqlAstJoinType.INNER,
fetched,
stem -> sqlAliasBase,
sqlExpressionResolver,
creationContext
);
tableGroup.registerElementTableGroup( tableGroupJoin );
}
private java.util.function.Predicate<String> createTableReferenceJoinNameChecker(
EntityMappingType elementDescriptorEntityMappingType,
EntityMappingType indexDescriptorEntityMappingType) {
return tableExpression -> {
if ( elementDescriptorEntityMappingType != null
&& elementDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
return true;
}
if ( indexDescriptorEntityMappingType != null
&& indexDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
return true;
}
return false;
};
return tableGroup;
}
@Override
@ -1068,7 +691,7 @@ public class PluralAttributeMappingImpl
explicitSourceAlias,
additionalPredicateCollectorAccess,
creationState.getSqlAliasBaseGenerator().createSqlAliasBase( getSqlAliasStem() ),
creationState,
creationState.getSqlExpressionResolver(),
creationContext
);
}
@ -1080,7 +703,7 @@ public class PluralAttributeMappingImpl
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlAstCreationState creationState,
SqlExpressionResolver expressionResolver,
SqlAstCreationContext creationContext) {
if ( getCollectionDescriptor().isOneToMany() ) {
return createOneToManyTableGroup(
@ -1089,7 +712,7 @@ public class PluralAttributeMappingImpl
false,
explicitSourceAlias,
sqlAliasBase,
creationState.getSqlExpressionResolver(),
expressionResolver,
creationContext
);
}
@ -1100,7 +723,7 @@ public class PluralAttributeMappingImpl
false,
explicitSourceAlias,
sqlAliasBase,
creationState.getSqlExpressionResolver(),
expressionResolver,
creationContext
);
}

View File

@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PropertyBasedMapping;
@ -37,8 +38,8 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver;
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.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult;
@ -61,16 +62,18 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
private AssociationKey associationKey;
public SimpleForeignKeyDescriptor(
ManagedMappingType keyDeclaringType,
BasicValuedModelPart keyModelPart,
PropertyAccess keyPropertyAccess,
SelectableMapping keySelectableMapping,
BasicValuedModelPart targetModelPart,
boolean refersToPrimaryKey,
boolean hasConstraint) {
this( keyModelPart, keyPropertyAccess, keySelectableMapping, targetModelPart, refersToPrimaryKey, hasConstraint, false );
this( keyDeclaringType, keyModelPart, keyPropertyAccess, keySelectableMapping, targetModelPart, refersToPrimaryKey, hasConstraint, false );
}
public SimpleForeignKeyDescriptor(
ManagedMappingType keyDeclaringType,
BasicValuedModelPart keyModelPart,
PropertyAccess keyPropertyAccess,
SelectableMapping keySelectableMapping,
@ -82,6 +85,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
assert targetModelPart != null;
keyModelPart = BasicAttributeMapping.withSelectableMapping(
keyDeclaringType,
keyModelPart,
keyPropertyAccess,
NoValueGeneration.INSTANCE,
@ -131,9 +135,12 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
@Override
public ForeignKeyDescriptor withKeySelectionMapping(
ManagedMappingType declaringType,
TableGroupProducer declaringTableGroupProducer,
IntFunction<SelectableMapping> selectableMappingAccess,
MappingModelCreationProcess creationProcess) {
return new SimpleForeignKeyDescriptor(
declaringType,
keySide.getModelPart(),
( (PropertyBasedMapping) keySide.getModelPart() ).getPropertyAccess(),
selectableMappingAccess.apply( 0 ),
@ -148,8 +155,6 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
assert tableGroup.getTableReference( navigablePath, keySide.getModelPart().getContainingTableExpression() ) != null;
return createDomainResult(
navigablePath,
tableGroup,
@ -160,8 +165,6 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
@Override
public DomainResult<?> createTargetDomainResult(NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState) {
assert tableGroup.getTableReference( navigablePath, targetSide.getModelPart().getContainingTableExpression() ) != null;
return createDomainResult(
navigablePath,
tableGroup,
@ -210,7 +213,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
final TableReference tableReference = tableGroup.resolveTableReference(
navigablePath.append( getNavigableRole().getNavigableName() ),
navigablePath.append( getTargetPart().getFetchableName() ),
selectableMapping.getContainingTableExpression()
);
final String identificationVariable = tableReference.getIdentificationVariable();
@ -269,11 +272,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
final TableReference lhsTableReference = targetSideTableGroup.resolveTableReference(
targetSideTableGroup.getNavigablePath(),
targetSide.getModelPart().getContainingTableExpression()
);
final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference(
final TableReference rhsTableKeyReference = keySideTableGroup.resolveTableReference(
keySide.getModelPart().getContainingTableExpression()
);
@ -287,7 +290,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
}
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
final NavigablePath navigablePath = lhs.getNavigablePath().append( getNavigableRole().getNavigableName() );
final NavigablePath navigablePath = lhs.getNavigablePath().append( getTargetPart().getFetchableName() );
if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) {
return lhs.getPrimaryTableReference();
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
@ -17,6 +18,7 @@ import org.hibernate.LockMode;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
@ -48,6 +50,7 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.EntityIdentifierNavigablePath;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.TreatedNavigablePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.FromClauseAccess;
@ -86,6 +89,7 @@ import org.hibernate.tuple.IdentifierProperty;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
/**
@ -360,22 +364,50 @@ public class ToOneAttributeMapping
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {
this.targetKeyPropertyName = compositeType.getPropertyNames()[0];
addPrefixedPropertyNames( targetKeyPropertyNames, targetKeyPropertyName, compositeType.getSubtypes()[0] );
addPrefixedPropertyNames(
targetKeyPropertyNames,
targetKeyPropertyName,
compositeType.getSubtypes()[0],
declaringEntityPersister.getFactory()
);
}
else {
this.targetKeyPropertyName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
addPrefixedPropertyNames( targetKeyPropertyNames, null, propertyType );
addPrefixedPropertyNames(
targetKeyPropertyNames,
null,
propertyType,
declaringEntityPersister.getFactory()
);
addPrefixedPropertyNames(
targetKeyPropertyNames,
targetKeyPropertyName,
propertyType,
declaringEntityPersister.getFactory()
);
}
}
else {
this.targetKeyPropertyName = identifierProperty.getName();
addPrefixedPropertyNames( targetKeyPropertyNames, targetKeyPropertyName, propertyType );
addPrefixedPropertyNames(
targetKeyPropertyNames,
targetKeyPropertyName,
propertyType,
declaringEntityPersister.getFactory()
);
}
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else if ( bootValue.isReferenceToPrimaryKey() ) {
this.targetKeyPropertyName = referencedPropertyName;
this.targetKeyPropertyNames = Collections.singleton( targetKeyPropertyName );
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
addPrefixedPropertyNames(
targetKeyPropertyNames,
targetKeyPropertyName,
bootValue.getType(),
declaringEntityPersister.getFactory()
);
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else {
final EntityMetamodel entityMetamodel = entityMappingType.getEntityPersister().getEntityMetamodel();
@ -389,18 +421,35 @@ public class ToOneAttributeMapping
}
else {
this.targetKeyPropertyName = referencedPropertyName;
this.targetKeyPropertyNames = Collections.singleton( targetKeyPropertyName );
final String mapsIdAttributeName;
if ( ( mapsIdAttributeName = mapsId( entityMappingType, referencedPropertyName ) ) != null ) {
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
targetKeyPropertyNames.add( targetKeyPropertyName );
addPrefixedPropertyNames(
targetKeyPropertyNames,
mapsIdAttributeName,
entityMappingType.getEntityPersister().getIdentifierType(),
declaringEntityPersister.getFactory()
);
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else {
this.targetKeyPropertyNames = Collections.singleton( targetKeyPropertyName );
}
}
}
}
private ToOneAttributeMapping(ToOneAttributeMapping original) {
private ToOneAttributeMapping(
ToOneAttributeMapping original,
ManagedMappingType declaringType,
TableGroupProducer declaringTableGroupProducer) {
super(
original.getAttributeName(),
original.getStateArrayPosition(),
original.getAttributeMetadataAccess(),
original,
original.getDeclaringType(),
declaringType,
original.getPropertyAccess(),
original.getValueGeneration()
);
@ -417,7 +466,7 @@ public class ToOneAttributeMapping
this.targetKeyPropertyNames = original.targetKeyPropertyNames;
this.cardinality = original.cardinality;
this.bidirectionalAttributeName = original.bidirectionalAttributeName;
this.declaringTableGroupProducer = original.declaringTableGroupProducer;
this.declaringTableGroupProducer = declaringTableGroupProducer;
this.isConstrained = original.isConstrained;
}
@ -438,10 +487,19 @@ public class ToOneAttributeMapping
return true;
}
private static void addPrefixedPropertyNames(
static String mapsId(EntityMappingType entityMappingType, String referencedPropertyName) {
final AbstractEntityPersister persister = (AbstractEntityPersister) entityMappingType.getEntityPersister();
if ( Arrays.equals( persister.getKeyColumnNames(), persister.getPropertyColumnNames( referencedPropertyName ) ) ) {
return persister.getIdentifierPropertyName();
}
return null;
}
static void addPrefixedPropertyNames(
Set<String> targetKeyPropertyNames,
String prefix,
Type type) {
Type type,
SessionFactoryImplementor factory) {
if ( prefix != null ) {
targetKeyPropertyNames.add( prefix );
}
@ -457,13 +515,32 @@ public class ToOneAttributeMapping
else {
newPrefix = prefix + "." + propertyNames[i];
}
addPrefixedPropertyNames( targetKeyPropertyNames, newPrefix, componentTypeSubtypes[i] );
addPrefixedPropertyNames( targetKeyPropertyNames, newPrefix, componentTypeSubtypes[i], factory );
}
}
else if ( type.isEntityType() ) {
final EntityType entityType = (EntityType) type;
final Type identifierOrUniqueKeyType = entityType.getIdentifierOrUniqueKeyType( factory );
final String propertyName;
if ( entityType.isReferenceToPrimaryKey() ) {
propertyName = entityType.getAssociatedEntityPersister( factory ).getIdentifierPropertyName();
}
else {
propertyName = entityType.getRHSUniqueKeyPropertyName();
}
final String newPrefix;
if ( prefix == null ) {
newPrefix = propertyName;
}
else {
newPrefix = prefix + "." + propertyName;
}
addPrefixedPropertyNames( targetKeyPropertyNames, newPrefix, identifierOrUniqueKeyType, factory );
}
}
public ToOneAttributeMapping copy() {
return new ToOneAttributeMapping( this );
public ToOneAttributeMapping copy(ManagedMappingType declaringType, TableGroupProducer declaringTableGroupProducer) {
return new ToOneAttributeMapping( this, declaringType, declaringTableGroupProducer );
}
@Override
@ -538,7 +615,7 @@ public class ToOneAttributeMapping
public ModelPart findSubPart(String name, EntityMappingType targetType) {
// Prefer resolving the key part of the foreign key rather than the target part if possible
// This way, we don't have to register table groups the target entity type
if ( canUseParentTableGroup && name.equals( targetKeyPropertyName ) ) {
if ( canUseParentTableGroup && targetKeyPropertyNames.contains( name ) ) {
return foreignKeyDescriptor.getKeyPart();
}
return EntityValuedFetchable.super.findSubPart( name, targetType );
@ -606,7 +683,7 @@ public class ToOneAttributeMapping
fetchablePath,
fetchParent,
parentNavigablePath,
LockMode.READ
creationState
);
}
@ -695,14 +772,17 @@ public class ToOneAttributeMapping
}
}
else if ( parentModelPart instanceof PluralAttributeMapping ) {
return ( (PluralAttributeMapping) parentModelPart ).isBidirectionalAttributeName( fetchablePath, this );
// The parent must be non-null. If it is null, the root is a CollectionResult
return parentNavigablePath.getParent() != null
&& ( (PluralAttributeMapping) parentModelPart ).isBidirectionalAttributeName( fetchablePath, this );
}
else if ( parentModelPart instanceof EntityCollectionPart ) {
NavigablePath parentOfParent = parentNavigablePath.getParent();
if ( parentOfParent instanceof EntityIdentifierNavigablePath ) {
parentOfParent = parentOfParent.getParent();
}
return ( (PluralAttributeMapping) creationState.resolveModelPart( parentOfParent ) )
// The parent must be non-null. If it is null, the root is a CollectionResult
return parentOfParent.getParent() != null && ( (PluralAttributeMapping) creationState.resolveModelPart( parentOfParent ) )
.isBidirectionalAttributeName( fetchablePath, this );
}
return false;
@ -723,11 +803,18 @@ public class ToOneAttributeMapping
this.mappedBy = "biologicalChild"
parent.getFullPath() = "Mother.biologicalChild"
*/
final String fullPath = parentNavigablePath.getFullPath();
if ( fullPath.endsWith( bidirectionalAttributeName + "." + CollectionPart.Nature.ELEMENT.getName() ) ) {
final NavigablePath parentPath = parentNavigablePath.getParent().getParent();
final NavigablePath grandparentNavigablePath = parentNavigablePath.getParent();
if ( parentNavigablePath.getUnaliasedLocalName().equals( CollectionPart.Nature.ELEMENT.getName() )
&& grandparentNavigablePath != null
&& grandparentNavigablePath.getUnaliasedLocalName().equals( bidirectionalAttributeName ) ) {
final NavigablePath parentPath = grandparentNavigablePath.getParent();
// This can be null for a collection loader
if ( parentPath != null ) {
if ( parentPath == null ) {
return grandparentNavigablePath.getFullPath().equals(
entityMappingType.findSubPart( bidirectionalAttributeName ).getNavigableRole().getFullPath()
);
}
else {
// If the parent is null, this is a simple collection fetch of a root, in which case the types must match
if ( parentPath.getParent() == null ) {
final String entityName = entityMappingType.getPartName();
@ -756,22 +843,83 @@ public class ToOneAttributeMapping
NavigablePath fetchablePath,
FetchParent fetchParent,
NavigablePath parentNavigablePath,
LockMode lockMode) {
NavigablePath referencedNavigablePath;
DomainResultCreationState creationState) {
final NavigablePath referencedNavigablePath;
final boolean hasBidirectionalFetchParent;
FetchParent realFetchParent = fetchParent;
// Traverse up the embeddable fetches
while ( realFetchParent.getNavigablePath() != parentNavigablePath ) {
realFetchParent = ( (Fetch) fetchParent ).getFetchParent();
}
if ( parentNavigablePath.getParent() == null ) {
referencedNavigablePath = parentNavigablePath;
hasBidirectionalFetchParent = true;
}
else if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getUnaliasedLocalName() ) != null ) {
referencedNavigablePath = parentNavigablePath.getParent().getParent();
hasBidirectionalFetchParent = fetchParent instanceof Fetch
&& ( (Fetch) fetchParent ).getFetchParent() instanceof Fetch;
}
else {
referencedNavigablePath = parentNavigablePath.getParent();
hasBidirectionalFetchParent = fetchParent instanceof Fetch;
}
// The referencedNavigablePath can be null if this is a collection initialization
if ( referencedNavigablePath != null ) {
if ( hasBidirectionalFetchParent ) {
return new CircularBiDirectionalFetchImpl(
FetchTiming.IMMEDIATE,
fetchablePath,
fetchParent,
this,
LockMode.READ,
referencedNavigablePath
);
}
else {
// A query like `select ch from Phone p join p.callHistory ch` returns collection element domain results
// but detects that Call#phone is bidirectional in the query.
// The problem with a bidirectional fetch though is that we can't find an initializer
// because there is none, as we don't fetch the data of the parent node.
// To avoid creating another join, we create a special join fetch that uses the existing joined data
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
final TableGroup tableGroup = fromClauseAccess.getTableGroup( referencedNavigablePath );
fromClauseAccess.registerTableGroup( fetchablePath, tableGroup );
return new EntityFetchJoinedImpl(
fetchParent,
this,
tableGroup,
false,
fetchablePath,
creationState
);
}
}
else {
// We get here is this is a lazy collection initialization for which we know the owner is in the PC
// So we create a delayed fetch, as we are sure to find the entity in the PC
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
final NavigablePath realParent;
if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getUnaliasedLocalName() ) != null ) {
realParent = parentNavigablePath.getParent();
}
else {
realParent = parentNavigablePath;
}
final TableGroup tableGroup = fromClauseAccess.getTableGroup( realParent );
return new EntityDelayedFetchImpl(
fetchParent,
this,
fetchablePath,
foreignKeyDescriptor.createDomainResult(
fetchablePath,
tableGroup,
sideNature,
creationState
),
isSelectByUniqueKey( sideNature )
);
}
return new CircularBiDirectionalFetchImpl(
FetchTiming.IMMEDIATE,
fetchablePath,
fetchParent,
this,
lockMode,
referencedNavigablePath
);
}
@Override
@ -791,7 +939,9 @@ public class ToOneAttributeMapping
);
final NavigablePath parentNavigablePath = fetchablePath.getParent();
assert parentNavigablePath.equals( fetchParent.getNavigablePath() );
assert parentNavigablePath.equals( fetchParent.getNavigablePath() )
|| fetchParent.getNavigablePath() instanceof TreatedNavigablePath
&& parentNavigablePath.equals( fetchParent.getNavigablePath().getRealParent() );
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
final TableGroup tableGroup;
@ -905,7 +1055,8 @@ public class ToOneAttributeMapping
fetchParent,
this,
fetchablePath,
keyResult
keyResult,
selectByUniqueKey
);
}
@ -917,7 +1068,10 @@ public class ToOneAttributeMapping
}
else {
// case 1.1
return bidirectionalAttributeName != null;
// Make sure the entity identifier is not a target key property i.e. this really is a unique key mapping
return bidirectionalAttributeName != null && !targetKeyPropertyNames.contains(
entityMappingType.getEntityPersister().getEntityMetamodel().getIdentifierProperty().getName()
);
}
}
@ -930,19 +1084,20 @@ public class ToOneAttributeMapping
// We only need a join if the key is on the referring side i.e. this is an inverse to-one
// and if the FK refers to a non-PK, in which case we must load the whole entity
if ( sideNature == ForeignKeyDescriptor.Nature.TARGET || referencedPropertyName != null ) {
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
navigablePath,
tableGroup,
null,
getDefaultSqlAstJoinType( tableGroup ),
true,
creationState.getSqlAstCreationState()
);
tableGroup.addTableGroupJoin( tableGroupJoin );
creationState.getSqlAstCreationState().getFromClauseAccess().registerTableGroup(
navigablePath,
tableGroupJoin.getJoinedGroup()
np -> {
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
navigablePath,
tableGroup,
null,
getDefaultSqlAstJoinType( tableGroup ),
true,
creationState.getSqlAstCreationState()
);
tableGroup.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin.getJoinedGroup();
}
);
}
if ( referencedPropertyName == null ) {
@ -955,12 +1110,15 @@ public class ToOneAttributeMapping
}
else {
// We don't support proxies based on a non-PK yet, so we must fetch the whole entity
return new EntityResultImpl(
final EntityResultImpl entityResult = new EntityResultImpl(
navigablePath,
this,
tableGroup, null,
creationState
);
entityResult.afterInitialize( entityResult, creationState );
//noinspection unchecked
return entityResult;
}
}
@ -980,25 +1138,6 @@ public class ToOneAttributeMapping
}
}
private TableGroup createTableGroupJoin(
NavigablePath fetchablePath,
boolean fetched,
SqlAstJoinType sqlAstJoinType,
String sourceAlias,
DomainResultCreationState creationState,
TableGroup parentTableGroup) {
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
fetchablePath,
parentTableGroup,
sourceAlias,
sqlAstJoinType,
fetched,
creationState.getSqlAstCreationState()
);
return tableGroupJoin.getJoinedGroup();
}
@Override
public int getNumberOfFetchables() {
return getEntityMappingType().getNumberOfFetchables();

View File

@ -401,7 +401,7 @@ public abstract class AbstractIdentifiableType<J>
else if ( nonAggregatedIdAttributes != null && ! nonAggregatedIdAttributes.isEmpty() ) {
// non-aggregate composite id
if ( idClassType == null ) {
return new NonAggregatedCompositeSqmPathSource(
return new NonAggregatedCompositeSqmPathSource<>(
EntityIdentifierMapping.ROLE_LOCAL_NAME,
Bindable.BindableType.SINGULAR_ATTRIBUTE,
this

View File

@ -592,7 +592,7 @@ public class JpaMetamodelImpl implements JpaMetamodel, Serializable {
else {
javaTypeDescriptor = context.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.resolveManagedTypeDescriptor( javaType );
.resolveEntityTypeDescriptor( javaType );
}
final EntityTypeImpl<?> entityType = new EntityTypeImpl(

View File

@ -16,11 +16,11 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
*
* @author Steve Ebersole
*/
public class NonAggregatedCompositeSqmPathSource extends AbstractSqmPathSource implements CompositeSqmPathSource {
public class NonAggregatedCompositeSqmPathSource<J> extends AbstractSqmPathSource<J> implements CompositeSqmPathSource<J> {
public NonAggregatedCompositeSqmPathSource(
String localName,
BindableType bindableType,
ManagedDomainType container) {
ManagedDomainType<J> container) {
super( localName, container, bindableType );
}
@ -35,8 +35,8 @@ public class NonAggregatedCompositeSqmPathSource extends AbstractSqmPathSource i
}
@Override
public SqmPath createSqmPath(SqmPath lhs) {
return new NonAggregatedCompositeSimplePath(
public SqmPath<J> createSqmPath(SqmPath<?> lhs) {
return new NonAggregatedCompositeSimplePath<>(
lhs.getNavigablePath().append( getPathName() ),
this,
lhs,

View File

@ -1171,7 +1171,7 @@ public abstract class AbstractCollectionPersister
null,
() -> p -> {},
new SqlAliasBaseConstant( alias ),
sqlAstCreationState,
sqlAstCreationState.getSqlExpressionResolver(),
getFactory()
);
@ -1828,7 +1828,7 @@ public abstract class AbstractCollectionPersister
buffer.append( " and " );
}
assert elementPersister instanceof Joinable;
final TableReference tableReference = tableGroup.getTableReference( ( (Joinable) elementPersister ).getTableName() );
final TableReference tableReference = tableGroup.resolveTableReference( ( (Joinable) elementPersister ).getTableName() );
buffer.append( StringHelper.replace( manyToManyWhereTemplate, Template.TEMPLATE, tableReference.getIdentificationVariable() ) );
}

View File

@ -216,7 +216,6 @@ import org.hibernate.sql.ast.spi.SqlAliasBaseConstant;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.AliasedExpression;
@ -1266,8 +1265,16 @@ public abstract class AbstractEntityPersister
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
final EntityResultImpl entityResult = new EntityResultImpl(
navigablePath,
this,
tableGroup,
resultVariable,
creationState
);
entityResult.afterInitialize( entityResult, creationState );
//noinspection unchecked
return new EntityResultImpl( navigablePath, this, tableGroup, resultVariable, creationState );
return entityResult;
}
@Override
@ -1313,10 +1320,8 @@ public abstract class AbstractEntityPersister
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlAstCreationState creationState,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlExpressionResolver();
final TableReference primaryTableReference = createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
@ -1905,7 +1910,7 @@ public abstract class AbstractEntityPersister
null,
() -> p -> {},
new SqlAliasBaseConstant( alias ),
sqlAstCreationState,
sqlAstCreationState.getSqlExpressionResolver(),
getFactory()
);
@ -6399,6 +6404,10 @@ public abstract class AbstractEntityPersister
}
}
protected EntityMappingType getSubclassMappingType(String subclassName) {
return subclassMappingTypes != null ? subclassMappingTypes.get( subclassName ) : null;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EntityDefinition impl (walking model - deprecated)

View File

@ -8,6 +8,8 @@ package org.hibernate.persister.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -54,12 +56,14 @@ import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.InFragment;
import org.hibernate.sql.Insert;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult;
@ -1293,14 +1297,79 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
String resultVariable,
DomainResultCreationState creationState) {
if ( hasSubclasses() ) {
final EntityResultJoinedSubclassImpl entityResultJoinedSubclass = new EntityResultJoinedSubclassImpl(
navigablePath,
this,
tableGroup,
resultVariable,
creationState
);
entityResultJoinedSubclass.afterInitialize( entityResultJoinedSubclass, creationState );
//noinspection unchecked
return new EntityResultJoinedSubclassImpl( navigablePath, this, tableGroup, resultVariable, creationState );
return entityResultJoinedSubclass;
}
else {
return super.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
}
}
@Override
public void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
if ( treatedEntityNames.contains( getEntityName() ) ) {
return;
}
final Set<TableReference> retainedTableReferences = new HashSet<>( treatedEntityNames.size() );
final Set<String> sharedSuperclassTables = new HashSet<>();
for ( String treatedEntityName : treatedEntityNames ) {
final JoinedSubclassEntityPersister subPersister = (JoinedSubclassEntityPersister) getSubclassMappingType( treatedEntityName );
final String[] subclassTableNames = subPersister.getSubclassTableNames();
if ( tableGroup.canUseInnerJoins() ) {
if ( sharedSuperclassTables.isEmpty() ) {
for ( int i = 0; i < subclassTableNames.length; i++ ) {
if ( subPersister.isClassOrSuperclassTable[i] ) {
sharedSuperclassTables.add( subclassTableNames[i] );
}
}
}
else {
sharedSuperclassTables.retainAll( Arrays.asList( subclassTableNames ) );
}
}
// todo (6.0): no need to resolve all table references, only the ones needed for cardinality
for ( int i = 0; i < subclassTableNames.length; i++ ) {
retainedTableReferences.add( tableGroup.resolveTableReference( null, subclassTableNames[i], false ) );
}
}
final List<TableReferenceJoin> tableReferenceJoins = tableGroup.getTableReferenceJoins();
if ( sharedSuperclassTables.isEmpty() ) {
tableReferenceJoins
.removeIf( join -> !retainedTableReferences.contains( join.getJoinedTableReference() ) );
}
else {
final TableReferenceJoin[] oldJoins = tableReferenceJoins.toArray( new TableReferenceJoin[0] );
tableReferenceJoins.clear();
for ( TableReferenceJoin oldJoin : oldJoins ) {
final TableReference joinedTableReference = oldJoin.getJoinedTableReference();
if ( retainedTableReferences.contains( joinedTableReference ) ) {
if ( oldJoin.getJoinType() != SqlAstJoinType.INNER
&& sharedSuperclassTables.contains( joinedTableReference.getTableExpression() ) ) {
tableReferenceJoins.add(
new TableReferenceJoin(
SqlAstJoinType.INNER,
joinedTableReference,
oldJoin.getPredicate()
)
);
}
else {
tableReferenceJoins.add( oldJoin );
}
}
}
}
}
@Override
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {

View File

@ -47,12 +47,12 @@ import org.hibernate.sql.InFragment;
import org.hibernate.sql.Insert;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction;
@ -654,7 +654,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
if ( !queryable.isAbstract() ) {
values.add( queryable.getDiscriminatorSQLValue() );
}
else if ( queryable.hasSubclasses() ) {
if ( queryable.hasSubclasses() ) {
// if the treat is an abstract class, add the concrete implementations to values if any
Set<String> actualSubClasses = queryable.getEntityMetamodel().getSubclassEntityNames();
@ -843,7 +843,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlAstCreationState creationState,
SqlExpressionResolver expressionResolver,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = super.createRootTableGroup(
canUseInnerJoins,
@ -851,14 +851,14 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
explicitSourceAlias,
additionalPredicateCollectorAccess,
sqlAliasBase,
creationState,
expressionResolver,
creationContext
);
if ( additionalPredicateCollectorAccess != null && needsDiscriminator() ) {
final Predicate discriminatorPredicate = createDiscriminatorPredicate(
tableGroup,
creationState.getSqlExpressionResolver(),
expressionResolver,
creationContext
);
additionalPredicateCollectorAccess.get().accept( discriminatorPredicate );
@ -952,6 +952,17 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
);
}
@Override
public void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
if ( treatedEntityNames.contains( getEntityName() ) ) {
return;
}
final TableReference tableReference = tableGroup.getPrimaryTableReference();
tableReference.setPrunedTableExpression(
"(select * from " + getTableName() + " t where " + discriminatorFilterFragment( "t", treatedEntityNames ) + ")"
);
}
@Override
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {

View File

@ -12,6 +12,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@ -42,12 +43,14 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
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.from.UnionTableGroup;
@ -251,7 +254,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlAstCreationState creationState,
SqlExpressionResolver expressionResolver,
SqlAstCreationContext creationContext) {
final TableReference tableReference = resolvePrimaryTableReference( sqlAliasBase );
@ -390,6 +393,14 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
return isAbstract() || hasSubclasses();
}
@Override
public void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
if ( treatedEntityNames.contains( getEntityName() ) ) {
return;
}
final TableReference tableReference = tableGroup.resolveTableReference( getRootTableName() );
tableReference.setPrunedTableExpression( generateSubquery( treatedEntityNames ) );
}
@Override
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
@ -509,6 +520,68 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
return buf.append( " )" ).toString();
}
protected String generateSubquery(Set<String> treated) {
if ( !hasSubclasses() ) {
return getTableName();
}
final Dialect dialect = getFactory().getJdbcServices().getDialect();
final LinkedHashMap<String, Map<String, SelectableMapping>> selectables = new LinkedHashMap<>();
visitSubTypeAttributeMappings(
attributeMapping -> attributeMapping.forEachSelectable(
(i, selectable) -> selectables.computeIfAbsent( selectable.getSelectionExpression(), k -> new HashMap<>() )
.put( selectable.getContainingTableExpression(), selectable )
)
);
final Set<String> treatedTableNames = new HashSet<>( treated.size() );
for ( String subclassName : treated ) {
final UnionSubclassEntityPersister subPersister = (UnionSubclassEntityPersister) getSubclassMappingType( subclassName );
for ( String subclassTableName : subPersister.getSubclassTableNames() ) {
if ( ArrayHelper.indexOf( subclassSpaces, subclassTableName ) != -1 ) {
treatedTableNames.add( subclassTableName );
}
}
}
final StringBuilder buf = new StringBuilder( subquery.length() )
.append( "( " );
for ( int i = 0; i < subclassTableNames.length; i++ ) {
final String subclassTableName = subclassTableNames[i];
if ( treatedTableNames.contains( subclassTableName ) ) {
buf.append( "select " );
for ( Map<String, SelectableMapping> selectableMappings : selectables.values() ) {
SelectableMapping selectableMapping = selectableMappings.get( subclassTableName );
if ( selectableMapping == null ) {
selectableMapping = selectableMappings.values().iterator().next();
final int sqlType = selectableMapping.getJdbcMapping().getJdbcTypeDescriptor()
.getDefaultSqlTypeCode();
buf.append( dialect.getSelectClauseNullString( sqlType ) )
.append( " as " );
}
buf.append(
new ColumnReference( (String) null, selectableMapping, getFactory() ).getExpressionText()
);
buf.append( ", " );
}
buf.append( i ).append( " as clazz_" );
buf.append( " from " ).append( subclassTableName );
buf.append( " union " );
if ( dialect.supportsUnionAll() ) {
buf.append( "all " );
}
}
}
if ( buf.length() > 2 ) {
//chop the last union (all)
buf.setLength( buf.length() - ( dialect.supportsUnionAll() ? 11 : 7 ) );
}
return buf.append( " )" ).toString();
}
@Override
protected String[] getSubclassTableKeyColumns(int j) {
if ( j != 0 ) {

View File

@ -88,6 +88,7 @@ public class ProcedureParameterImpl<T> extends AbstractQueryParameter<T> impleme
return javaType;
}
@Override
public NamedCallableQueryMemento.ParameterMemento toMemento() {
return session -> {
if ( getName() != null ) {

View File

@ -101,6 +101,25 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
this( "" );
}
NavigablePath(
NavigablePath parent,
String fullPath,
String unaliasedLocalName,
String identifierForTableGroup) {
this.parent = parent;
this.fullPath = fullPath;
this.unaliasedLocalName = unaliasedLocalName;
this.identifierForTableGroup = identifierForTableGroup;
}
public NavigablePath treatAs(String entityName) {
return new TreatedNavigablePath( this, entityName );
}
public NavigablePath treatAs(String entityName, String alias) {
return new TreatedNavigablePath( this, entityName, alias );
}
public NavigablePath append(String property) {
return new NavigablePath( this, property );
}

View File

@ -11,20 +11,39 @@ package org.hibernate.query;
*/
public class TreatedNavigablePath extends NavigablePath {
public static final String ROLE_LOCAL_NAME = "{treated}";
public TreatedNavigablePath(NavigablePath parent, String entityTypeName) {
super( parent, ROLE_LOCAL_NAME, entityTypeName );
this( parent, entityTypeName, null );
}
public TreatedNavigablePath(NavigablePath parent, String entityTypeName, String alias) {
super(
parent,
alias == null ? "treat(" + parent.getFullPath() + " as " + entityTypeName + ")"
: "treat(" + parent.getFullPath() + " as " + entityTypeName + ")(" + alias + ")",
entityTypeName,
"treat(" + parent.getFullPath() + " as " + entityTypeName + ")"
);
assert !( parent instanceof TreatedNavigablePath );
}
@Override
public NavigablePath treatAs(String entityName) {
return new TreatedNavigablePath( getRealParent(), entityName );
}
@Override
public NavigablePath treatAs(String entityName, String alias) {
return new TreatedNavigablePath( getRealParent(), entityName, alias );
}
@Override
public String getLocalName() {
return ROLE_LOCAL_NAME;
return getUnaliasedLocalName();
}
@Override
public int hashCode() {
return getParent().getFullPath().hashCode();
return getFullPath().hashCode();
}
@Override

View File

@ -6,6 +6,10 @@
*/
package org.hibernate.query.criteria;
import java.util.Collection;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import jakarta.persistence.criteria.CollectionJoin;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
@ -15,7 +19,7 @@ import jakarta.persistence.criteria.Predicate;
*
* @author Steve Ebersole
*/
public interface JpaCollectionJoin<O, T> extends JpaJoin<O, T>, CollectionJoin<O, T> {
public interface JpaCollectionJoin<O, T> extends JpaPluralJoin<O, Collection<T>, T>, CollectionJoin<O, T> {
@Override
JpaCollectionJoin<O, T> on(JpaExpression<Boolean> restriction);
@ -31,4 +35,7 @@ public interface JpaCollectionJoin<O, T> extends JpaJoin<O, T>, CollectionJoin<O
@Override
<S extends T> JpaCollectionJoin<O, S> treatAs(Class<S> treatAsType);
@Override
<S extends T> JpaCollectionJoin<O, S> treatAs(EntityDomainType<S> treatAsType);
}

View File

@ -11,6 +11,7 @@ import jakarta.persistence.criteria.Fetch;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
/**
@ -32,4 +33,10 @@ public interface JpaJoin<O, T> extends JpaJoinedFrom<O, T>, Join<O, T> {
@Override
JpaJoin<O, T> on(Predicate... restrictions);
@Override
<S extends T> JpaJoin<O, S> treatAs(Class<S> treatAsType);
@Override
<S extends T> JpaJoin<O, S> treatAs(EntityDomainType<S> treatAsType);
}

View File

@ -6,6 +6,10 @@
*/
package org.hibernate.query.criteria;
import java.util.List;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.ListJoin;
import jakarta.persistence.criteria.Predicate;
@ -15,7 +19,7 @@ import jakarta.persistence.criteria.Predicate;
*
* @author Steve Ebersole
*/
public interface JpaListJoin<O, T> extends JpaJoin<O, T>, ListJoin<O, T> {
public interface JpaListJoin<O, T> extends JpaPluralJoin<O, List<T>, T>, ListJoin<O, T> {
@Override
JpaListJoin<O, T> on(JpaExpression<Boolean> restriction);
@ -30,4 +34,7 @@ public interface JpaListJoin<O, T> extends JpaJoin<O, T>, ListJoin<O, T> {
@Override
<S extends T> JpaListJoin<O, S> treatAs(Class<S> treatAsType);
@Override
<S extends T> JpaListJoin<O, S> treatAs(EntityDomainType<S> treatAsType);
}

View File

@ -6,6 +6,11 @@
*/
package org.hibernate.query.criteria;
import java.util.Map;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.PathException;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.MapJoin;
import jakarta.persistence.criteria.Predicate;
@ -15,7 +20,7 @@ import jakarta.persistence.criteria.Predicate;
*
* @author Steve Ebersole
*/
public interface JpaMapJoin<O,K,V> extends JpaJoin<O,V>, MapJoin<O,K,V> {
public interface JpaMapJoin<O,K,V> extends JpaPluralJoin<O, Map<K, V>, V>, MapJoin<O,K,V> {
@Override
JpaMapJoin<O, K, V> on(JpaExpression<Boolean> restriction);
@ -29,4 +34,7 @@ public interface JpaMapJoin<O,K,V> extends JpaJoin<O,V>, MapJoin<O,K,V> {
JpaMapJoin<O, K, V> on(Predicate... restrictions);
<S extends V> JpaMapJoin<O, K, S> treatAs(Class<S> treatAsType);
@Override
<S extends V> JpaMapJoin<O, K, S> treatAs(EntityDomainType<S> treatJavaType);
}

View File

@ -37,12 +37,12 @@ public interface JpaPath<T> extends JpaExpression<T>, Path<T> {
/**
* Support for JPA's explicit (TREAT) down-casting.
*/
<S extends T> JpaPath<S> treatAs(Class<S> treatJavaType) throws PathException;
<S extends T> JpaPath<S> treatAs(Class<S> treatJavaType);
/**
* Support for JPA's explicit (TREAT) down-casting.
*/
<S extends T> JpaPath<S> treatAs(EntityDomainType<S> treatJavaType) throws PathException;
<S extends T> JpaPath<S> treatAs(EntityDomainType<S> treatJavaType);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -0,0 +1,36 @@
/*
* 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.query.criteria;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.PluralJoin;
import jakarta.persistence.criteria.Predicate;
/**
* Specialization of {@link JpaJoin} for {@link java.util.Set} typed attribute joins
*
* @author Steve Ebersole
*/
public interface JpaPluralJoin<O, C, E> extends JpaJoin<O, E>, PluralJoin<O, C, E> {
@Override
PluralPersistentAttribute<? super O, C, E> getAttribute();
JpaPluralJoin<O, ? extends C, E> on(JpaExpression<Boolean> restriction);
JpaPluralJoin<O, ? extends C, E> on(Expression<Boolean> restriction);
JpaPluralJoin<O, ? extends C, E> on(JpaPredicate... restrictions);
JpaPluralJoin<O, ? extends C, E> on(Predicate... restrictions);
<S extends E> JpaPluralJoin<O, ?, S> treatAs(Class<S> treatAsType);
<S extends E> JpaPluralJoin<O, ?, S> treatAs(EntityDomainType<S> treatAsType);
}

View File

@ -6,6 +6,11 @@
*/
package org.hibernate.query.criteria;
import java.util.Set;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.SetJoin;
@ -15,7 +20,7 @@ import jakarta.persistence.criteria.SetJoin;
*
* @author Steve Ebersole
*/
public interface JpaSetJoin<O, T> extends JpaJoin<O, T>, SetJoin<O, T> {
public interface JpaSetJoin<O, T> extends JpaPluralJoin<O, Set<T>, T>, SetJoin<O, T> {
JpaSetJoin<O, T> on(JpaExpression<Boolean> restriction);
@ -26,4 +31,6 @@ public interface JpaSetJoin<O, T> extends JpaJoin<O, T>, SetJoin<O, T> {
JpaSetJoin<O, T> on(Predicate... restrictions);
<S extends T> JpaSetJoin<O, S> treatAs(Class<S> treatAsType);
<S extends T> JpaSetJoin<O, S> treatAs(EntityDomainType<S> treatAsType);
}

View File

@ -10,6 +10,7 @@ import java.lang.reflect.Field;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.criteria.JpaPath;
import org.hibernate.query.hql.HqlLogging;
import org.hibernate.query.hql.spi.DotIdentifierConsumer;
import org.hibernate.query.hql.spi.SemanticPathPart;
@ -93,6 +94,13 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
currentPart = currentPart.resolvePathPart( identifier, isTerminal, creationState );
}
@Override
public void consumeTreat(String entityName, boolean isTerminal) {
final EntityDomainType<?> entityDomainType = creationState.getCreationContext().getJpaMetamodel()
.entity( entityName );
currentPart = ( (SqmPath) currentPart ).treatAs( entityDomainType );
}
protected void reset() {
pathSoFar = null;
currentPart = createBasePart();
@ -249,13 +257,13 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
throw new ParsingException( "Could not interpret dot-ident : " + pathSoFar );
}
protected void validateAsRoot(SqmFrom pathRoot) {
protected void validateAsRoot(SqmFrom<?, ?> pathRoot) {
}
@Override
public SqmPath resolveIndexedAccess(
SqmExpression selector,
public SqmPath<?> resolveIndexedAccess(
SqmExpression<?> selector,
boolean isTerminal,
SqmCreationState processingState) {
return currentPart.resolveIndexedAccess( selector, isTerminal, processingState );

View File

@ -144,8 +144,8 @@ public class DomainPathPart implements SemanticPathPart {
}
@Override
public SqmPath resolveIndexedAccess(
SqmExpression selector,
public SqmPath<?> resolveIndexedAccess(
SqmExpression<?> selector,
boolean isTerminal,
SqmCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );

View File

@ -41,7 +41,7 @@ public class FullyQualifiedReflectivePath implements SemanticPathPart, FullyQual
@Override
public SqmPath<?> resolveIndexedAccess(
SqmExpression selector,
SqmExpression<?> selector,
boolean isTerminal,
SqmCreationState creationState) {
throw new UnsupportedOperationException( "Fully qualified reflective paths cannot contain indexed access" );

View File

@ -44,6 +44,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
private final String alias;
private ConsumerDelegate delegate;
private boolean treated;
public QualifiedJoinPathConsumer(
SqmRoot<?> sqmRoot,
@ -78,6 +79,10 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
);
}
public void setTreated(boolean treated) {
this.treated = treated;
}
@Override
public SemanticPathPart getConsumedPart() {
return delegate.getConsumedPart();
@ -87,14 +92,20 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
public void consumeIdentifier(String identifier, boolean isBase, boolean isTerminal) {
if ( isBase ) {
assert delegate == null;
delegate = resolveBase( identifier, isTerminal );
delegate = resolveBase( identifier, !treated && isTerminal );
}
else {
assert delegate != null;
delegate.consumeIdentifier( identifier, isTerminal );
delegate.consumeIdentifier( identifier, !treated && isTerminal );
}
}
@Override
public void consumeTreat(String entityName, boolean isTerminal) {
assert delegate != null;
delegate.consumeTreat( entityName, isTerminal );
}
private ConsumerDelegate resolveBase(String identifier, boolean isTerminal) {
final SqmCreationProcessingState processingState = creationState.getCurrentProcessingState();
final SqmPathRegistry pathRegistry = processingState.getPathRegistry();
@ -187,6 +198,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
private interface ConsumerDelegate {
void consumeIdentifier(String identifier, boolean isTerminal);
void consumeTreat(String entityName, boolean isTerminal);
SemanticPathPart getConsumedPart();
}
@ -226,6 +238,14 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
);
}
@Override
public void consumeTreat(String entityName, boolean isTerminal) {
final EntityDomainType<?> entityDomainType = creationState.getCreationContext().getJpaMetamodel()
.entity( entityName );
currentPath = currentPath.treatAs( entityDomainType, isTerminal ? alias : null );
creationState.getCurrentProcessingState().getPathRegistry().register( currentPath );
}
@Override
public SemanticPathPart getConsumedPart() {
return currentPath;
@ -240,7 +260,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
private final boolean fetch;
private final String alias;
private NavigablePath path = new NavigablePath();
private final StringBuilder path = new StringBuilder();
private SqmEntityJoin<?> join;
@ -263,14 +283,17 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
@Override
public void consumeIdentifier(String identifier, boolean isTerminal) {
path = path.append( identifier );
if ( path.length() != 0 ) {
path.append( '.' );
}
path.append( identifier );
if ( isTerminal ) {
final String fullPath = path.toString();
final EntityDomainType<?> joinedEntityType = creationState.getCreationContext()
.getJpaMetamodel()
.resolveHqlEntityReference( path.getFullPath() );
.resolveHqlEntityReference( fullPath );
if ( joinedEntityType == null ) {
throw new SemanticException( "Could not resolve join path - " + path.getFullPath() );
throw new SemanticException( "Could not resolve join path - " + fullPath );
}
assert ! ( joinedEntityType instanceof SqmPolymorphicRootDescriptor );
@ -284,6 +307,11 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
}
}
@Override
public void consumeTreat(String entityName, boolean isTerminal) {
throw new UnsupportedOperationException();
}
@Override
public SemanticPathPart getConsumedPart() {
return join;

View File

@ -11,8 +11,12 @@ import java.util.Locale;
import org.hibernate.query.SemanticException;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.tree.SqmQuery;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
* Specialized consumer for processing domain model paths occurring as part
@ -34,8 +38,19 @@ public class QualifiedJoinPredicatePathConsumer extends BasicDotIdentifierConsum
protected SemanticPathPart createBasePart() {
return new BaseLocalSequencePart() {
@Override
protected void validateAsRoot(SqmFrom pathRoot) {
if ( pathRoot.findRoot() != sqmJoin.findRoot() ) {
protected void validateAsRoot(SqmFrom<?, ?> pathRoot) {
final SqmRoot<?> root = pathRoot.findRoot();
if ( root != sqmJoin.findRoot() ) {
final SqmQuery<?> processingQuery = getCreationState().getCurrentProcessingState().getProcessingQuery();
if ( processingQuery instanceof SqmSubQuery<?> ) {
final SqmQuerySpec<?> querySpec = ( (SqmSubQuery<?>) processingQuery ).getQuerySpec();
// If this "foreign" from element is used in a sub query
// This is only an error if the from element is actually part of the sub query
if ( querySpec.getFromClause() == null || !querySpec.getFromClause().getRoots().contains( root ) ) {
super.validateAsRoot( pathRoot );
return;
}
}
throw new SemanticException(
String.format(
Locale.ROOT,

View File

@ -272,8 +272,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
private final Stack<DotIdentifierConsumer> dotIdentifierConsumerStack;
private final Stack<TreatHandler> treatHandlerStack = new StandardStack<>( new TreatHandlerNormal() );
private final Stack<ParameterDeclarationContext> parameterDeclarationContextStack = new StandardStack<>();
private final Stack<SqmCreationProcessingState> processingStateStack = new StandardStack<>();
@ -282,12 +280,16 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
private final JavaType<Map<?,?>> mapJavaTypeDescriptor;
private ParameterCollector parameterCollector;
private ParameterStyle parameterStyle;
@SuppressWarnings("WeakerAccess")
public SemanticQueryBuilder(SqmCreationOptions creationOptions, SqmCreationContext creationContext) {
this.creationOptions = creationOptions;
this.creationContext = creationContext;
this.dotIdentifierConsumerStack = new StandardStack<>( new BasicDotIdentifierConsumer( this ) );
this.parameterStyle = creationOptions.useStrictJpaCompliance()
? ParameterStyle.UNKNOWN
: ParameterStyle.MIXED;
this.integerDomainType = creationContext
.getNodeBuilder()
@ -787,13 +789,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
// visit from-clause first!!!
treatHandlerStack.push( new TreatHandlerFromClause() );
try {
sqmQuerySpec.setFromClause( visitFromClause( (HqlParser.FromClauseContext) ctx.getChild( fromIndex ) ) );
}
finally {
treatHandlerStack.pop();
}
sqmQuerySpec.setFromClause( visitFromClause( (HqlParser.FromClauseContext) ctx.getChild( fromIndex ) ) );
final SqmSelectClause selectClause;
if ( fromIndex == 1 ) {
@ -817,13 +813,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
int currentIndex = fromIndex + 1;
final SqmWhereClause whereClause = new SqmWhereClause( creationContext.getNodeBuilder() );
if ( currentIndex < ctx.getChildCount() && ctx.getChild( currentIndex ) instanceof HqlParser.WhereClauseContext ) {
treatHandlerStack.push( new TreatHandlerNormal( DowncastLocation.WHERE ) );
try {
whereClause.setPredicate( (SqmPredicate) ctx.getChild( currentIndex++ ).accept( this ) );
}
finally {
treatHandlerStack.pop();
}
whereClause.setPredicate( (SqmPredicate) ctx.getChild( currentIndex++ ).accept( this ) );
}
sqmQuerySpec.setWhereClause( whereClause );
@ -862,8 +852,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmSelectClause visitSelectClause(HqlParser.SelectClauseContext ctx) {
treatHandlerStack.push( new TreatHandlerNormal( DowncastLocation.SELECT ) );
// todo (6.0) : primer a select-clause-specific SemanticPathPart into the stack
final int selectionListIndex;
if ( ctx.getChild( 1 ) instanceof HqlParser.SelectionListContext ) {
@ -873,24 +861,19 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
selectionListIndex = 2;
}
try {
final SqmSelectClause selectClause = new SqmSelectClause(
selectionListIndex == 2,
creationContext.getNodeBuilder()
);
final HqlParser.SelectionListContext selectionListContext = (HqlParser.SelectionListContext) ctx.getChild(
selectionListIndex
);
for ( ParseTree subCtx : selectionListContext.children ) {
if ( subCtx instanceof HqlParser.SelectionContext ) {
selectClause.addSelection( visitSelection( (HqlParser.SelectionContext) subCtx ) );
}
final SqmSelectClause selectClause = new SqmSelectClause(
selectionListIndex == 2,
creationContext.getNodeBuilder()
);
final HqlParser.SelectionListContext selectionListContext = (HqlParser.SelectionListContext) ctx.getChild(
selectionListIndex
);
for ( ParseTree subCtx : selectionListContext.children ) {
if ( subCtx instanceof HqlParser.SelectionContext ) {
selectClause.addSelection( visitSelection( (HqlParser.SelectionContext) subCtx ) );
}
return selectClause;
}
finally {
treatHandlerStack.pop();
}
return selectClause;
}
@Override
@ -1409,30 +1392,23 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmFromClause visitFromClause(HqlParser.FromClauseContext parserFromClause) {
treatHandlerStack.push( new TreatHandlerFromClause() );
try {
final SqmFromClause fromClause;
if ( parserFromClause == null ) {
fromClause = new SqmFromClause();
}
else {
final int size = parserFromClause.getChildCount();
// Shift 1 bit instead of division by 2
final int estimatedSize = size >> 1;
fromClause = new SqmFromClause( estimatedSize );
for ( int i = 0; i < size; i++ ) {
final ParseTree parseTree = parserFromClause.getChild( i );
if ( parseTree instanceof HqlParser.FromClauseSpaceContext ) {
fromClause.addRoot( visitFromClauseSpace( (HqlParser.FromClauseSpaceContext) parseTree ) );
}
final SqmFromClause fromClause;
if ( parserFromClause == null ) {
fromClause = new SqmFromClause();
}
else {
final int size = parserFromClause.getChildCount();
// Shift 1 bit instead of division by 2
final int estimatedSize = size >> 1;
fromClause = new SqmFromClause( estimatedSize );
for ( int i = 0; i < size; i++ ) {
final ParseTree parseTree = parserFromClause.getChild( i );
if ( parseTree instanceof HqlParser.FromClauseSpaceContext ) {
fromClause.addRoot( visitFromClauseSpace( (HqlParser.FromClauseSpaceContext) parseTree ) );
}
}
return fromClause;
}
finally {
treatHandlerStack.pop();
}
return fromClause;
}
@Override
@ -1679,10 +1655,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
//noinspection unchecked
final SqmQualifiedJoin<X, ?> join = (SqmQualifiedJoin<X, ?>) qualifiedJoinRhsContext.getChild( 0 ).accept( this );
// we need to set the alias here because the path could be treated - the treat operator is
// not consumed by the identifierConsumer
join.setExplicitAlias( alias );
final HqlParser.QualifiedJoinPredicateContext qualifiedJoinPredicateContext = parserJoin.qualifiedJoinPredicate();
if ( join instanceof SqmEntityJoin<?> ) {
sqmRoot.addSqmJoin( join );
@ -3129,6 +3101,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmNamedParameter<?> visitNamedParameter(HqlParser.NamedParameterContext ctx) {
parameterStyle = parameterStyle.withNamed();
final SqmNamedParameter<?> param = new SqmNamedParameter<>(
ctx.getChild( 1 ).getText(),
parameterDeclarationContextStack.getCurrent().isMultiValuedBindingAllowed(),
@ -3143,6 +3116,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( ctx.getChildCount() == 1 ) {
throw new SemanticException( "Encountered positional parameter which did not declare position (? instead of, e.g., ?1)" );
}
parameterStyle = parameterStyle.withPositional();
final SqmPositionalParameter<?> param = new SqmPositionalParameter<>(
Integer.parseInt( ctx.getChild( 1 ).getText() ),
parameterDeclarationContextStack.getCurrent().isMultiValuedBindingAllowed(),
@ -4128,15 +4102,20 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPath<?> visitTreatedNavigablePath(HqlParser.TreatedNavigablePathContext ctx) {
final SqmPath<?> sqmPath = consumeManagedTypeReference( (HqlParser.PathContext) ctx.getChild( 2 ) );
final DotIdentifierConsumer consumer = dotIdentifierConsumerStack.getCurrent();
if ( consumer instanceof QualifiedJoinPathConsumer ) {
( (QualifiedJoinPathConsumer) consumer ).setTreated( true );
}
consumeManagedTypeReference( (HqlParser.PathContext) ctx.getChild( 2 ) );
final String treatTargetName = ctx.getChild( 4 ).getText();
final String treatTargetEntityName = getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName );
final EntityDomainType<?> treatTarget = getCreationContext().getJpaMetamodel().entity( treatTargetEntityName );
SqmPath<?> result = resolveTreatedPath( sqmPath, treatTarget );
final boolean hasContinuation = ctx.getChildCount() == 7;
consumer.consumeTreat( treatTargetEntityName, !hasContinuation );
SqmPath<?> result = (SqmPath<?>) consumer.getConsumedPart();
if ( ctx.getChildCount() == 7 ) {
if ( hasContinuation ) {
dotIdentifierConsumerStack.push(
new BasicDotIdentifierConsumer( result, this ) {
@Override
@ -4155,11 +4134,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return result;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private SqmTreatedPath<?, ?> resolveTreatedPath(SqmPath<?> sqmPath, EntityDomainType<?> treatTarget) {
return sqmPath.treatAs( (EntityDomainType) treatTarget );
}
@Override
public SqmPath<?> visitCollectionElementNavigablePath(HqlParser.CollectionElementNavigablePathContext ctx) {
final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
@ -4257,15 +4231,10 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmPath<?> sqmPath = consumeDomainPath( parserPath );
final SqmPathSource<?> pathSource = sqmPath.getReferencedPathSource();
try {
// use the `#sqmAs` call to validate the path is a ManagedType
pathSource.sqmAs( ManagedDomainType.class );
if ( pathSource.getSqmPathType() instanceof ManagedDomainType<?> ) {
return sqmPath;
}
catch (Exception e) {
throw new SemanticException( "Expecting ManagedType valued path [" + sqmPath.getNavigablePath() + "], but found : " + pathSource.getSqmPathType() );
}
throw new SemanticException( "Expecting ManagedType valued path [" + sqmPath.getNavigablePath() + "], but found : " + pathSource.getSqmPathType() );
}
private SqmPath<?> consumePluralAttributeReference(HqlParser.PathContext parserPath) {
@ -4278,40 +4247,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
throw new SemanticException( "Expecting plural attribute valued path [" + sqmPath.getNavigablePath() + "], but found : " + sqmPath.getReferencedPathSource().getSqmPathType() );
}
private interface TreatHandler {
void addDowncast(SqmFrom<?, ?> sqmFrom, IdentifiableDomainType<?> downcastTarget);
}
private static class TreatHandlerNormal implements TreatHandler {
private final DowncastLocation downcastLocation;
public TreatHandlerNormal() {
this( DowncastLocation.OTHER );
}
public TreatHandlerNormal(DowncastLocation downcastLocation) {
this.downcastLocation = downcastLocation;
}
@Override
public void addDowncast(
SqmFrom<?, ?> sqmFrom,
IdentifiableDomainType<?> downcastTarget) {
// ( (MutableUsageDetails) sqmFrom.getUsageDetails() ).addDownCast( false, downcastTarget, downcastLocation );
throw new NotYetImplementedFor6Exception();
}
}
private static class TreatHandlerFromClause implements TreatHandler {
@Override
public void addDowncast(
SqmFrom<?, ?> sqmFrom,
IdentifiableDomainType<?> downcastTarget) {
// ( (MutableUsageDetails) sqmFrom.getUsageDetails() ).addDownCast( true, downcastTarget, DowncastLocation.FROM );
throw new NotYetImplementedFor6Exception();
}
}
private void checkFQNEntityNameJpaComplianceViolationIfNeeded(String name, EntityDomainType<?> entityDescriptor) {
if ( getCreationOptions().useStrictJpaCompliance() && ! name.equals( entityDescriptor.getName() ) ) {
// FQN is the only possible reason
@ -4321,4 +4256,59 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
);
}
}
private enum ParameterStyle {
UNKNOWN {
@Override
ParameterStyle withNamed() {
return NAMED;
}
@Override
ParameterStyle withPositional() {
return POSITIONAL;
}
},
NAMED {
@Override
ParameterStyle withNamed() {
return NAMED;
}
@Override
ParameterStyle withPositional() {
throw new StrictJpaComplianceViolation(
"Cannot mix positional and named parameters",
StrictJpaComplianceViolation.Type.MIXED_POSITIONAL_NAMED_PARAMETERS
);
}
},
POSITIONAL {
@Override
ParameterStyle withNamed() {
throw new StrictJpaComplianceViolation(
"Cannot mix positional and named parameters",
StrictJpaComplianceViolation.Type.MIXED_POSITIONAL_NAMED_PARAMETERS
);
}
@Override
ParameterStyle withPositional() {
return POSITIONAL;
}
},
MIXED {
@Override
ParameterStyle withNamed() {
return MIXED;
}
@Override
ParameterStyle withPositional() {
return MIXED;
}
};
abstract ParameterStyle withNamed();
abstract ParameterStyle withPositional();
}
}

View File

@ -22,6 +22,15 @@ public interface DotIdentifierConsumer {
*/
void consumeIdentifier(String identifier, boolean isBase, boolean isTerminal);
/**
* Responsible for consuming each part of the path. Called sequentially for
* each part.
*
* @param entityName The treat target entity name
* @param isTerminal Is this the terminus of the path (last token)?
*/
void consumeTreat(String entityName, boolean isTerminal);
/**
* Get the currently consumed part. Generally called after the whole path
* has been processed at which point this will return the final outcome of the

View File

@ -46,7 +46,7 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
}
@Override
public SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan> creator) {
public <R> SelectQueryPlan<R> resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan<R>> creator) {
return null;
}

View File

@ -76,17 +76,18 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
}
@Override
public SelectQueryPlan resolveSelectQueryPlan(
public <R> SelectQueryPlan<R> resolveSelectQueryPlan(
Key key,
Supplier<SelectQueryPlan> creator) {
Supplier<SelectQueryPlan<R>> creator) {
log.tracef( "QueryPlan#getSelectQueryPlan(%s)", key );
final SelectQueryPlan cached = (SelectQueryPlan) queryPlanCache.get( key );
@SuppressWarnings("unchecked")
final SelectQueryPlan<R> cached = (SelectQueryPlan<R>) queryPlanCache.get( key );
if ( cached != null ) {
return cached;
}
final SelectQueryPlan plan = creator.get();
final SelectQueryPlan<R> plan = creator.get();
queryPlanCache.put( key.prepareForStore(), plan );
return plan;
}

View File

@ -240,8 +240,8 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
final TypeConfiguration typeConfiguration = session.getFactory().getTypeConfiguration();
if ( binding.getBindType() instanceof JavaTypedExpressable ) {
final JavaTypedExpressable javaTypedExpressable = (JavaTypedExpressable) binding.getBindType();
final JavaType jtd = javaTypedExpressable.getExpressableJavaTypeDescriptor();
final JavaTypedExpressable<?> javaTypedExpressable = (JavaTypedExpressable<?>) binding.getBindType();
final JavaType<?> jtd = javaTypedExpressable.getExpressableJavaTypeDescriptor();
if ( jtd.getJavaTypeClass() != null ) {
// avoid dynamic models
return typeConfiguration.getBasicTypeForJavaType( jtd.getJavaTypeClass() );

View File

@ -131,7 +131,7 @@ public class TableGroupImpl implements TableGroup {
NavigablePath navigablePath,
String tableExpression,
boolean allowFkOptimization) {
final TableReference tableReference = getTableReference( navigablePath, tableExpression, allowFkOptimization );
final TableReference tableReference = getTableReference( navigablePath, tableExpression, allowFkOptimization, true );
if ( tableReference == null ) {
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
}
@ -143,14 +143,15 @@ public class TableGroupImpl implements TableGroup {
public TableReference getTableReference(
NavigablePath navigablePath,
String tableExpression,
boolean allowFkOptimization) {
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, allowFkOptimization ) != null ) {
boolean allowFkOptimization,
boolean resolve) {
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, allowFkOptimization, resolve ) != null ) {
return primaryTableReference;
}
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve ) != null ) {
return primaryTableReference;
}
}

View File

@ -68,7 +68,7 @@ public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, Basi
final String mappedColumn = referencedModelPart.getSelectionExpression();
final TableGroup tableGroup = creationState.getFromClauseAccess().getTableGroup( parent.getNavigablePath() );
final TableReference tableReference = tableGroup.getTableReference( navigablePath, mappedTable );
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, mappedTable );
final String selectedAlias;
final int jdbcPosition;

View File

@ -69,7 +69,7 @@ public class CompleteFetchBuilderEntityValuedModelPart
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
modelPart.forEachSelectable(
(selectionIndex, selectableMapping) -> {
final TableReference tableReference = tableGroup.getTableReference( navigablePath, selectableMapping.getContainingTableExpression() );
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, selectableMapping.getContainingTableExpression() );
final String mappedColumn = selectableMapping.getSelectionExpression();
final String columnAlias = columnAliases.get( selectionIndex );
creationStateImpl.resolveSqlSelection(

View File

@ -68,7 +68,7 @@ public class CompleteResultBuilderBasicModelPart
final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState );
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
final TableReference tableReference = tableGroup.getTableReference( navigablePath, modelPart.getContainingTableExpression() );
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, modelPart.getContainingTableExpression() );
final String mappedColumn = modelPart.getSelectionExpression();
final SqlSelection sqlSelection = creationStateImpl.resolveSqlSelection(

View File

@ -146,7 +146,7 @@ public class CompleteResultBuilderCollectionStandard implements CompleteResultBu
creationStateImpl.resolveSqlSelection(
creationStateImpl.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
tableGroup.getTableReference( selectableMapping.getContainingTableExpression() ),
tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() ),
selectableMapping.getSelectionExpression()
),
processingState -> {

View File

@ -58,7 +58,6 @@ public class DelayedFetchBuilderBasicPart
parent,
fetchPath,
referencedModelPart,
true,
null,
FetchTiming.DELAYED,
isEnhancedForLazyLoading,

View File

@ -10,6 +10,7 @@ import java.util.List;
import java.util.function.Function;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.internal.util.MutableObject;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
@ -19,7 +20,6 @@ import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -37,7 +37,7 @@ public class EntityResultImpl implements EntityResult {
private final NavigablePath navigablePath;
private final EntityValuedModelPart entityValuedModelPart;
private final DomainResult<?> identifierResult;
private final Fetch identifierFetch;
private final BasicFetch<?> discriminatorFetch;
private final List<Fetch> fetches;
@ -102,17 +102,20 @@ public class EntityResultImpl implements EntityResult {
}
if ( idFetchRef.isNotSet() ) {
identifierResult = ResultsHelper.implicitIdentifierResult(
identifierMapping,
identifierFetch = ( (Fetchable) identifierMapping ).generateFetch(
this,
new EntityIdentifierNavigablePath(
navigablePath,
ResultsHelper.attributeName( identifierMapping )
),
FetchTiming.IMMEDIATE,
true,
null,
creationState
);
}
else {
this.identifierResult = idFetchRef.get().asResult( creationState );
this.identifierFetch = idFetchRef.get();
}
}
@ -161,7 +164,7 @@ public class EntityResultImpl implements EntityResult {
this,
getNavigablePath(),
lockMode,
identifierResult,
identifierFetch,
discriminatorFetch,
null,
creationState

View File

@ -148,7 +148,7 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
resolveSqlSelection(
columnNames.get( selectionIndex ),
createColumnReferenceKey(
tableGroup.getTableReference( selectableMapping.getContainingTableExpression() ),
tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() ),
selectableMapping.getSelectionExpression()
),
selectableMapping.getJdbcMapping(),

View File

@ -65,7 +65,7 @@ public class DynamicFetchBuilderStandard
final SqlExpressionResolver sqlExpressionResolver = domainResultCreationState.getSqlAstCreationState().getSqlExpressionResolver();
final SelectableConsumer selectableConsumer = (selectionIndex, selectableMapping) -> {
final TableReference tableReference = ownerTableGroup.getTableReference(
final TableReference tableReference = ownerTableGroup.resolveTableReference(
fetchPath,
selectableMapping.getContainingTableExpression()
);

View File

@ -67,7 +67,7 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicVal
final Expression expression = creationStateImpl.resolveSqlExpression(
createColumnReferenceKey(
parentTableGroup.getTableReference( fetchPath, table ),
parentTableGroup.resolveTableReference( fetchPath, table ),
fetchable.getSelectionExpression()
),
processingState -> {
@ -99,8 +99,6 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicVal
parent,
fetchPath,
fetchable,
// todo (6.0) - we don't know
true,
valueConverter,
FetchTiming.IMMEDIATE,
domainResultCreationState

View File

@ -101,7 +101,7 @@ import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;
*/
@SuppressWarnings("WeakerAccess")
public abstract class AbstractQuery<R> implements QueryImplementor<R> {
private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( AbstractQuery.class );
protected static final EntityManagerMessageLogger log = HEMLogging.messageLogger( AbstractQuery.class );
private final SharedSessionContractImplementor session;

View File

@ -35,7 +35,7 @@ public interface QueryInterpretationCache {
HqlInterpretation resolveHqlInterpretation(String queryString, Function<String, SqmStatement<?>> creator);
SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan> creator);
<R> SelectQueryPlan<R> resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan<R>> creator);
NonSelectQueryPlan getNonSelectQueryPlan(Key key);
void cacheNonSelectQueryPlan(Key key, NonSelectQueryPlan plan);

View File

@ -13,18 +13,12 @@ import java.util.Set;
import org.hibernate.action.internal.BulkOperationCleanupAction;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.spi.DomainQueryExecutionContext;
import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sql.spi.ParameterOccurrence;
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.internal.StandardJdbcMutationExecutor;
import org.hibernate.sql.exec.spi.JdbcMutation;
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
@ -39,12 +33,12 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
private final String sql;
private final Set<String> affectedTableNames;
private final List<QueryParameterImplementor<?>> parameterList;
private final List<ParameterOccurrence> parameterList;
public NativeNonSelectQueryPlanImpl(
String sql,
Set<String> affectedTableNames,
List<QueryParameterImplementor<?>> parameterList) {
List<ParameterOccurrence> parameterList) {
this.sql = sql;
this.affectedTableNames = affectedTableNames;
this.parameterList = parameterList;
@ -66,26 +60,12 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
for ( QueryParameterImplementor<?> param : parameterList ) {
QueryParameterBinding<?> binding = queryParameterBindings.getBinding( param );
AllowableParameterType<?> type = binding.getBindType();
if ( type == null ) {
type = param.getHibernateType();
}
if ( type == null ) {
type = executionContext.getSession().getTypeConfiguration().getBasicTypeForJavaType( Object.class );
}
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
jdbcParameterBinders.add( jdbcParameter );
jdbcParameterBindings.addBinding(
jdbcParameter,
new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() )
);
}
jdbcParameterBindings.registerNativeQueryParameters(
queryParameterBindings,
parameterList,
jdbcParameterBinders,
executionContext.getSession().getFactory()
);
}
final JdbcMutation jdbcMutation = new NativeJdbcMutation(

View File

@ -11,11 +11,13 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -30,6 +32,8 @@ import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.query.spi.NativeQueryInterpreter;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -37,6 +41,7 @@ import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.RootGraph;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.AbstractSharedSessionContract;
import org.hibernate.internal.util.MathHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
@ -69,6 +74,7 @@ import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.spi.ScrollableResultsImplementor;
@ -79,6 +85,7 @@ import org.hibernate.query.sql.spi.NativeSelectQueryDefinition;
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
import org.hibernate.query.sql.spi.NonSelectInterpretationsKey;
import org.hibernate.query.sql.spi.ParameterInterpretation;
import org.hibernate.query.sql.spi.ParameterOccurrence;
import org.hibernate.query.sql.spi.SelectInterpretationsKey;
import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.spi.Callback;
@ -110,7 +117,7 @@ public class NativeQueryImpl<R>
private final String sqlString;
private final ParameterMetadataImplementor parameterMetadata;
private final List<QueryParameterImplementor<?>> occurrenceOrderedParamList;
private final List<ParameterOccurrence> parameterOccurrences;
private final QueryParameterBindings parameterBindings;
private final ResultSetMappingImpl resultSetMapping;
@ -190,7 +197,7 @@ public class NativeQueryImpl<R>
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
session.getFactory(),
@ -327,7 +334,7 @@ public class NativeQueryImpl<R>
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
session.getFactory(),
@ -386,7 +393,7 @@ public class NativeQueryImpl<R>
this.sqlString = parameterInterpretation.getAdjustedSqlString();
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
this.parameterBindings = QueryParameterBindingsImpl.from(
parameterMetadata,
session.getFactory(),
@ -571,11 +578,9 @@ public class NativeQueryImpl<R>
@Override
protected List<R> doList() {
//noinspection unchecked
return resolveSelectQueryPlan().performList( this );
}
@SuppressWarnings("unchecked")
private SelectQueryPlan<R> resolveSelectQueryPlan() {
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
if ( cacheKey != null ) {
@ -590,10 +595,11 @@ public class NativeQueryImpl<R>
}
private NativeSelectQueryPlan<R> createQueryPlan(ResultSetMapping resultSetMapping) {
final NativeSelectQueryDefinition queryDefinition = new NativeSelectQueryDefinition() {
final String sqlString = expandParameterLists();
final NativeSelectQueryDefinition<R> queryDefinition = new NativeSelectQueryDefinition<R>() {
@Override
public String getSqlString() {
return NativeQueryImpl.this.getQueryString();
return sqlString;
}
@Override
@ -602,8 +608,8 @@ public class NativeQueryImpl<R>
}
@Override
public List<QueryParameterImplementor<?>> getQueryParameterList() {
return NativeQueryImpl.this.occurrenceOrderedParamList;
public List<ParameterOccurrence> getQueryParameterOccurrences() {
return NativeQueryImpl.this.parameterOccurrences;
}
@Override
@ -622,6 +628,142 @@ public class NativeQueryImpl<R>
.createQueryPlan( queryDefinition, getSessionFactory() );
}
private String expandParameterLists() {
if ( parameterOccurrences == null || parameterOccurrences.isEmpty() ) {
return sqlString;
}
// HHH-1123
// Some DBs limit number of IN expressions. For now, warn...
final Dialect dialect = getSessionFactory().getServiceRegistry().getService( JdbcServices.class ).getJdbcEnvironment().getDialect();
final boolean paddingEnabled = getSessionFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled();
final int inExprLimit = dialect.getInExpressionCountLimit();
StringBuilder sb = null;
// Handle parameter lists
int offset = 0;
for ( ParameterOccurrence occurrence : parameterOccurrences ) {
final QueryParameterImplementor<?> queryParameter = occurrence.getParameter();
final QueryParameterBinding<?> binding = parameterBindings.getBinding( queryParameter );
if ( !binding.isMultiValued() ) {
continue;
}
final Collection<?> bindValues = binding.getBindValues();
int bindValueCount = bindValues.size();
int bindValueMaxCount = determineBindValueMaxCount( paddingEnabled, inExprLimit, bindValueCount );
if ( inExprLimit > 0 && bindValueCount > inExprLimit ) {
log.tooManyInExpressions(
dialect.getClass().getName(),
inExprLimit,
queryParameter.getName() == null
? queryParameter.getPosition().toString()
: queryParameter.getName(),
bindValueCount
);
}
final int sourcePosition = occurrence.getSourcePosition();
if ( sourcePosition < 0 ) {
continue;
}
// check if placeholder is already immediately enclosed in parentheses
// (ignoring whitespace)
boolean isEnclosedInParens = true;
for ( int i = sourcePosition - 1; i >= 0; i-- ) {
final char ch = sqlString.charAt( i );
if ( !Character.isWhitespace( ch ) ) {
isEnclosedInParens = ch == '(';
break;
}
}
if ( isEnclosedInParens ) {
for ( int i = sourcePosition + 1; i < sqlString.length(); i++ ) {
final char ch = sqlString.charAt( i );
if ( !Character.isWhitespace( ch ) ) {
isEnclosedInParens = ch == ')';
break;
}
}
}
if ( bindValueCount == 1 && isEnclosedInParens ) {
// short-circuit for performance when only 1 value and the
// placeholder is already enclosed in parentheses...
continue;
}
if ( sb == null ) {
sb = new StringBuilder( sqlString.length() + 20 );
sb.append( sqlString );
}
final String expansionListAsString;
// HHH-8901
if ( bindValueMaxCount == 0 ) {
if ( isEnclosedInParens ) {
expansionListAsString = "null";
}
else {
expansionListAsString = "(null)";
}
}
else {
// Shift 1 bit instead of multiplication by 2
char[] chars;
if ( isEnclosedInParens ) {
chars = new char[( bindValueMaxCount << 1 ) - 1];
chars[0] = '?';
for ( int i = 1; i < bindValueMaxCount; i++ ) {
final int index = i << 1;
chars[index - 1] = ',';
chars[index] = '?';
}
}
else {
chars = new char[( bindValueMaxCount << 1 ) + 1];
chars[0] = '(';
chars[1] = '?';
for ( int i = 1; i < bindValueMaxCount; i++ ) {
final int index = i << 1;
chars[index] = ',';
chars[index + 1] = '?';
}
chars[chars.length - 1] = ')';
}
expansionListAsString = new String(chars);
}
final int start = sourcePosition + offset;
final int end = start + 1;
sb.replace( start, end, expansionListAsString );
offset += expansionListAsString.length() - 1;
}
return sb == null ? sqlString : sb.toString();
}
public static int determineBindValueMaxCount(boolean paddingEnabled, int inExprLimit, int bindValueCount) {
int bindValueMaxCount = bindValueCount;
final boolean inClauseParameterPaddingEnabled = paddingEnabled && bindValueCount > 2;
if ( inClauseParameterPaddingEnabled ) {
int bindValuePaddingCount = MathHelper.ceilingPowerOfTwo( bindValueCount );
if ( inExprLimit > 0 && bindValuePaddingCount > inExprLimit ) {
bindValuePaddingCount = inExprLimit;
}
if ( bindValueCount < bindValuePaddingCount ) {
bindValueMaxCount = bindValuePaddingCount;
}
}
return bindValueMaxCount;
}
private SelectInterpretationsKey generateSelectInterpretationsKey(JdbcValuesMappingProducer resultSetMapping) {
if ( !isCacheable( this ) ) {
return null;
@ -635,8 +777,7 @@ public class NativeQueryImpl<R>
);
}
@SuppressWarnings("RedundantIfStatement")
private static boolean isCacheable(NativeQueryImpl query) {
private static boolean isCacheable(NativeQueryImpl<?> query) {
// todo (6.0): unless we move the limit rendering from DeferredResultSetAccess to NativeSelectQueryPlanImpl
// we don't need to consider the limit here at all because that is applied on demand.
// It certainly is better for performance to include the limit early, but then we might trash the cache
@ -644,7 +785,8 @@ public class NativeQueryImpl<R>
// return false;
// }
return true;
// For now, don't cache plans that have parameter lists
return !query.parameterBindings.hasAnyMultiValuedBindings();
}
private static boolean hasLimit(Limit limit) {
@ -669,7 +811,8 @@ public class NativeQueryImpl<R>
}
if ( queryPlan == null ) {
queryPlan = new NativeNonSelectQueryPlanImpl( sqlString, querySpaces, occurrenceOrderedParamList );
final String sqlString = expandParameterLists();
queryPlan = new NativeNonSelectQueryPlanImpl( sqlString, querySpaces, parameterOccurrences );
if ( cacheKey != null ) {
getSession().getFactory().getQueryEngine().getInterpretationCache().cacheNonSelectQueryPlan( cacheKey, queryPlan );
}
@ -680,6 +823,10 @@ public class NativeQueryImpl<R>
protected NonSelectInterpretationsKey generateNonSelectInterpretationsKey() {
if ( !isCacheable( this ) ) {
return null;
}
// todo (6.0) - should this account for query-spaces in determining "cacheable"?
return new NonSelectInterpretationsKey(
getQueryString(),
@ -1412,7 +1559,7 @@ public class NativeQueryImpl<R>
private static class ParameterInterpretationImpl implements ParameterInterpretation {
private final String sqlString;
private final List<QueryParameterImplementor<?>> parameterList;
private final List<ParameterOccurrence> parameterList;
private final Map<Integer, QueryParameterImplementor<?>> positionalParameters;
private final Map<String, QueryParameterImplementor<?>> namedParameters;
@ -1424,7 +1571,7 @@ public class NativeQueryImpl<R>
}
@Override
public List<QueryParameterImplementor<?>> getOccurrenceOrderedParameters() {
public List<ParameterOccurrence> getOrderedParameterOccurrences() {
return parameterList;
}

View File

@ -15,20 +15,14 @@ import java.util.Set;
import org.hibernate.ScrollMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.EmptyScrollableResults;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.results.ResultSetMapping;
import org.hibernate.query.spi.DomainQueryExecutionContext;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
import org.hibernate.query.sql.spi.ParameterOccurrence;
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
@ -44,14 +38,14 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
private final String sql;
private final Set<String> affectedTableNames;
private final List<QueryParameterImplementor<?>> parameterList;
private final List<ParameterOccurrence> parameterList;
private final JdbcValuesMappingProducer resultSetMapping;
public NativeSelectQueryPlanImpl(
String sql,
Set<String> affectedTableNames,
List<QueryParameterImplementor<?>> parameterList,
List<ParameterOccurrence> parameterList,
ResultSetMapping resultSetMapping,
SessionFactoryImplementor sessionFactory) {
final ResultSetMappingProcessor processor = new ResultSetMappingProcessor( resultSetMapping, sessionFactory );
@ -85,26 +79,12 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
for ( QueryParameterImplementor<?> param : parameterList ) {
QueryParameterBinding<?> binding = queryParameterBindings.getBinding( param );
AllowableParameterType<?> type = binding.getBindType();
if ( type == null ) {
type = param.getHibernateType();
}
if ( type == null ) {
type = executionContext.getSession().getTypeConfiguration().getBasicTypeForJavaType( Object.class );
}
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
jdbcParameterBinders.add( jdbcParameter );
jdbcParameterBindings.addBinding(
jdbcParameter,
new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() )
);
}
jdbcParameterBindings.registerNativeQueryParameters(
queryParameterBindings,
parameterList,
jdbcParameterBinders,
executionContext.getSession().getFactory()
);
}
executionContext.getSession().autoFlushIfRequired( affectedTableNames );
@ -150,26 +130,11 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
queryParameterBindings.visitBindings(
(param, binding) -> {
AllowableParameterType<?> type = binding.getBindType();
if ( type == null ) {
type = param.getHibernateType();
}
if ( type == null ) {
type = executionContext.getSession().getTypeConfiguration().getBasicTypeForJavaType( Object.class );
}
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
jdbcParameterBinders.add( jdbcParameter );
jdbcParameterBindings.addBinding(
jdbcParameter,
new JdbcParameterBindingImpl( jdbcMapping, binding.getBindValue() )
);
}
jdbcParameterBindings.registerNativeQueryParameters(
queryParameterBindings,
parameterList,
jdbcParameterBinders,
executionContext.getSession().getFactory()
);
}

View File

@ -18,6 +18,7 @@ import org.hibernate.query.QueryParameter;
import org.hibernate.query.internal.QueryParameterNamedImpl;
import org.hibernate.query.internal.QueryParameterPositionalImpl;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sql.spi.ParameterOccurrence;
import org.hibernate.query.sql.spi.ParameterRecognizer;
/**
@ -37,8 +38,8 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
private int ordinalParameterImplicitPosition;
private List<QueryParameterImplementor<?>> parameterList;
private StringBuilder sqlStringBuffer = new StringBuilder();
private List<ParameterOccurrence> parameterList;
private final StringBuilder sqlStringBuffer = new StringBuilder();
@SuppressWarnings("WeakerAccess")
public ParameterRecognizerImpl(SessionFactoryImplementor factory) {
@ -77,7 +78,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
return positionalQueryParameters;
}
public List<QueryParameterImplementor<?>> getParameterList() {
public List<ParameterOccurrence> getParameterList() {
return parameterList;
}
@ -117,7 +118,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
parameterList = new ArrayList<>();
}
parameterList.add( parameter );
parameterList.add( new ParameterOccurrence( parameter, sqlStringBuffer.length() ) );
sqlStringBuffer.append( "?" );
}
@ -148,7 +149,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
parameterList = new ArrayList<>();
}
parameterList.add( parameter );
parameterList.add( new ParameterOccurrence( parameter, sqlStringBuffer.length() ) );
sqlStringBuffer.append( "?" );
}
@ -183,7 +184,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
parameterList = new ArrayList<>();
}
parameterList.add( parameter );
parameterList.add( new ParameterOccurrence( parameter, sqlStringBuffer.length() ) );
sqlStringBuffer.append( "?" );
}

View File

@ -165,9 +165,6 @@ public class SQLQueryParser {
result.append( '{' ).append( aliasPath ).append( '}' );
}
}
// Possibly handle :something parameters for the query ?
return result.toString();
}

View File

@ -26,7 +26,7 @@ public interface NativeSelectQueryDefinition<R> {
* @apiNote This returns query parameters in the order they were
* encountered - potentially including "duplicate references" to a single parameter
*/
List<QueryParameterImplementor<?>> getQueryParameterList();
List<ParameterOccurrence> getQueryParameterOccurrences();
ResultSetMapping getResultSetMapping();

View File

@ -20,7 +20,7 @@ public interface ParameterInterpretation {
* Access to the defined parameters in the order they were encountered,
* potentially including "duplicate references" to a single parameter
*/
List<QueryParameterImplementor<?>> getOccurrenceOrderedParameters();
List<ParameterOccurrence> getOrderedParameterOccurrences();
/**
* Create the ParameterMetadata representation of this interpretation

View File

@ -0,0 +1,31 @@
/*
* 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.query.sql.spi;
import org.hibernate.query.spi.QueryParameterImplementor;
/**
* @author Christian Beikov
*/
public final class ParameterOccurrence {
private final QueryParameterImplementor<?> parameter;
private final int sourcePosition;
public ParameterOccurrence(QueryParameterImplementor<?> parameter, int sourcePosition) {
this.parameter = parameter;
this.sourcePosition = sourcePosition;
}
public QueryParameterImplementor<?> getParameter() {
return parameter;
}
public int getSourcePosition() {
return sourcePosition;
}
}

View File

@ -6,11 +6,9 @@
*/
package org.hibernate.query.sqm;
import java.util.Locale;
import jakarta.persistence.metamodel.Bindable;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.tree.SqmExpressableAccessor;
import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -52,20 +50,4 @@ public interface SqmPathSource<J> extends SqmExpressable<J>, Bindable<J>, SqmExp
default SqmExpressable<J> getExpressable() {
return (SqmExpressable<J>) getSqmPathType();
}
default <X extends DomainType> X sqmAs(Class<X> targetType) {
if ( targetType.isInstance( this ) ) {
//noinspection unchecked
return (X) this;
}
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"`%s` cannot be treated as `%s`",
getClass().getName(),
targetType.getName()
)
);
}
}

View File

@ -31,6 +31,7 @@ public class StrictJpaComplianceViolation extends SemanticException {
IDENTIFICATION_VARIABLE_NOT_DECLARED_IN_FROM_CLAUSE( "use of an alias not declared in the FROM clause" ),
FQN_ENTITY_NAME( "use of FQN for entity name" ),
IMPLICIT_TREAT( "use of implicit treat" ),
MIXED_POSITIONAL_NAMED_PARAMETERS( "mix of positional and named parameters" ),
;
private final String description;

View File

@ -47,16 +47,16 @@ public class DomainParameterXref {
final Map<SqmParameter,QueryParameterImplementor<?>> xrefMap = new TreeMap<>(
(o1, o2) -> {
if ( o1 instanceof SqmNamedParameter ) {
final SqmNamedParameter one = (SqmNamedParameter) o1;
final SqmNamedParameter another = (SqmNamedParameter) o2;
return one.getName().compareTo( another.getName() );
final SqmNamedParameter<?> one = (SqmNamedParameter<?>) o1;
return o2 instanceof SqmNamedParameter<?>
? one.getName().compareTo( ((SqmNamedParameter<?>) o2).getName() )
: -1;
}
else if ( o1 instanceof SqmPositionalParameter ) {
final SqmPositionalParameter one = (SqmPositionalParameter) o1;
final SqmPositionalParameter another = (SqmPositionalParameter) o2;
return one.getPosition().compareTo( another.getPosition() );
final SqmPositionalParameter<?> one = (SqmPositionalParameter<?>) o1;
return o2 instanceof SqmPositionalParameter<?>
? one.getPosition().compareTo( ( (SqmPositionalParameter<?>) o2 ).getPosition() )
: 1;
}
else if ( o1 instanceof SqmJpaCriteriaParameterWrapper
&& o2 instanceof SqmJpaCriteriaParameterWrapper ) {
@ -101,7 +101,7 @@ public class DomainParameterXref {
sqmParameter,
p -> {
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper ) {
return ( (SqmJpaCriteriaParameterWrapper) sqmParameter ).getJpaCriteriaParameter();
return ( (SqmJpaCriteriaParameterWrapper<?>) sqmParameter ).getJpaCriteriaParameter();
}
else if ( sqmParameter.getName() != null ) {
return QueryParameterNamedImpl.fromSqm( sqmParameter );

View File

@ -670,7 +670,6 @@ public class QuerySqmImpl<R>
return lockMode != null && lockMode.greaterThan( LockMode.READ );
}
@SuppressWarnings("unchecked")
private SelectQueryPlan<R> resolveSelectQueryPlan() {
// resolve (or make) the QueryPlan. This QueryPlan might be an aggregation of multiple plans.
//

View File

@ -201,7 +201,7 @@ public class MatchingIdSelectionHelper {
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(
entityDescriptor,
sqmMutationStatement.getTarget().getExplicitAlias(),
sqmMutationStatement.getTarget(),
domainParameterXref,
executionContext.getQueryOptions(),
executionContext.getSession().getLoadQueryInfluencers(),

View File

@ -14,7 +14,6 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.sqm.internal.DomainParameterXref;
@ -23,6 +22,7 @@ import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.sql.internal.SqlAstProcessingStateImpl;
import org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
import org.hibernate.query.sqm.tree.update.SqmAssignment;
@ -63,7 +63,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
public MultiTableSqmMutationConverter(
EntityMappingType mutatingEntityDescriptor,
String mutatingEntityExplicitAlias,
SqmRoot<?> sqmRoot,
DomainParameterXref domainParameterXref,
QueryOptions queryOptions,
LoadQueryInfluencers loadQueryInfluencers,
@ -71,8 +71,8 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
SqlAstCreationContext creationContext) {
this(
mutatingEntityDescriptor,
mutatingEntityExplicitAlias,
mutatingEntityExplicitAlias,
sqmRoot,
sqmRoot.getExplicitAlias(),
domainParameterXref,
queryOptions,
loadQueryInfluencers,
@ -83,7 +83,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
public MultiTableSqmMutationConverter(
EntityMappingType mutatingEntityDescriptor,
String mutatingEntityExplicitAlias,
SqmRoot<?> sqmRoot,
String sourceAlias,
DomainParameterXref domainParameterXref,
QueryOptions queryOptions,
@ -101,10 +101,9 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
pushProcessingState( rootProcessingState );
final NavigablePath navigablePath = new NavigablePath( mutatingEntityDescriptor.getEntityName(), mutatingEntityExplicitAlias );
this.mutatingTableGroup = mutatingEntityDescriptor.createRootTableGroup(
true,
navigablePath,
sqmRoot.getNavigablePath(),
sourceAlias,
// We don't care about the discriminator predicate,
// but we pass non-null to ensure table reference join predicates are generated
@ -112,7 +111,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
this,
creationContext.getSessionFactory() );
getFromClauseAccess().registerTableGroup( navigablePath, mutatingTableGroup );
getFromClauseAccess().registerTableGroup( sqmRoot.getNavigablePath(), mutatingTableGroup );
}
@SuppressWarnings("unused")

View File

@ -117,7 +117,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(
entityDescriptor,
sqmMutationStatement.getTarget().getExplicitAlias(),
sqmMutationStatement.getTarget(),
explicitDmlTargetAlias,
domainParameterXref,
executionContext.getQueryOptions(),
@ -324,7 +324,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
);
}
else {
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression );
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression, true, true );
}
}

View File

@ -110,7 +110,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
converter = new MultiTableSqmMutationConverter(
entityDescriptor,
sqmDelete.getTarget().getExplicitAlias(),
sqmDelete.getTarget(),
domainParameterXref,
queryOptions,
loadQueryInfluencers,
@ -288,7 +288,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
);
}
else {
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression );
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression, true, true );
}
}

View File

@ -126,7 +126,7 @@ public class TableBasedUpdateHandler
final MultiTableSqmMutationConverter converterDelegate = new MultiTableSqmMutationConverter(
entityDescriptor,
getSqmDeleteOrUpdateStatement().getTarget().getExplicitAlias(),
getSqmDeleteOrUpdateStatement().getTarget(),
domainParameterXref,
executionContext.getQueryOptions(),
executionContext.getSession().getLoadQueryInfluencers(),

View File

@ -230,7 +230,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
);
}
else {
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression );
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression, true, true );
}
}

View File

@ -16,13 +16,17 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
*/
public class SqmCreationHelper {
public static NavigablePath buildRootNavigablePath(String base, String alias) {
// Make sure we always create a unique alias, otherwise we might use a wrong table group for the same join
return alias == null
? new NavigablePath( base )
? new NavigablePath( base, Long.toString( System.nanoTime() ) )
: new NavigablePath( base, alias );
}
public static NavigablePath buildSubNavigablePath(NavigablePath lhs, String base, String alias) {
return lhs.append( base, alias );
// Make sure we always create a unique alias, otherwise we might use a wrong table group for the same join
return alias == null
? lhs.append( base, Long.toString( System.nanoTime() ) )
: lhs.append( base, alias );
}
public static NavigablePath buildSubNavigablePath(SqmPath<?> lhs, String subNavigable, String alias) {

View File

@ -12,6 +12,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -88,6 +89,7 @@ import org.hibernate.query.sqm.tree.domain.SqmCorrelatedRootJoin;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
import org.hibernate.sql.ast.tree.expression.ModifiedSubQueryExpression;
import org.hibernate.query.sqm.tree.domain.SqmTreatedRoot;
import org.hibernate.sql.exec.internal.VersionTypeSeedParameterSpecification;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
@ -597,6 +599,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final SqmStatement<?> sqmStatement = getStatement();
//noinspection unchecked
final T statement = (T) sqmStatement.accept( this );
pruneTableGroupJoins();
return new StandardSqmTranslation<>(
statement,
getJdbcParamsBySqmParam(),
@ -1988,13 +1991,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
additionalRestrictions,
new ComparisonPredicate(
new ColumnReference(
parentTableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
parentTableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
selectable,
sessionFactory
),
ComparisonOperator.EQUAL,
new ColumnReference(
tableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
tableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
selectable,
sessionFactory
)
@ -2009,14 +2012,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
(index, selectable) -> {
lhs.add(
new ColumnReference(
parentTableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
parentTableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
selectable,
sessionFactory
)
);
rhs.add(
new ColumnReference(
tableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
tableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
selectable,
sessionFactory
)
@ -2095,13 +2098,58 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return creationContext.getDomainModel().getEntityDescriptor( entityDomainType.getHibernateEntityName() );
}
private final Map<TableGroup, Set<String>> tableGroupTreatUsages = new IdentityHashMap<>();
protected void registerUsage(SqmFrom<?, ?> sqmFrom, TableGroup tableGroup) {
final EntityDomainType<?> treatedType;
if ( sqmFrom instanceof SqmTreatedPath<?, ?> ) {
treatedType = ( (SqmTreatedPath<?, ?>) sqmFrom ).getTreatTarget();
}
else if ( sqmFrom.getReferencedPathSource().getSqmPathType() instanceof EntityDomainType<?> ) {
treatedType = (EntityDomainType<?>) sqmFrom.getReferencedPathSource().getSqmPathType();
}
else {
return;
}
final Set<String> treatedEntityNames = tableGroupTreatUsages.computeIfAbsent(
tableGroup,
tg -> new HashSet<>( 1 )
);
treatedEntityNames.add( treatedType.getHibernateEntityName() );
}
protected void pruneTableGroupJoins() {
for ( Map.Entry<TableGroup, Set<String>> entry : tableGroupTreatUsages.entrySet() ) {
final TableGroup tableGroup = entry.getKey();
final Set<String> treatedEntityNames = entry.getValue();
final ModelPartContainer modelPart = tableGroup.getModelPart();
final EntityPersister tableGroupPersister;
if ( modelPart instanceof PluralAttributeMapping ) {
tableGroupPersister = (EntityPersister) ( (PluralAttributeMapping) modelPart )
.getElementDescriptor()
.getPartMappingType();
}
else {
tableGroupPersister = (EntityPersister) modelPart.getPartMappingType();
}
tableGroupPersister.pruneForSubclasses( tableGroup, treatedEntityNames );
}
}
protected void consumeExplicitJoins(SqmFrom<?, ?> sqmFrom, TableGroup lhsTableGroup) {
if ( log.isTraceEnabled() ) {
log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() );
}
sqmFrom.visitSqmJoins(
sqmJoin -> consumeExplicitJoin( sqmJoin, lhsTableGroup, lhsTableGroup, true )
sqmJoin -> {
registerUsage( (SqmFrom<?, ?>) sqmJoin.getLhs(), lhsTableGroup );
consumeExplicitJoin( sqmJoin, lhsTableGroup, lhsTableGroup, true );
}
);
for ( SqmFrom<?, ?> sqmTreat : sqmFrom.getSqmTreats() ) {
registerUsage( sqmTreat, lhsTableGroup );
consumeExplicitJoins( sqmTreat, lhsTableGroup );
}
}
@SuppressWarnings("WeakerAccess")
@ -2221,7 +2269,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private NavigablePath getJoinNavigablePath(
NavigablePath sqmJoinNavigablePath,
NavigablePath parentNavigablePath, String partName) {
NavigablePath parentNavigablePath,
String partName) {
if ( parentNavigablePath == null ) {
return sqmJoinNavigablePath;
}
@ -2327,7 +2376,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
JpaPath<?> sqmPath,
boolean useInnerJoin,
Consumer<TableGroup> implicitJoinChecker) {
final JpaPath<?> parentPath = sqmPath.getParentPath();
final JpaPath<?> parentPath;
if ( sqmPath instanceof SqmTreatedPath<?, ?> ) {
parentPath = ( (SqmTreatedPath<?, ?>) sqmPath ).getWrappedPath();
}
else {
parentPath = sqmPath.getParentPath();
}
final TableGroup tableGroup = fromClauseIndex.findTableGroup( parentPath.getNavigablePath() );
if ( tableGroup == null ) {
final TableGroup parentTableGroup = prepareReusablePath(
@ -2336,17 +2391,31 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
useInnerJoin,
implicitJoinChecker
);
if ( parentPath instanceof SqmTreatedPath<?, ?> ) {
fromClauseIndex.register( (SqmPath<?>) parentPath, parentTableGroup );
}
final TableGroup newTableGroup = createTableGroup( parentTableGroup, (SqmPath<?>) parentPath, useInnerJoin );
if ( newTableGroup != null ) {
implicitJoinChecker.accept( newTableGroup );
if ( sqmPath instanceof SqmFrom<?, ?> ) {
registerUsage( (SqmFrom<?, ?>) sqmPath, newTableGroup );
}
}
return newTableGroup;
}
else if ( sqmPath instanceof SqmTreatedPath<?, ?> ) {
fromClauseIndex.register( (SqmPath<?>) sqmPath, tableGroup );
if ( sqmPath instanceof SqmFrom<?, ?> ) {
registerUsage( (SqmFrom<?, ?>) sqmPath, tableGroup );
}
}
else if ( parentPath instanceof SqmFrom<?, ?> ) {
registerUsage( (SqmFrom<?, ?>) parentPath, tableGroup );
}
return tableGroup;
}
private void prepareForSelection(SqmPath<?> joinedPath) {
final SqmPath<?> lhsPath = joinedPath.getLhs();
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
final TableGroup tableGroup = fromClauseIndex.findTableGroup( joinedPath.getNavigablePath() );
if ( tableGroup == null ) {
@ -2354,24 +2423,29 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final NavigablePath navigablePath;
if ( CollectionPart.Nature.fromNameExact( joinedPath.getNavigablePath().getUnaliasedLocalName() ) != null ) {
navigablePath = lhsPath.getLhs().getNavigablePath();
navigablePath = joinedPath.getLhs().getLhs().getNavigablePath();
}
else if ( joinedPath instanceof SqmTreatedRoot<?, ?> ) {
navigablePath = ( (SqmTreatedRoot<?, ?>) joinedPath ).getWrappedPath().getNavigablePath();
}
else {
navigablePath = lhsPath.getNavigablePath();
navigablePath = joinedPath.getLhs().getNavigablePath();
}
// todo (6.0): check again if this really is a "requirement" by the JPA spec and document the reference if it is.
// The additional join will filter rows, so there would be no way to just select the FK for a nullable association
final boolean useInnerJoin = true;
// INNER join semantics are required per the JPA spec for select items.
createTableGroup( fromClauseIndex.getTableGroup( navigablePath ), joinedPath, useInnerJoin );
}
// When we select a treated path, we must add the type restriction as where clause predicate
if ( joinedPath instanceof SqmTreatedPath<?, ?> ) {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) joinedPath;
// todo (6.0): the persister and the table group should participate so we can optimize the joins/selects
currentQuerySpec().applyPredicate(
createTreatTypeRestriction( treatedPath.getWrappedPath(), treatedPath.getTreatTarget() )
final TableGroup createdTableGroup = createTableGroup(
fromClauseIndex.getTableGroup( navigablePath ),
joinedPath,
useInnerJoin
);
if ( createdTableGroup != null && joinedPath instanceof SqmTreatedPath<?, ?> ) {
fromClauseIndex.register( joinedPath, createdTableGroup );
}
}
else if ( joinedPath instanceof SqmFrom<?, ?> ) {
registerUsage( (SqmFrom<?, ?>) joinedPath, tableGroup );
}
}
@ -3000,7 +3074,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
(selectionIndex, selectionMapping) -> {
tupleElements.add(
new ColumnReference(
tableGroup.getTableReference(
tableGroup.resolveTableReference(
navigablePath,
selectionMapping.getContainingTableExpression()
),
@ -5254,9 +5328,18 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup
);
if ( manyToManyFilterPredicate != null ) {
assert tableGroup.getTableReferenceJoins() != null &&
tableGroup.getTableReferenceJoins().size() == 1;
tableGroup.getTableReferenceJoins().get( 0 ).applyPredicate( manyToManyFilterPredicate );
TableGroupJoin elementTableGroupJoin = null;
for ( TableGroupJoin nestedTableGroupJoin : tableGroup.getNestedTableGroupJoins() ) {
final NavigablePath navigablePath = nestedTableGroupJoin.getNavigablePath();
if ( navigablePath.getParent() == tableGroup.getNavigablePath()
&& CollectionPart.Nature.ELEMENT.getName().equals( navigablePath.getUnaliasedLocalName() ) ) {
elementTableGroupJoin = nestedTableGroupJoin;
break;
}
}
assert elementTableGroupJoin != null;
elementTableGroupJoin.applyPredicate( manyToManyFilterPredicate );
}
}

View File

@ -12,7 +12,6 @@ import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
@ -20,27 +19,19 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
@ -53,16 +44,9 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
public static <T> EntityValuedPathInterpretation<T> from(
SqmEntityValuedSimplePath<T> sqmPath,
SqmToSqlAstConverter sqlAstCreationState) {
final SqmPath<?> realPath;
if ( CollectionPart.Nature.fromNameExact( sqmPath.getNavigablePath().getUnaliasedLocalName() ) != null ) {
realPath = sqmPath.getLhs();
}
else {
realPath = sqmPath;
}
final TableGroup tableGroup = sqlAstCreationState
.getFromClauseAccess()
.findTableGroup( realPath.getLhs().getNavigablePath() );
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
final EntityValuedModelPart mapping = (EntityValuedModelPart) sqlAstCreationState
.getFromClauseAccess()
@ -124,19 +108,6 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
final String lhsTable;
final ModelPart lhsPart;
boolean useKeyPart = associationMapping.getSideNature() == ForeignKeyDescriptor.Nature.KEY;
if ( mapping instanceof EntityCollectionPart ) {
// EntityCollectionPart always returns TARGET, but sometimes we still want to use the KEY (element) side.
// With a collection table, we can always use the TARGET for referring to the collection,
// but in case of a one-to-many without collection table, this would be problematic,
// as we can't use e.g. the primary key of the owner entity as substitution.
final TableGroup pluralTableGroup = sqlAstCreationState.getFromClauseAccess()
.findTableGroup( navigablePath.getParent() );
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) pluralTableGroup.getModelPart();
if ( pluralAttributeMapping.getSeparateCollectionTable() == null ) {
useKeyPart = true;
tableGroup = pluralTableGroup;
}
}
if ( useKeyPart ) {
lhsTable = fkDescriptor.getKeyTable();
lhsPart = fkDescriptor.getKeyPart();
@ -281,46 +252,4 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
return (EntityValuedModelPart) super.getExpressionType();
}
@Override
public DomainResult<T> createDomainResult(String resultVariable, DomainResultCreationState creationState) {
final EntityValuedModelPart mappingType = getExpressionType();
if ( mappingType instanceof EntityAssociationMapping ) {
final NavigablePath navigablePath = getNavigablePath();
// for a to-one or to-many we may not have yet joined to the association table,
// but we need to because the association is a root return and needs to select
// all of the entity columns
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final FromClauseAccess fromClauseAccess = sqlAstCreationState.getFromClauseAccess();
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) mappingType;
final TableGroup tableGroup = fromClauseAccess.resolveTableGroup(
navigablePath,
np -> {
final TableGroup parentTableGroup;
if ( getExpressionType() instanceof CollectionPart ) {
parentTableGroup = fromClauseAccess.findTableGroup( np.getParent().getParent() );
}
else {
parentTableGroup = getTableGroup();
}
final TableGroupJoin tableGroupJoin = associationMapping.createTableGroupJoin(
navigablePath,
parentTableGroup,
null,
SqlAstJoinType.INNER,
false,
sqlAstCreationState
);
parentTableGroup.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin.getJoinedGroup();
}
);
return associationMapping.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
}
return super.createDomainResult( resultVariable, creationState );
}
}

View File

@ -11,6 +11,7 @@ import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder;
@ -48,9 +49,28 @@ public abstract class AbstractSqmAttributeJoin<O,T>
SqmJoinType joinType,
boolean fetched,
NodeBuilder nodeBuilder) {
this(
lhs,
SqmCreationHelper.buildSubNavigablePath( lhs, joinedNavigable.getName(), alias ),
joinedNavigable,
alias,
joinType,
fetched,
nodeBuilder
);
}
protected AbstractSqmAttributeJoin(
SqmFrom<?,O> lhs,
NavigablePath navigablePath,
SqmJoinable joinedNavigable,
String alias,
SqmJoinType joinType,
boolean fetched,
NodeBuilder nodeBuilder) {
//noinspection unchecked
super(
SqmCreationHelper.buildSubNavigablePath( lhs, joinedNavigable.getName(), alias ),
navigablePath,
(SqmPathSource<T>) joinedNavigable,
lhs,
alias,

View File

@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@ -39,7 +40,6 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.UnknownPathException;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.spi.SqmCreationHelper;
import org.hibernate.query.sqm.tree.SqmJoinType;
@ -58,6 +58,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
private String alias;
private List<SqmJoin<T, ?>> joins;
private List<SqmFrom<?, ?>> treats;
protected AbstractSqmFrom(
NavigablePath navigablePath,
@ -168,6 +169,38 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
}
@Override
public boolean hasTreats() {
return treats != null && !treats.isEmpty();
}
@Override
public List<SqmFrom<?, ?>> getSqmTreats() {
return treats == null ? Collections.emptyList() : treats;
}
protected <S, X extends SqmFrom<?, S>> X findTreat(EntityDomainType<S> targetType, String alias) {
if ( treats != null ) {
for ( SqmFrom<?, ?> treat : treats ) {
if ( treat.getModel() == targetType ) {
if ( treat.getExplicitAlias() == null && alias == null
|| Objects.equals( treat.getExplicitAlias(), alias ) ) {
//noinspection unchecked
return (X) treat;
}
}
}
}
return null;
}
protected <X extends SqmFrom<?, ?>> X addTreat(X treat) {
if ( treats == null ) {
treats = new ArrayList<>();
}
treats.add( treat );
return treat;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA

View File

@ -59,18 +59,6 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
return (SqmPathSource<T>) super.getNodeType();
}
@SuppressWarnings("WeakerAccess")
protected AbstractSqmPath(SqmPathSource<T> referencedPathSource, SqmPath<?> lhs, NodeBuilder nodeBuilder) {
this(
lhs == null
? new NavigablePath( referencedPathSource.getPathName() )
: lhs.getNavigablePath().append( referencedPathSource.getPathName() ),
referencedPathSource,
lhs,
nodeBuilder
);
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;

View File

@ -9,8 +9,10 @@ package org.hibernate.query.sqm.tree.domain;
import jakarta.persistence.criteria.PluralJoin;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.criteria.JpaJoin;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmJoinable;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.from.SqmFrom;
@ -27,14 +29,18 @@ public abstract class AbstractSqmPluralJoin<O,C,E> extends AbstractSqmAttributeJ
SqmJoinType joinType,
boolean fetched,
NodeBuilder nodeBuilder) {
super(
lhs,
joinedNavigable,
alias,
joinType,
fetched,
nodeBuilder
);
super( lhs, joinedNavigable, alias, joinType, fetched, nodeBuilder );
}
protected AbstractSqmPluralJoin(
SqmFrom<?, O> lhs,
NavigablePath navigablePath,
PluralPersistentAttribute<O,C,E> joinedNavigable,
String alias,
SqmJoinType joinType,
boolean fetched,
NodeBuilder nodeBuilder) {
super( lhs, navigablePath, joinedNavigable, alias, joinType, fetched, nodeBuilder );
}
@Override

View File

@ -12,7 +12,7 @@ import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.PathException;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.criteria.JpaCollectionJoin;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaPredicate;
@ -36,6 +36,17 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
super( lhs, attribute, alias, sqmJoinType, fetched, nodeBuilder );
}
protected SqmBagJoin(
SqmFrom<?, O> lhs,
NavigablePath navigablePath,
BagPersistentAttribute<O,E> attribute,
String alias,
SqmJoinType joinType,
boolean fetched,
NodeBuilder nodeBuilder) {
super( lhs, navigablePath, attribute, alias, joinType, fetched, nodeBuilder );
}
@Override
public BagPersistentAttribute<O,E> getReferencedPathSource() {
return (BagPersistentAttribute<O,E>) super.getReferencedPathSource();
@ -85,15 +96,27 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
}
@Override
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
//noinspection unchecked
return new SqmTreatedBagJoin( this, treatTarget, null );
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) {
return treatAs( treatTarget, null );
}
@Override
public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) {
//noinspection unchecked
return new SqmBagJoin(
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias );
}
@Override
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget, String alias) {
final SqmTreatedBagJoin<O,E,S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
return addTreat( new SqmTreatedBagJoin<>( this, treatTarget, alias ) );
}
return treat;
}
@Override
public SqmAttributeJoin<O, E> makeCopy(SqmCreationProcessingState creationProcessingState) {
return new SqmBagJoin<>(
creationProcessingState.getPathRegistry().findFromByPath( getLhs().getNavigablePath() ),
getReferencedPathSource(),
getExplicitAlias(),

View File

@ -12,6 +12,8 @@ import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.PathException;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaListJoin;
@ -39,6 +41,17 @@ public class SqmListJoin<O,E>
super( lhs, listAttribute, alias, sqmJoinType, fetched, nodeBuilder );
}
protected SqmListJoin(
SqmFrom<?, O> lhs,
NavigablePath navigablePath,
ListPersistentAttribute<O, E> listAttribute,
String alias,
SqmJoinType joinType,
boolean fetched,
NodeBuilder nodeBuilder) {
super( lhs, navigablePath, listAttribute, alias, joinType, fetched, nodeBuilder );
}
@Override
public ListPersistentAttribute<O, E> getReferencedPathSource() {
return (ListPersistentAttribute<O, E>) super.getReferencedPathSource();
@ -88,12 +101,26 @@ public class SqmListJoin<O,E>
@Override
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatAsType) {
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ) );
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ), null );
}
@Override
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
return new SqmTreatedListJoin<>( this, treatTarget, null );
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) {
return treatAs( treatTarget, null );
}
@Override
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias );
}
@Override
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget, String alias) {
final SqmTreatedListJoin<O,E,S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
return addTreat( new SqmTreatedListJoin<>( this, treatTarget, alias ) );
}
return treat;
}
@Override

View File

@ -13,6 +13,8 @@ import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.PathException;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaMapJoin;
@ -40,6 +42,17 @@ public class SqmMapJoin<O, K, V>
super( lhs, pluralValuedNavigable, alias, sqmJoinType, fetched, nodeBuilder );
}
protected SqmMapJoin(
SqmFrom<?, O> lhs,
NavigablePath navigablePath,
MapPersistentAttribute<O, K, V> pluralValuedNavigable,
String alias,
SqmJoinType joinType,
boolean fetched,
NodeBuilder nodeBuilder) {
super( lhs, navigablePath, pluralValuedNavigable, alias, joinType, fetched, nodeBuilder );
}
@Override
public MapPersistentAttribute<O, K, V> getReferencedPathSource() {
return(MapPersistentAttribute<O, K, V>) super.getReferencedPathSource();
@ -103,13 +116,27 @@ public class SqmMapJoin<O, K, V>
}
@Override
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType) throws PathException {
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
}
@Override
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
return new SqmTreatedMapJoin<>( this, treatTarget, null );
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(EntityDomainType<S> treatTarget) {
return treatAs( treatTarget, null );
}
@Override
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias );
}
@Override
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(EntityDomainType<S> treatTarget, String alias) {
final SqmTreatedMapJoin<O, K, V, S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
return addTreat( new SqmTreatedMapJoin<>( this, treatTarget, alias ) );
}
return treat;
}
@Override

View File

@ -114,10 +114,10 @@ public interface SqmPath<T> extends SqmExpression<T>, SemanticPathPart, JpaPath<
}
@Override
<S extends T> SqmTreatedPath<T,S> treatAs(Class<S> treatJavaType) throws PathException;
<S extends T> SqmPath<S> treatAs(Class<S> treatJavaType);
@Override
<S extends T> SqmTreatedPath<T,S> treatAs(EntityDomainType<S> treatTarget) throws PathException;
<S extends T> SqmPath<S> treatAs(EntityDomainType<S> treatTarget);
default SqmRoot<?> findRoot() {
final SqmPath<?> lhs = getLhs();

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