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:
parent
24c758c2e9
commit
38d1c122eb
|
@ -1052,6 +1052,7 @@ identifier
|
||||||
| UPDATE
|
| UPDATE
|
||||||
| UPPER
|
| UPPER
|
||||||
| VALUE
|
| VALUE
|
||||||
|
| VALUES
|
||||||
| VERSION
|
| VERSION
|
||||||
| VERSIONED
|
| VERSIONED
|
||||||
| WEEK
|
| WEEK
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class NativeQueryInterpreterStandardImpl implements NativeQueryInterprete
|
||||||
return new NativeSelectQueryPlanImpl<>(
|
return new NativeSelectQueryPlanImpl<>(
|
||||||
queryDefinition.getSqlString(),
|
queryDefinition.getSqlString(),
|
||||||
queryDefinition.getAffectedTableNames(),
|
queryDefinition.getAffectedTableNames(),
|
||||||
queryDefinition.getQueryParameterList(),
|
queryDefinition.getQueryParameterOccurrences(),
|
||||||
queryDefinition.getResultSetMapping(),
|
queryDefinition.getResultSetMapping(),
|
||||||
sessionFactory
|
sessionFactory
|
||||||
);
|
);
|
||||||
|
|
|
@ -44,7 +44,7 @@ public interface NativeQueryInterpreter extends Service {
|
||||||
return new NativeSelectQueryPlanImpl<>(
|
return new NativeSelectQueryPlanImpl<>(
|
||||||
queryDefinition.getSqlString(),
|
queryDefinition.getSqlString(),
|
||||||
queryDefinition.getAffectedTableNames(),
|
queryDefinition.getAffectedTableNames(),
|
||||||
queryDefinition.getQueryParameterList(),
|
queryDefinition.getQueryParameterOccurrences(),
|
||||||
queryDefinition.getResultSetMapping(),
|
queryDefinition.getResultSetMapping(),
|
||||||
sessionFactory
|
sessionFactory
|
||||||
);
|
);
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class TableGroupFilterAliasGenerator implements FilterAliasGenerator {
|
||||||
if ( table == null ) {
|
if ( table == null ) {
|
||||||
table = defaultTable;
|
table = defaultTable;
|
||||||
}
|
}
|
||||||
final TableReference tableReference = tableGroup.getTableReference( table );
|
final TableReference tableReference = tableGroup.getTableReference( null, table, true, true );
|
||||||
return tableReference == null ? null : tableReference.getIdentificationVariable();
|
return tableReference == null ? null : tableReference.getIdentificationVariable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
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.internal.RowTransformerPassThruImpl;
|
||||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||||
|
|
||||||
|
@ -163,13 +164,22 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( subSelectFetchedCollections != null && ! subSelectFetchedCollections.isEmpty() ) {
|
if ( subSelectFetchedCollections != null && ! subSelectFetchedCollections.isEmpty() ) {
|
||||||
subSelectFetchedCollections.forEach( (c) -> {
|
subSelectFetchedCollections.forEach(
|
||||||
if ( c.wasInitialized() ) {
|
c -> {
|
||||||
return;
|
if ( c.wasInitialized() ) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
c.initializeEmptyCollection( getLoadable().getCollectionDescriptor() );
|
c.initializeEmptyCollection( getLoadable().getCollectionDescriptor() );
|
||||||
} );
|
ResultsHelper.finalizeCollectionLoading(
|
||||||
|
persistenceContext,
|
||||||
|
getLoadable().getCollectionDescriptor(),
|
||||||
|
c,
|
||||||
|
c.getKey(),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
subSelectFetchedCollections.clear();
|
subSelectFetchedCollections.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
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.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
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.from.TableReference;
|
||||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||||
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
|
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
|
||||||
|
@ -401,21 +401,9 @@ public class LoaderSelectBuilder {
|
||||||
for ( ModelPart part : partsToSelect ) {
|
for ( ModelPart part : partsToSelect ) {
|
||||||
final NavigablePath navigablePath = rootNavigablePath.append( part.getPartName() );
|
final NavigablePath navigablePath = rootNavigablePath.append( part.getPartName() );
|
||||||
final TableGroup tableGroup;
|
final TableGroup tableGroup;
|
||||||
if ( part instanceof RootTableGroupProducer ) {
|
if ( part instanceof TableGroupJoinProducer ) {
|
||||||
tableGroup = ( (RootTableGroupProducer) part ).createRootTableGroup(
|
final TableGroupJoinProducer tableGroupJoinProducer = (TableGroupJoinProducer) part;
|
||||||
true,
|
final TableGroupJoin tableGroupJoin = tableGroupJoinProducer.createTableGroupJoin(
|
||||||
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(
|
|
||||||
navigablePath,
|
navigablePath,
|
||||||
rootTableGroup,
|
rootTableGroup,
|
||||||
null,
|
null,
|
||||||
|
@ -613,8 +601,18 @@ public class LoaderSelectBuilder {
|
||||||
tableGroup
|
tableGroup
|
||||||
);
|
);
|
||||||
if ( manyToManyFilterPredicate != null ) {
|
if ( manyToManyFilterPredicate != null ) {
|
||||||
assert tableGroup.getTableReferenceJoins().size() == 1;
|
TableGroupJoin elementTableGroupJoin = null;
|
||||||
tableGroup.getTableReferenceJoins().get( 0 ).applyPredicate( manyToManyFilterPredicate );
|
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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
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.RootTableGroupProducer;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
|
@ -42,7 +43,8 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAstCreationState creationState, SqlAstCreationContext creationContext) {
|
SqlAstCreationState creationState,
|
||||||
|
SqlAstCreationContext creationContext) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +55,8 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
SqlAstCreationState creationState, SqlAstCreationContext creationContext) {
|
SqlExpressionResolver expressionResolver,
|
||||||
|
SqlAstCreationContext creationContext) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,6 @@ public abstract class AbstractCompositeIdentifierMapping
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
selected,
|
selected,
|
||||||
attributeMetadataAccess.resolveAttributeMetadata( null ).isNullable(),
|
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class EntityRepresentationStrategyPojoStandard implements EntityRepresent
|
||||||
.getJavaTypeDescriptorRegistry();
|
.getJavaTypeDescriptorRegistry();
|
||||||
|
|
||||||
final Class<?> mappedJavaType = bootDescriptor.getMappedClass();
|
final Class<?> mappedJavaType = bootDescriptor.getMappedClass();
|
||||||
this.mappedJtd = jtdRegistry.resolveManagedTypeDescriptor( mappedJavaType );
|
this.mappedJtd = jtdRegistry.resolveEntityTypeDescriptor( mappedJavaType );
|
||||||
|
|
||||||
final Class<?> proxyJavaType = bootDescriptor.getProxyInterface();
|
final Class<?> proxyJavaType = bootDescriptor.getProxyInterface();
|
||||||
if ( proxyJavaType != null ) {
|
if ( proxyJavaType != null ) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
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.MappingModelCreationHelper;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||||
import org.hibernate.metamodel.mapping.internal.SelectableMappingsImpl;
|
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.Clause;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
import org.hibernate.sql.results.graph.Fetchable;
|
||||||
|
@ -176,7 +178,8 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
|
||||||
}
|
}
|
||||||
|
|
||||||
private EmbeddableMappingType(
|
private EmbeddableMappingType(
|
||||||
EmbeddableValuedModelPart valueMapping,
|
EmbeddedAttributeMapping valueMapping,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
SelectableMappings selectableMappings,
|
SelectableMappings selectableMappings,
|
||||||
EmbeddableMappingType inverseMappingType,
|
EmbeddableMappingType inverseMappingType,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
|
@ -186,6 +189,7 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
|
||||||
this.valueMapping = valueMapping;
|
this.valueMapping = valueMapping;
|
||||||
this.createEmptyCompositesEnabled = inverseMappingType.isCreateEmptyCompositesEnabled();
|
this.createEmptyCompositesEnabled = inverseMappingType.isCreateEmptyCompositesEnabled();
|
||||||
this.selectableMappings = selectableMappings;
|
this.selectableMappings = selectableMappings;
|
||||||
|
final ManagedMappingType declaringType = valueMapping.getDeclaringType();
|
||||||
creationProcess.registerInitializationCallback(
|
creationProcess.registerInitializationCallback(
|
||||||
"EmbeddableMappingType(" + inverseMappingType.getNavigableRole().getFullPath() + ".{inverse})#finishInitialization",
|
"EmbeddableMappingType(" + inverseMappingType.getNavigableRole().getFullPath() + ".{inverse})#finishInitialization",
|
||||||
() -> {
|
() -> {
|
||||||
|
@ -201,6 +205,7 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
|
||||||
final BasicAttributeMapping original = (BasicAttributeMapping) attributeMapping;
|
final BasicAttributeMapping original = (BasicAttributeMapping) attributeMapping;
|
||||||
final SelectableMapping selectableMapping = selectableMappings.getSelectable( currentIndex );
|
final SelectableMapping selectableMapping = selectableMappings.getSelectable( currentIndex );
|
||||||
attributeMapping = BasicAttributeMapping.withSelectableMapping(
|
attributeMapping = BasicAttributeMapping.withSelectableMapping(
|
||||||
|
declaringType,
|
||||||
original,
|
original,
|
||||||
original.getPropertyAccess(),
|
original.getPropertyAccess(),
|
||||||
original.getValueGeneration(),
|
original.getValueGeneration(),
|
||||||
|
@ -210,13 +215,18 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
|
||||||
}
|
}
|
||||||
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||||
final ToOneAttributeMapping original = (ToOneAttributeMapping) attributeMapping;
|
final ToOneAttributeMapping original = (ToOneAttributeMapping) attributeMapping;
|
||||||
final ToOneAttributeMapping toOne = original.copy();
|
final ToOneAttributeMapping toOne = original.copy(
|
||||||
|
declaringType,
|
||||||
|
declaringTableGroupProducer
|
||||||
|
);
|
||||||
final int offset = currentIndex;
|
final int offset = currentIndex;
|
||||||
toOne.setIdentifyingColumnsTableExpression(
|
toOne.setIdentifyingColumnsTableExpression(
|
||||||
selectableMappings.getSelectable( offset ).getContainingTableExpression()
|
selectableMappings.getSelectable( offset ).getContainingTableExpression()
|
||||||
);
|
);
|
||||||
toOne.setForeignKeyDescriptor(
|
toOne.setForeignKeyDescriptor(
|
||||||
original.getForeignKeyDescriptor().withKeySelectionMapping(
|
original.getForeignKeyDescriptor().withKeySelectionMapping(
|
||||||
|
declaringType,
|
||||||
|
declaringTableGroupProducer,
|
||||||
index -> selectableMappings.getSelectable( offset + index ),
|
index -> selectableMappings.getSelectable( offset + index ),
|
||||||
creationProcess
|
creationProcess
|
||||||
)
|
)
|
||||||
|
@ -237,10 +247,17 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmbeddableMappingType createInverseMappingType(
|
public EmbeddableMappingType createInverseMappingType(
|
||||||
EmbeddableValuedModelPart valueMapping,
|
EmbeddedAttributeMapping valueMapping,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
SelectableMappings selectableMappings,
|
SelectableMappings selectableMappings,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
return new EmbeddableMappingType( valueMapping, selectableMappings, this, creationProcess );
|
return new EmbeddableMappingType(
|
||||||
|
valueMapping,
|
||||||
|
declaringTableGroupProducer,
|
||||||
|
selectableMappings,
|
||||||
|
this,
|
||||||
|
creationProcess
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean finishInitialization(
|
private boolean finishInitialization(
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.metamodel.mapping;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@ -195,8 +196,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
|
||||||
return superMappingType.getRootEntityDescriptor();
|
return superMappingType.getRootEntityDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
default TableReference locateTableReference(TableGroup tableGroup) {
|
default void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
|
||||||
return tableGroup.getPrimaryTableReference();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean isAbstract() {
|
default boolean isAbstract() {
|
||||||
|
@ -296,7 +296,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
additionalPredicateCollectorAccess,
|
additionalPredicateCollectorAccess,
|
||||||
creationState.getSqlAliasBaseGenerator().createSqlAliasBase( getSqlAliasStem() ),
|
creationState.getSqlAliasBaseGenerator().createSqlAliasBase( getSqlAliasStem() ),
|
||||||
creationState,
|
creationState.getSqlExpressionResolver(),
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
SqlAstCreationState creationState,
|
SqlExpressionResolver expressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
return getEntityPersister().createRootTableGroup(
|
return getEntityPersister().createRootTableGroup(
|
||||||
canUseInnerJoins,
|
canUseInnerJoins,
|
||||||
|
@ -316,7 +316,7 @@ public interface EntityMappingType extends ManagedMappingType, EntityValuedModel
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
additionalPredicateCollectorAccess,
|
additionalPredicateCollectorAccess,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
creationState,
|
expressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.TableReference;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
|
@ -102,15 +103,15 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
||||||
DomainResultCreationState creationState);
|
DomainResultCreationState creationState);
|
||||||
|
|
||||||
Predicate generateJoinPredicate(
|
Predicate generateJoinPredicate(
|
||||||
TableGroup lhs,
|
TableGroup targetSideTableGroup,
|
||||||
TableGroup tableGroup,
|
TableGroup keySideTableGroup,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext);
|
SqlAstCreationContext creationContext);
|
||||||
|
|
||||||
Predicate generateJoinPredicate(
|
Predicate generateJoinPredicate(
|
||||||
TableReference lhs,
|
TableReference targetSideReference,
|
||||||
TableReference rhs,
|
TableReference keySideReference,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext);
|
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.
|
* Return a copy of this foreign key descriptor with the selectable mappings as provided by the given accessor.
|
||||||
*/
|
*/
|
||||||
ForeignKeyDescriptor withKeySelectionMapping(
|
ForeignKeyDescriptor withKeySelectionMapping(
|
||||||
|
ManagedMappingType declaringType,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
IntFunction<SelectableMapping> selectableMappingAccess,
|
IntFunction<SelectableMapping> selectableMappingAccess,
|
||||||
MappingModelCreationProcess creationProcess);
|
MappingModelCreationProcess creationProcess);
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class MappingModelHelper {
|
||||||
qualifier = selection.getContainingTableExpression();
|
qualifier = selection.getContainingTableExpression();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qualifier = tableGroup.getTableReference( selection.getContainingTableExpression() ).getIdentificationVariable();
|
qualifier = tableGroup.resolveTableReference( selection.getContainingTableExpression() ).getIdentificationVariable();
|
||||||
}
|
}
|
||||||
if ( sqlExpressionResolver == null ) {
|
if ( sqlExpressionResolver == null ) {
|
||||||
colRef = new ColumnReference(
|
colRef = new ColumnReference(
|
||||||
|
@ -78,7 +78,7 @@ public class MappingModelHelper {
|
||||||
qualifier = basicPart.getContainingTableExpression();
|
qualifier = basicPart.getContainingTableExpression();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qualifier = tableGroup.getTableReference( basicPart.getContainingTableExpression() ).getIdentificationVariable();
|
qualifier = tableGroup.resolveTableReference( basicPart.getContainingTableExpression() ).getIdentificationVariable();
|
||||||
}
|
}
|
||||||
if ( sqlExpressionResolver == null ) {
|
if ( sqlExpressionResolver == null ) {
|
||||||
return new ColumnReference(
|
return new ColumnReference(
|
||||||
|
|
|
@ -177,7 +177,6 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
false,
|
|
||||||
null,
|
null,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -188,7 +188,7 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
|
||||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||||
|
|
||||||
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchablePath.getParent().getParent() );
|
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(
|
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
|
||||||
createColumnReferenceKey( tableReference, column ),
|
createColumnReferenceKey( tableReference, column ),
|
||||||
processingState -> new ColumnReference(
|
processingState -> new ColumnReference(
|
||||||
|
@ -212,7 +212,6 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions,
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
nullable,
|
|
||||||
null,
|
null,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -151,7 +151,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
.getSessionFactory();
|
.getSessionFactory();
|
||||||
|
|
||||||
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchParent.getNavigablePath().getParent() );
|
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(
|
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
|
||||||
SqlExpressionResolver.createColumnReferenceKey( tableReference, column ),
|
SqlExpressionResolver.createColumnReferenceKey( tableReference, column ),
|
||||||
|
@ -177,7 +177,6 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
nullable,
|
|
||||||
null,
|
null,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -106,6 +106,7 @@ public class BasicAttributeMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BasicAttributeMapping withSelectableMapping(
|
public static BasicAttributeMapping withSelectableMapping(
|
||||||
|
ManagedMappingType declaringType,
|
||||||
BasicValuedModelPart original,
|
BasicValuedModelPart original,
|
||||||
PropertyAccess propertyAccess,
|
PropertyAccess propertyAccess,
|
||||||
ValueGeneration valueGeneration,
|
ValueGeneration valueGeneration,
|
||||||
|
@ -114,19 +115,16 @@ public class BasicAttributeMapping
|
||||||
int stateArrayPosition = 0;
|
int stateArrayPosition = 0;
|
||||||
StateArrayContributorMetadataAccess attributeMetadataAccess = null;
|
StateArrayContributorMetadataAccess attributeMetadataAccess = null;
|
||||||
BasicValueConverter<?, ?> valueConverter = null;
|
BasicValueConverter<?, ?> valueConverter = null;
|
||||||
ManagedMappingType declaringType = null;
|
|
||||||
if ( original instanceof SingleAttributeIdentifierMapping ) {
|
if ( original instanceof SingleAttributeIdentifierMapping ) {
|
||||||
final SingleAttributeIdentifierMapping mapping = (SingleAttributeIdentifierMapping) original;
|
final SingleAttributeIdentifierMapping mapping = (SingleAttributeIdentifierMapping) original;
|
||||||
attributeName = mapping.getAttributeName();
|
attributeName = mapping.getAttributeName();
|
||||||
attributeMetadataAccess = null;
|
attributeMetadataAccess = null;
|
||||||
declaringType = mapping.findContainingEntityMapping();
|
|
||||||
}
|
}
|
||||||
else if ( original instanceof SingularAttributeMapping ) {
|
else if ( original instanceof SingularAttributeMapping ) {
|
||||||
final SingularAttributeMapping mapping = (SingularAttributeMapping) original;
|
final SingularAttributeMapping mapping = (SingularAttributeMapping) original;
|
||||||
attributeName = mapping.getAttributeName();
|
attributeName = mapping.getAttributeName();
|
||||||
stateArrayPosition = mapping.getStateArrayPosition();
|
stateArrayPosition = mapping.getStateArrayPosition();
|
||||||
attributeMetadataAccess = mapping.getAttributeMetadataAccess();
|
attributeMetadataAccess = mapping.getAttributeMetadataAccess();
|
||||||
declaringType = mapping.getDeclaringType();
|
|
||||||
}
|
}
|
||||||
if ( original instanceof ConvertibleModelPart ) {
|
if ( original instanceof ConvertibleModelPart ) {
|
||||||
valueConverter = ( (ConvertibleModelPart) original ).getValueConverter();
|
valueConverter = ( (ConvertibleModelPart) original ).getValueConverter();
|
||||||
|
@ -212,7 +210,7 @@ public class BasicAttributeMapping
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, true, creationState );
|
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, true, creationState );
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return new BasicResult(
|
return new BasicResult(
|
||||||
|
@ -225,12 +223,13 @@ public class BasicAttributeMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqlSelection resolveSqlSelection(
|
private SqlSelection resolveSqlSelection(
|
||||||
|
NavigablePath navigablePath,
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
boolean allowFkOptimization,
|
boolean allowFkOptimization,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||||
tableGroup.getNavigablePath().append( getNavigableRole().getNavigableName() ),
|
navigablePath,
|
||||||
getContainingTableExpression(),
|
getContainingTableExpression(),
|
||||||
allowFkOptimization
|
allowFkOptimization
|
||||||
);
|
);
|
||||||
|
@ -257,7 +256,7 @@ public class BasicAttributeMapping
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
resolveSqlSelection( tableGroup, true, creationState );
|
resolveSqlSelection( navigablePath, tableGroup, true, creationState );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -266,7 +265,7 @@ public class BasicAttributeMapping
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
DomainResultCreationState creationState,
|
DomainResultCreationState creationState,
|
||||||
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
|
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
|
||||||
selectionConsumer.accept( resolveSqlSelection( tableGroup, true, creationState ), getJdbcMapping() );
|
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, true, creationState ), getJdbcMapping() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,7 +292,7 @@ public class BasicAttributeMapping
|
||||||
|
|
||||||
assert tableGroup != null;
|
assert tableGroup != null;
|
||||||
|
|
||||||
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, false, creationState );
|
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, creationState );
|
||||||
valuesArrayPosition = sqlSelection.getValuesArrayPosition();
|
valuesArrayPosition = sqlSelection.getValuesArrayPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +301,6 @@ public class BasicAttributeMapping
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
|
||||||
valueConverter,
|
valueConverter,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.Clause;
|
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.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
|
@ -326,12 +327,19 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
||||||
boolean selected,
|
boolean selected,
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
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<>(
|
return new BasicFetch<>(
|
||||||
0,
|
sqlSelection.getValuesArrayPosition(),
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
false,
|
|
||||||
null,
|
null,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -230,7 +230,6 @@ public class BasicValuedCollectionPart
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
false,
|
|
||||||
valueConverter,
|
valueConverter,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -9,20 +9,29 @@ package org.hibernate.metamodel.mapping.internal;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
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.JdbcMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||||
import org.hibernate.persister.entity.DiscriminatorType;
|
import org.hibernate.persister.entity.DiscriminatorType;
|
||||||
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
|
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
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.SqlAstCreationState;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
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.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
|
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
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;
|
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
|
@Override
|
||||||
public Expression resolveSqlExpression(
|
public Expression resolveSqlExpression(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -82,37 +116,63 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CaseSearchedExpression createCaseSearchedExpression(TableGroup entityTableGroup) {
|
private Expression createCaseSearchedExpression(TableGroup entityTableGroup) {
|
||||||
final CaseSearchedExpression caseSearchedExpression = new CaseSearchedExpression( this );
|
return new SelfRenderingExpression() {
|
||||||
|
CaseSearchedExpression caseSearchedExpression;
|
||||||
|
|
||||||
tableDiscriminatorDetailsMap.forEach( (tableName, tableDiscriminatorDetails) -> {
|
@Override
|
||||||
final TableReference tableReference = entityTableGroup.getTableReference( entityTableGroup.getNavigablePath(), tableName );
|
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 ) {
|
if ( tableReference == null ) {
|
||||||
// assume this is because it is a table that is not part of the processing entity's sub-hierarchy
|
// assume this is because it is a table that is not part of the processing entity's sub-hierarchy
|
||||||
return;
|
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(
|
@Override
|
||||||
new ColumnReference(
|
public JdbcMappingContainer getExpressionType() {
|
||||||
tableReference,
|
return CaseStatementDiscriminatorMappingImpl.this;
|
||||||
tableDiscriminatorDetails.getCheckColumnName(),
|
}
|
||||||
false,
|
};
|
||||||
null,
|
|
||||||
null,
|
|
||||||
getJdbcMapping(),
|
|
||||||
getSessionFactory()
|
|
||||||
),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
caseSearchedExpression.when( predicate, new QueryLiteral<>(
|
|
||||||
tableDiscriminatorDetails.getDiscriminatorValue(),
|
|
||||||
getUnderlyingJdbcMappingType()
|
|
||||||
) );
|
|
||||||
} );
|
|
||||||
|
|
||||||
return caseSearchedExpression;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -180,7 +180,6 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
! selected,
|
|
||||||
null,
|
null,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -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.CompositeTableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
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.from.TableReference;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
|
@ -110,6 +111,8 @@ public class EmbeddedAttributeMapping
|
||||||
|
|
||||||
// Constructor is only used for creating the inverse attribute mapping
|
// Constructor is only used for creating the inverse attribute mapping
|
||||||
private EmbeddedAttributeMapping(
|
private EmbeddedAttributeMapping(
|
||||||
|
ManagedMappingType keyDeclaringType,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
SelectableMappings selectableMappings,
|
SelectableMappings selectableMappings,
|
||||||
EmbeddableValuedModelPart inverseModelPart,
|
EmbeddableValuedModelPart inverseModelPart,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
|
@ -118,11 +121,7 @@ public class EmbeddedAttributeMapping
|
||||||
-1,
|
-1,
|
||||||
null,
|
null,
|
||||||
inverseModelPart.getMappedFetchOptions(),
|
inverseModelPart.getMappedFetchOptions(),
|
||||||
inverseModelPart instanceof AttributeMapping
|
keyDeclaringType,
|
||||||
? ( (AttributeMapping) inverseModelPart ).getDeclaringType()
|
|
||||||
: inverseModelPart instanceof EntityIdentifierMapping
|
|
||||||
? inverseModelPart.findContainingEntityMapping()
|
|
||||||
: null,
|
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
@ -132,6 +131,7 @@ public class EmbeddedAttributeMapping
|
||||||
this.tableExpression = selectableMappings.getSelectable( 0 ).getContainingTableExpression();
|
this.tableExpression = selectableMappings.getSelectable( 0 ).getContainingTableExpression();
|
||||||
this.embeddableMappingType = inverseModelPart.getEmbeddableTypeDescriptor().createInverseMappingType(
|
this.embeddableMappingType = inverseModelPart.getEmbeddableTypeDescriptor().createInverseMappingType(
|
||||||
this,
|
this,
|
||||||
|
declaringTableGroupProducer,
|
||||||
selectableMappings,
|
selectableMappings,
|
||||||
creationProcess
|
creationProcess
|
||||||
);
|
);
|
||||||
|
@ -140,9 +140,17 @@ public class EmbeddedAttributeMapping
|
||||||
|
|
||||||
public static EmbeddableValuedModelPart createInverseModelPart(
|
public static EmbeddableValuedModelPart createInverseModelPart(
|
||||||
EmbeddableValuedModelPart modelPart,
|
EmbeddableValuedModelPart modelPart,
|
||||||
|
ManagedMappingType keyDeclaringType,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
SelectableMappings selectableMappings,
|
SelectableMappings selectableMappings,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
return new EmbeddedAttributeMapping( selectableMappings, modelPart, creationProcess );
|
return new EmbeddedAttributeMapping(
|
||||||
|
keyDeclaringType,
|
||||||
|
declaringTableGroupProducer,
|
||||||
|
selectableMappings,
|
||||||
|
modelPart,
|
||||||
|
creationProcess
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -225,7 +233,6 @@ public class EmbeddedAttributeMapping
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
selected,
|
selected,
|
||||||
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,6 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
||||||
fetchParent,
|
fetchParent,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
selected,
|
selected,
|
||||||
true,
|
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
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.SelectableMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableMappings;
|
import org.hibernate.metamodel.mapping.SelectableMappings;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.ComparisonOperator;
|
import org.hibernate.query.ComparisonOperator;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.Clause;
|
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.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
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.from.TableReference;
|
||||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||||
|
@ -101,6 +104,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
private EmbeddedForeignKeyDescriptor(
|
private EmbeddedForeignKeyDescriptor(
|
||||||
EmbeddedForeignKeyDescriptor original,
|
EmbeddedForeignKeyDescriptor original,
|
||||||
String keyTable,
|
String keyTable,
|
||||||
|
ManagedMappingType keyDeclaringType,
|
||||||
|
TableGroupProducer keyDeclaringTableGroupProducer,
|
||||||
SelectableMappings keySelectableMappings,
|
SelectableMappings keySelectableMappings,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
this.keyTable = keyTable;
|
this.keyTable = keyTable;
|
||||||
|
@ -112,6 +117,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
Nature.KEY,
|
Nature.KEY,
|
||||||
EmbeddedAttributeMapping.createInverseModelPart(
|
EmbeddedAttributeMapping.createInverseModelPart(
|
||||||
original.targetSide.getModelPart(),
|
original.targetSide.getModelPart(),
|
||||||
|
keyDeclaringType,
|
||||||
|
keyDeclaringTableGroupProducer,
|
||||||
keySelectableMappings,
|
keySelectableMappings,
|
||||||
creationProcess
|
creationProcess
|
||||||
)
|
)
|
||||||
|
@ -158,6 +165,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ForeignKeyDescriptor withKeySelectionMapping(
|
public ForeignKeyDescriptor withKeySelectionMapping(
|
||||||
|
ManagedMappingType declaringType,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
IntFunction<SelectableMapping> selectableMappingAccess,
|
IntFunction<SelectableMapping> selectableMappingAccess,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
SelectableMapping[] selectionMappings = new SelectableMapping[keySelectableMappings.getJdbcTypeCount()];
|
SelectableMapping[] selectionMappings = new SelectableMapping[keySelectableMappings.getJdbcTypeCount()];
|
||||||
|
@ -167,6 +176,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
return new EmbeddedForeignKeyDescriptor(
|
return new EmbeddedForeignKeyDescriptor(
|
||||||
this,
|
this,
|
||||||
selectionMappings[0].getContainingTableExpression(),
|
selectionMappings[0].getContainingTableExpression(),
|
||||||
|
declaringType,
|
||||||
|
declaringTableGroupProducer,
|
||||||
new SelectableMappingsImpl( selectionMappings ),
|
new SelectableMappingsImpl( selectionMappings ),
|
||||||
creationProcess
|
creationProcess
|
||||||
);
|
);
|
||||||
|
@ -340,11 +351,11 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
|
final TableReference lhsTableReference = targetSideTableGroup.resolveTableReference(
|
||||||
targetSideTableGroup.getNavigablePath(),
|
targetSideTableGroup.getNavigablePath(),
|
||||||
targetTable
|
targetTable
|
||||||
);
|
);
|
||||||
final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference( keyTable );
|
final TableReference rhsTableKeyReference = keySideTableGroup.resolveTableReference( keyTable );
|
||||||
|
|
||||||
return generateJoinPredicate(
|
return generateJoinPredicate(
|
||||||
lhsTableReference,
|
lhsTableReference,
|
||||||
|
|
|
@ -6,42 +6,66 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
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.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.mapping.Collection;
|
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.mapping.Value;
|
||||||
|
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
|
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
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.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
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.SqlAliasBaseGenerator;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
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.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
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.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.FetchOptions;
|
import org.hibernate.sql.results.graph.FetchOptions;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
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.EntityFetch;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
|
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
|
||||||
import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl;
|
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;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,8 +77,10 @@ public class EntityCollectionPart
|
||||||
private final CollectionPersister collectionDescriptor;
|
private final CollectionPersister collectionDescriptor;
|
||||||
private final Nature nature;
|
private final Nature nature;
|
||||||
private final EntityMappingType entityMappingType;
|
private final EntityMappingType entityMappingType;
|
||||||
|
private final Set<String> targetKeyPropertyNames;
|
||||||
|
|
||||||
private ModelPart fkTargetModelPart;
|
private ModelPart fkTargetModelPart;
|
||||||
|
private ForeignKeyDescriptor fkDescriptor;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public EntityCollectionPart(
|
public EntityCollectionPart(
|
||||||
|
@ -67,6 +93,81 @@ public class EntityCollectionPart
|
||||||
this.collectionDescriptor = collectionDescriptor;
|
this.collectionDescriptor = collectionDescriptor;
|
||||||
this.nature = nature;
|
this.nature = nature;
|
||||||
this.entityMappingType = entityMappingType;
|
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")
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
@ -81,8 +182,80 @@ public class EntityCollectionPart
|
||||||
else {
|
else {
|
||||||
fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null );
|
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
|
@Override
|
||||||
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
|
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
|
||||||
|
@ -146,22 +319,24 @@ public class EntityCollectionPart
|
||||||
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
|
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
|
||||||
creationState.registerVisitedAssociationKey( getForeignKeyDescriptor().getAssociationKey() );
|
creationState.registerVisitedAssociationKey( getForeignKeyDescriptor().getAssociationKey() );
|
||||||
|
|
||||||
TableGroup tableGroup = fromClauseAccess.resolveTableGroup(
|
final TableGroup partTableGroup = fromClauseAccess.resolveTableGroup(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
np -> {
|
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
|
throw new IllegalStateException( "Could not find table group for: " + np );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return new EntityFetchJoinedImpl( fetchParent, this, tableGroup, selected, fetchablePath, creationState );
|
return new EntityFetchJoinedImpl( fetchParent, this, partTableGroup, selected, fetchablePath, creationState );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -184,15 +359,20 @@ public class EntityCollectionPart
|
||||||
final TableGroup partTableGroup = fromClauseAccess.resolveTableGroup(
|
final TableGroup partTableGroup = fromClauseAccess.resolveTableGroup(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
np -> {
|
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 ) {
|
||||||
// first, find the collection's TableGroup
|
return ( (OneToManyTableGroup) parentTableGroup ).getElementTableGroup();
|
||||||
final TableGroup collectionTableGroup = fromClauseAccess.getTableGroup( np.getParent() );
|
}
|
||||||
|
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||||
assert collectionTableGroup != null;
|
navigablePath,
|
||||||
|
parentTableGroup,
|
||||||
// create a "wrapper" around the collection TableGroup adding in the entity's table references
|
resultVariable,
|
||||||
return new EntityCollectionPartTableGroup( np, collectionTableGroup, this );
|
SqlAstJoinType.INNER,
|
||||||
|
true,
|
||||||
|
creationState.getSqlAstCreationState()
|
||||||
|
);
|
||||||
|
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -247,8 +427,7 @@ public class EntityCollectionPart
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ForeignKeyDescriptor getForeignKeyDescriptor() {
|
public ForeignKeyDescriptor getForeignKeyDescriptor() {
|
||||||
// todo (6.0) : this will not strictly work - we'd want a new ForeignKeyDescriptor that points the other direction
|
return fkDescriptor;
|
||||||
return collectionDescriptor.getAttributeMapping().getKeyDescriptor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -269,27 +448,60 @@ public class EntityCollectionPart
|
||||||
@Override
|
@Override
|
||||||
public TableGroupJoin createTableGroupJoin(
|
public TableGroupJoin createTableGroupJoin(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
TableGroup lhs,
|
TableGroup collectionTableGroup,
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
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,
|
navigablePath,
|
||||||
lhs,
|
collectionTableGroup,
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
sqlAstJoinType,
|
sqlAstJoinType,
|
||||||
fetched,
|
fetched,
|
||||||
|
null,
|
||||||
aliasBaseGenerator,
|
aliasBaseGenerator,
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
creationContext
|
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
|
@Override
|
||||||
public TableGroup createRootTableGroupJoin(
|
public LazyTableGroup createRootTableGroupJoin(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
TableGroup lhs,
|
TableGroup lhs,
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
|
@ -299,17 +511,101 @@ public class EntityCollectionPart
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
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,
|
navigablePath,
|
||||||
lhs,
|
|
||||||
explicitSourceAlias,
|
|
||||||
sqlAstJoinType,
|
|
||||||
fetched,
|
fetched,
|
||||||
predicateConsumer,
|
() -> createTableGroupInternal(
|
||||||
aliasBaseGenerator,
|
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,
|
sqlExpressionResolver,
|
||||||
creationContext
|
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
|
@Override
|
||||||
|
|
|
@ -200,7 +200,6 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
||||||
fetchParent,
|
fetchParent,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
this,
|
this,
|
||||||
false,
|
|
||||||
null,
|
null,
|
||||||
fetchTiming,
|
fetchTiming,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -76,6 +76,7 @@ import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.collection.SQLLoadableCollection;
|
import org.hibernate.persister.collection.SQLLoadableCollection;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.Joinable;
|
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.internal.PropertyAccessStrategyMapImpl;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
|
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||||
import org.hibernate.tuple.ValueGeneration;
|
import org.hibernate.tuple.ValueGeneration;
|
||||||
import org.hibernate.type.AnyType;
|
import org.hibernate.type.AnyType;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
|
@ -908,6 +910,17 @@ public class MappingModelCreationHelper {
|
||||||
final ModelPart fkTarget;
|
final ModelPart fkTarget;
|
||||||
final String lhsPropertyName = collectionDescriptor.getCollectionType().getLHSPropertyName();
|
final String lhsPropertyName = collectionDescriptor.getCollectionType().getLHSPropertyName();
|
||||||
final boolean isReferenceToPrimaryKey = lhsPropertyName == null;
|
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 ) {
|
if ( isReferenceToPrimaryKey ) {
|
||||||
fkTarget = collectionDescriptor.getOwnerEntityPersister().getIdentifierMapping();
|
fkTarget = collectionDescriptor.getOwnerEntityPersister().getIdentifierMapping();
|
||||||
}
|
}
|
||||||
|
@ -929,6 +942,7 @@ public class MappingModelCreationHelper {
|
||||||
);
|
);
|
||||||
attributeMapping.setForeignKeyDescriptor(
|
attributeMapping.setForeignKeyDescriptor(
|
||||||
new SimpleForeignKeyDescriptor(
|
new SimpleForeignKeyDescriptor(
|
||||||
|
keyDeclaringType,
|
||||||
simpleFkTarget,
|
simpleFkTarget,
|
||||||
null,
|
null,
|
||||||
keySelectableMapping,
|
keySelectableMapping,
|
||||||
|
@ -943,6 +957,9 @@ public class MappingModelCreationHelper {
|
||||||
buildEmbeddableForeignKeyDescriptor(
|
buildEmbeddableForeignKeyDescriptor(
|
||||||
(EmbeddableValuedModelPart) fkTarget,
|
(EmbeddableValuedModelPart) fkTarget,
|
||||||
bootValueMapping,
|
bootValueMapping,
|
||||||
|
keyDeclaringType,
|
||||||
|
collectionDescriptor.getAttributeMapping(),
|
||||||
|
false,
|
||||||
dialect,
|
dialect,
|
||||||
creationProcess
|
creationProcess
|
||||||
);
|
);
|
||||||
|
@ -1025,6 +1042,8 @@ public class MappingModelCreationHelper {
|
||||||
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor(
|
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor(
|
||||||
(EmbeddableValuedModelPart) modelPart,
|
(EmbeddableValuedModelPart) modelPart,
|
||||||
bootValueMapping,
|
bootValueMapping,
|
||||||
|
attributeMapping.getDeclaringType(),
|
||||||
|
attributeMapping.findContainingEntityMapping(),
|
||||||
true,
|
true,
|
||||||
dialect,
|
dialect,
|
||||||
creationProcess
|
creationProcess
|
||||||
|
@ -1058,12 +1077,15 @@ public class MappingModelCreationHelper {
|
||||||
if ( inversePropertyAccess == null ) {
|
if ( inversePropertyAccess == null ) {
|
||||||
// So far, OneToOne mappings are only supported based on the owner's PK
|
// So far, OneToOne mappings are only supported based on the owner's PK
|
||||||
if ( bootValueMapping instanceof OneToOne ) {
|
if ( bootValueMapping instanceof OneToOne ) {
|
||||||
declaringKeyPart = (BasicValuedModelPart) attributeMapping.findContainingEntityMapping().getIdentifierMapping();
|
declaringKeyPart = simpleFkTarget;
|
||||||
|
final EntityIdentifierMapping identifierMapping = attributeMapping.findContainingEntityMapping()
|
||||||
|
.getIdentifierMapping();
|
||||||
|
declaringKeyPropertyAccess = ( (PropertyBasedMapping) identifierMapping ).getPropertyAccess();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
declaringKeyPart = simpleFkTarget;
|
declaringKeyPart = simpleFkTarget;
|
||||||
|
declaringKeyPropertyAccess = ( (PropertyBasedMapping) declaringKeyPart ).getPropertyAccess();
|
||||||
}
|
}
|
||||||
declaringKeyPropertyAccess = ( (PropertyBasedMapping) declaringKeyPart ).getPropertyAccess();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
declaringKeyPart = simpleFkTarget;
|
declaringKeyPart = simpleFkTarget;
|
||||||
|
@ -1094,6 +1116,7 @@ public class MappingModelCreationHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
final ForeignKeyDescriptor foreignKeyDescriptor = new SimpleForeignKeyDescriptor(
|
final ForeignKeyDescriptor foreignKeyDescriptor = new SimpleForeignKeyDescriptor(
|
||||||
|
attributeMapping.getDeclaringType(),
|
||||||
declaringKeyPart,
|
declaringKeyPart,
|
||||||
declaringKeyPropertyAccess,
|
declaringKeyPropertyAccess,
|
||||||
keySelectableMapping,
|
keySelectableMapping,
|
||||||
|
@ -1108,6 +1131,8 @@ public class MappingModelCreationHelper {
|
||||||
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor(
|
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor(
|
||||||
(EmbeddableValuedModelPart) fkTarget,
|
(EmbeddableValuedModelPart) fkTarget,
|
||||||
bootValueMapping,
|
bootValueMapping,
|
||||||
|
attributeMapping.getDeclaringType(),
|
||||||
|
attributeMapping.findContainingEntityMapping(),
|
||||||
swapDirection,
|
swapDirection,
|
||||||
dialect,
|
dialect,
|
||||||
creationProcess
|
creationProcess
|
||||||
|
@ -1179,20 +1204,8 @@ public class MappingModelCreationHelper {
|
||||||
public static EmbeddedForeignKeyDescriptor buildEmbeddableForeignKeyDescriptor(
|
public static EmbeddedForeignKeyDescriptor buildEmbeddableForeignKeyDescriptor(
|
||||||
EmbeddableValuedModelPart embeddableValuedModelPart,
|
EmbeddableValuedModelPart embeddableValuedModelPart,
|
||||||
Value bootValueMapping,
|
Value bootValueMapping,
|
||||||
Dialect dialect,
|
ManagedMappingType keyDeclaringType,
|
||||||
MappingModelCreationProcess creationProcess) {
|
TableGroupProducer keyDeclaringTableGroupProducer,
|
||||||
return buildEmbeddableForeignKeyDescriptor(
|
|
||||||
embeddableValuedModelPart,
|
|
||||||
bootValueMapping,
|
|
||||||
false,
|
|
||||||
dialect,
|
|
||||||
creationProcess
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static EmbeddedForeignKeyDescriptor buildEmbeddableForeignKeyDescriptor(
|
|
||||||
EmbeddableValuedModelPart embeddableValuedModelPart,
|
|
||||||
Value bootValueMapping,
|
|
||||||
boolean inverse,
|
boolean inverse,
|
||||||
Dialect dialect,
|
Dialect dialect,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
|
@ -1241,6 +1254,8 @@ public class MappingModelCreationHelper {
|
||||||
embeddableValuedModelPart,
|
embeddableValuedModelPart,
|
||||||
EmbeddedAttributeMapping.createInverseModelPart(
|
EmbeddedAttributeMapping.createInverseModelPart(
|
||||||
embeddableValuedModelPart,
|
embeddableValuedModelPart,
|
||||||
|
keyDeclaringType,
|
||||||
|
keyDeclaringTableGroupProducer,
|
||||||
keySelectableMappings,
|
keySelectableMappings,
|
||||||
creationProcess
|
creationProcess
|
||||||
),
|
),
|
||||||
|
@ -1256,6 +1271,8 @@ public class MappingModelCreationHelper {
|
||||||
return new EmbeddedForeignKeyDescriptor(
|
return new EmbeddedForeignKeyDescriptor(
|
||||||
EmbeddedAttributeMapping.createInverseModelPart(
|
EmbeddedAttributeMapping.createInverseModelPart(
|
||||||
embeddableValuedModelPart,
|
embeddableValuedModelPart,
|
||||||
|
keyDeclaringType,
|
||||||
|
keyDeclaringTableGroupProducer,
|
||||||
keySelectableMappings,
|
keySelectableMappings,
|
||||||
creationProcess
|
creationProcess
|
||||||
),
|
),
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.mapping.ManyToOne;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping;
|
import org.hibernate.metamodel.internal.AbstractCompositeIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||||
|
@ -175,7 +176,7 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFetchableName() {
|
public String getFetchableName() {
|
||||||
return "id";
|
return EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,14 +6,11 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
|
||||||
import org.hibernate.dialect.Dialect;
|
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.engine.spi.CascadeStyle;
|
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.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.IndexedCollection;
|
|
||||||
import org.hibernate.mapping.IndexedConsumer;
|
import org.hibernate.mapping.IndexedConsumer;
|
||||||
import org.hibernate.mapping.List;
|
import org.hibernate.mapping.List;
|
||||||
import org.hibernate.mapping.Property;
|
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.CollectionIdentifierDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.CollectionMappingType;
|
import org.hibernate.metamodel.mapping.CollectionMappingType;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
||||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragmentTranslator;
|
import org.hibernate.metamodel.mapping.ordering.OrderByFragmentTranslator;
|
||||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
import org.hibernate.persister.entity.Joinable;
|
import org.hibernate.persister.entity.Joinable;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.query.NavigablePath;
|
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.SqlAstCreationState;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
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.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
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.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
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.EagerCollectionFetch;
|
||||||
import org.hibernate.sql.results.graph.collection.internal.SelectEagerCollectionFetch;
|
import org.hibernate.sql.results.graph.collection.internal.SelectEagerCollectionFetch;
|
||||||
import org.hibernate.tuple.ValueGeneration;
|
import org.hibernate.tuple.ValueGeneration;
|
||||||
import org.hibernate.type.EntityType;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
@ -113,45 +102,10 @@ public class PluralAttributeMappingImpl
|
||||||
private final IndexMetadata indexMetadata;
|
private final IndexMetadata indexMetadata;
|
||||||
|
|
||||||
private ForeignKeyDescriptor fkDescriptor;
|
private ForeignKeyDescriptor fkDescriptor;
|
||||||
private ForeignKeyDescriptor elementFkDescriptor;
|
|
||||||
private ForeignKeyDescriptor indexFkDescriptor;
|
|
||||||
|
|
||||||
private OrderByFragment orderByFragment;
|
private OrderByFragment orderByFragment;
|
||||||
private OrderByFragment manyToManyOrderByFragment;
|
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"})
|
@SuppressWarnings({"WeakerAccess", "rawtypes"})
|
||||||
public PluralAttributeMappingImpl(
|
public PluralAttributeMappingImpl(
|
||||||
String attributeName,
|
String attributeName,
|
||||||
|
@ -243,40 +197,6 @@ public class PluralAttributeMappingImpl
|
||||||
Property bootProperty,
|
Property bootProperty,
|
||||||
Collection bootDescriptor,
|
Collection bootDescriptor,
|
||||||
MappingModelCreationProcess creationProcess) {
|
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 hasOrder = bootDescriptor.getOrderBy() != null;
|
||||||
final boolean hasManyToManyOrder = bootDescriptor.getManyToManyOrdering() != 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
|
@Override
|
||||||
public NavigableRole getNavigableRole() {
|
public NavigableRole getNavigableRole() {
|
||||||
return getCollectionDescriptor().getNavigableRole();
|
return getCollectionDescriptor().getNavigableRole();
|
||||||
|
@ -482,6 +349,10 @@ public class PluralAttributeMappingImpl
|
||||||
|
|
||||||
assert collectionTableGroup != null;
|
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
|
//noinspection unchecked
|
||||||
return new CollectionDomainResult( navigablePath, this, resultVariable, tableGroup, creationState );
|
return new CollectionDomainResult( navigablePath, this, resultVariable, tableGroup, creationState );
|
||||||
}
|
}
|
||||||
|
@ -498,7 +369,7 @@ public class PluralAttributeMappingImpl
|
||||||
|
|
||||||
creationState.registerVisitedAssociationKey( fkDescriptor.getAssociationKey() );
|
creationState.registerVisitedAssociationKey( fkDescriptor.getAssociationKey() );
|
||||||
|
|
||||||
if ( fetchTiming == FetchTiming.IMMEDIATE) {
|
if ( fetchTiming == FetchTiming.IMMEDIATE ) {
|
||||||
if ( selected ) {
|
if ( selected ) {
|
||||||
final TableGroup collectionTableGroup = resolveCollectionTableGroup(
|
final TableGroup collectionTableGroup = resolveCollectionTableGroup(
|
||||||
fetchParent,
|
fetchParent,
|
||||||
|
@ -628,29 +499,26 @@ public class PluralAttributeMappingImpl
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
|
final java.util.List<Predicate> predicates = new ArrayList<>( 2 );
|
||||||
final TableGroup tableGroup = createRootTableGroupJoin(
|
final TableGroup tableGroup = createRootTableGroupJoin(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
lhs,
|
lhs,
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
sqlAstJoinType,
|
sqlAstJoinType,
|
||||||
fetched,
|
fetched,
|
||||||
null,
|
predicates::add,
|
||||||
aliasBaseGenerator,
|
aliasBaseGenerator,
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
return new TableGroupJoin(
|
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
sqlAstJoinType,
|
sqlAstJoinType,
|
||||||
tableGroup,
|
tableGroup,
|
||||||
getKeyDescriptor().generateJoinPredicate(
|
null
|
||||||
lhs,
|
|
||||||
tableGroup,
|
|
||||||
sqlAstJoinType,
|
|
||||||
sqlExpressionResolver,
|
|
||||||
creationContext
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
predicates.forEach( tableGroupJoin::applyPredicate );
|
||||||
|
return tableGroupJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -715,125 +583,36 @@ public class PluralAttributeMappingImpl
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final EntityMappingType elementDescriptorEntityMappingType;
|
final TableGroup elementTableGroup = ( (EntityCollectionPart) elementDescriptor ).createTableGroupInternal(
|
||||||
if ( elementDescriptor instanceof EntityCollectionPart ) {
|
canUseInnerJoins,
|
||||||
elementDescriptorEntityMappingType = ( (EntityCollectionPart) elementDescriptor ).getEntityMappingType();
|
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||||
}
|
fetched,
|
||||||
else {
|
sourceAlias,
|
||||||
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(
|
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
final OneToManyTableGroup tableGroup = new OneToManyTableGroup(
|
||||||
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,
|
|
||||||
this,
|
this,
|
||||||
fetched,
|
elementTableGroup,
|
||||||
sourceAlias,
|
|
||||||
primaryTableReference,
|
|
||||||
true,
|
|
||||||
sqlAliasBase,
|
|
||||||
tableReferenceJoinNameChecker,
|
|
||||||
tableReferenceJoinCreator,
|
|
||||||
creationContext.getSessionFactory()
|
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(
|
private TableGroup createCollectionTableGroup(
|
||||||
|
@ -854,116 +633,7 @@ public class PluralAttributeMappingImpl
|
||||||
creationContext.getSessionFactory()
|
creationContext.getSessionFactory()
|
||||||
);
|
);
|
||||||
|
|
||||||
final EntityMappingType elementDescriptorEntityMappingType;
|
final CollectionTableGroup tableGroup = new CollectionTableGroup(
|
||||||
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(
|
|
||||||
canUseInnerJoins,
|
canUseInnerJoins,
|
||||||
navigablePath,
|
navigablePath,
|
||||||
this,
|
this,
|
||||||
|
@ -972,86 +642,39 @@ public class PluralAttributeMappingImpl
|
||||||
collectionTableReference,
|
collectionTableReference,
|
||||||
true,
|
true,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
tableReferenceJoinNameChecker,
|
s -> false,
|
||||||
tableReferenceJoinCreator,
|
null,
|
||||||
creationContext.getSessionFactory()
|
creationContext.getSessionFactory()
|
||||||
);
|
);
|
||||||
|
|
||||||
return tableGroup;
|
if ( indexDescriptor instanceof EntityCollectionPart ) {
|
||||||
}
|
final TableGroupJoin tableGroupJoin = ( (EntityCollectionPart) indexDescriptor ).createTableGroupJoin(
|
||||||
|
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||||
private TableReferenceJoin createTableReferenceJoin(
|
tableGroup,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
null,
|
||||||
SqlAstCreationContext creationContext,
|
SqlAstJoinType.INNER,
|
||||||
SqlAliasBase sqlAliasBase,
|
fetched,
|
||||||
EntityMappingType elementDescriptorEntityMappingType,
|
stem -> sqlAliasBase,
|
||||||
TableReference elementAssociatedPrimaryTable,
|
sqlExpressionResolver,
|
||||||
Function<TableGroup, TableReferenceJoin> elementTableGroupFinalizer,
|
creationContext
|
||||||
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
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
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(
|
return tableGroup;
|
||||||
EntityMappingType elementDescriptorEntityMappingType,
|
|
||||||
EntityMappingType indexDescriptorEntityMappingType) {
|
|
||||||
return tableExpression -> {
|
|
||||||
if ( elementDescriptorEntityMappingType != null
|
|
||||||
&& elementDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ( indexDescriptorEntityMappingType != null
|
|
||||||
&& indexDescriptorEntityMappingType.containsTableReference( tableExpression ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1068,7 +691,7 @@ public class PluralAttributeMappingImpl
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
additionalPredicateCollectorAccess,
|
additionalPredicateCollectorAccess,
|
||||||
creationState.getSqlAliasBaseGenerator().createSqlAliasBase( getSqlAliasStem() ),
|
creationState.getSqlAliasBaseGenerator().createSqlAliasBase( getSqlAliasStem() ),
|
||||||
creationState,
|
creationState.getSqlExpressionResolver(),
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +703,7 @@ public class PluralAttributeMappingImpl
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
SqlAstCreationState creationState,
|
SqlExpressionResolver expressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
if ( getCollectionDescriptor().isOneToMany() ) {
|
if ( getCollectionDescriptor().isOneToMany() ) {
|
||||||
return createOneToManyTableGroup(
|
return createOneToManyTableGroup(
|
||||||
|
@ -1089,7 +712,7 @@ public class PluralAttributeMappingImpl
|
||||||
false,
|
false,
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
creationState.getSqlExpressionResolver(),
|
expressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1100,7 +723,7 @@ public class PluralAttributeMappingImpl
|
||||||
false,
|
false,
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
creationState.getSqlExpressionResolver(),
|
expressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.PropertyBasedMapping;
|
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.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.TableReference;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
|
||||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
|
@ -61,16 +62,18 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
private AssociationKey associationKey;
|
private AssociationKey associationKey;
|
||||||
|
|
||||||
public SimpleForeignKeyDescriptor(
|
public SimpleForeignKeyDescriptor(
|
||||||
|
ManagedMappingType keyDeclaringType,
|
||||||
BasicValuedModelPart keyModelPart,
|
BasicValuedModelPart keyModelPart,
|
||||||
PropertyAccess keyPropertyAccess,
|
PropertyAccess keyPropertyAccess,
|
||||||
SelectableMapping keySelectableMapping,
|
SelectableMapping keySelectableMapping,
|
||||||
BasicValuedModelPart targetModelPart,
|
BasicValuedModelPart targetModelPart,
|
||||||
boolean refersToPrimaryKey,
|
boolean refersToPrimaryKey,
|
||||||
boolean hasConstraint) {
|
boolean hasConstraint) {
|
||||||
this( keyModelPart, keyPropertyAccess, keySelectableMapping, targetModelPart, refersToPrimaryKey, hasConstraint, false );
|
this( keyDeclaringType, keyModelPart, keyPropertyAccess, keySelectableMapping, targetModelPart, refersToPrimaryKey, hasConstraint, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimpleForeignKeyDescriptor(
|
public SimpleForeignKeyDescriptor(
|
||||||
|
ManagedMappingType keyDeclaringType,
|
||||||
BasicValuedModelPart keyModelPart,
|
BasicValuedModelPart keyModelPart,
|
||||||
PropertyAccess keyPropertyAccess,
|
PropertyAccess keyPropertyAccess,
|
||||||
SelectableMapping keySelectableMapping,
|
SelectableMapping keySelectableMapping,
|
||||||
|
@ -82,6 +85,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
assert targetModelPart != null;
|
assert targetModelPart != null;
|
||||||
|
|
||||||
keyModelPart = BasicAttributeMapping.withSelectableMapping(
|
keyModelPart = BasicAttributeMapping.withSelectableMapping(
|
||||||
|
keyDeclaringType,
|
||||||
keyModelPart,
|
keyModelPart,
|
||||||
keyPropertyAccess,
|
keyPropertyAccess,
|
||||||
NoValueGeneration.INSTANCE,
|
NoValueGeneration.INSTANCE,
|
||||||
|
@ -131,9 +135,12 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ForeignKeyDescriptor withKeySelectionMapping(
|
public ForeignKeyDescriptor withKeySelectionMapping(
|
||||||
|
ManagedMappingType declaringType,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
IntFunction<SelectableMapping> selectableMappingAccess,
|
IntFunction<SelectableMapping> selectableMappingAccess,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
return new SimpleForeignKeyDescriptor(
|
return new SimpleForeignKeyDescriptor(
|
||||||
|
declaringType,
|
||||||
keySide.getModelPart(),
|
keySide.getModelPart(),
|
||||||
( (PropertyBasedMapping) keySide.getModelPart() ).getPropertyAccess(),
|
( (PropertyBasedMapping) keySide.getModelPart() ).getPropertyAccess(),
|
||||||
selectableMappingAccess.apply( 0 ),
|
selectableMappingAccess.apply( 0 ),
|
||||||
|
@ -148,8 +155,6 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
assert tableGroup.getTableReference( navigablePath, keySide.getModelPart().getContainingTableExpression() ) != null;
|
|
||||||
|
|
||||||
return createDomainResult(
|
return createDomainResult(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
tableGroup,
|
tableGroup,
|
||||||
|
@ -160,8 +165,6 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DomainResult<?> createTargetDomainResult(NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState) {
|
public DomainResult<?> createTargetDomainResult(NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||||
assert tableGroup.getTableReference( navigablePath, targetSide.getModelPart().getContainingTableExpression() ) != null;
|
|
||||||
|
|
||||||
return createDomainResult(
|
return createDomainResult(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
tableGroup,
|
tableGroup,
|
||||||
|
@ -210,7 +213,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||||
|
|
||||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||||
navigablePath.append( getNavigableRole().getNavigableName() ),
|
navigablePath.append( getTargetPart().getFetchableName() ),
|
||||||
selectableMapping.getContainingTableExpression()
|
selectableMapping.getContainingTableExpression()
|
||||||
);
|
);
|
||||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||||
|
@ -269,11 +272,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
|
final TableReference lhsTableReference = targetSideTableGroup.resolveTableReference(
|
||||||
targetSideTableGroup.getNavigablePath(),
|
targetSideTableGroup.getNavigablePath(),
|
||||||
targetSide.getModelPart().getContainingTableExpression()
|
targetSide.getModelPart().getContainingTableExpression()
|
||||||
);
|
);
|
||||||
final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference(
|
final TableReference rhsTableKeyReference = keySideTableGroup.resolveTableReference(
|
||||||
keySide.getModelPart().getContainingTableExpression()
|
keySide.getModelPart().getContainingTableExpression()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -287,7 +290,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
|
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 ) {
|
if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) {
|
||||||
return lhs.getPrimaryTableReference();
|
return lhs.getPrimaryTableReference();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -17,6 +18,7 @@ import org.hibernate.LockMode;
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
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.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.query.EntityIdentifierNavigablePath;
|
import org.hibernate.query.EntityIdentifierNavigablePath;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.query.TreatedNavigablePath;
|
||||||
import org.hibernate.sql.ast.Clause;
|
import org.hibernate.sql.ast.Clause;
|
||||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
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.tuple.entity.EntityMetamodel;
|
||||||
import org.hibernate.type.ComponentType;
|
import org.hibernate.type.ComponentType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
import org.hibernate.type.EntityType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -360,22 +364,50 @@ public class ToOneAttributeMapping
|
||||||
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
|
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
|
||||||
&& compositeType.getPropertyNames().length == 1 ) {
|
&& compositeType.getPropertyNames().length == 1 ) {
|
||||||
this.targetKeyPropertyName = compositeType.getPropertyNames()[0];
|
this.targetKeyPropertyName = compositeType.getPropertyNames()[0];
|
||||||
addPrefixedPropertyNames( targetKeyPropertyNames, targetKeyPropertyName, compositeType.getSubtypes()[0] );
|
addPrefixedPropertyNames(
|
||||||
|
targetKeyPropertyNames,
|
||||||
|
targetKeyPropertyName,
|
||||||
|
compositeType.getSubtypes()[0],
|
||||||
|
declaringEntityPersister.getFactory()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.targetKeyPropertyName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
this.targetKeyPropertyName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||||
addPrefixedPropertyNames( targetKeyPropertyNames, null, propertyType );
|
addPrefixedPropertyNames(
|
||||||
|
targetKeyPropertyNames,
|
||||||
|
null,
|
||||||
|
propertyType,
|
||||||
|
declaringEntityPersister.getFactory()
|
||||||
|
);
|
||||||
|
addPrefixedPropertyNames(
|
||||||
|
targetKeyPropertyNames,
|
||||||
|
targetKeyPropertyName,
|
||||||
|
propertyType,
|
||||||
|
declaringEntityPersister.getFactory()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.targetKeyPropertyName = identifierProperty.getName();
|
this.targetKeyPropertyName = identifierProperty.getName();
|
||||||
addPrefixedPropertyNames( targetKeyPropertyNames, targetKeyPropertyName, propertyType );
|
addPrefixedPropertyNames(
|
||||||
|
targetKeyPropertyNames,
|
||||||
|
targetKeyPropertyName,
|
||||||
|
propertyType,
|
||||||
|
declaringEntityPersister.getFactory()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||||
}
|
}
|
||||||
else if ( bootValue.isReferenceToPrimaryKey() ) {
|
else if ( bootValue.isReferenceToPrimaryKey() ) {
|
||||||
this.targetKeyPropertyName = referencedPropertyName;
|
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 {
|
else {
|
||||||
final EntityMetamodel entityMetamodel = entityMappingType.getEntityPersister().getEntityMetamodel();
|
final EntityMetamodel entityMetamodel = entityMappingType.getEntityPersister().getEntityMetamodel();
|
||||||
|
@ -389,18 +421,35 @@ public class ToOneAttributeMapping
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.targetKeyPropertyName = referencedPropertyName;
|
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(
|
super(
|
||||||
original.getAttributeName(),
|
original.getAttributeName(),
|
||||||
original.getStateArrayPosition(),
|
original.getStateArrayPosition(),
|
||||||
original.getAttributeMetadataAccess(),
|
original.getAttributeMetadataAccess(),
|
||||||
original,
|
original,
|
||||||
original.getDeclaringType(),
|
declaringType,
|
||||||
original.getPropertyAccess(),
|
original.getPropertyAccess(),
|
||||||
original.getValueGeneration()
|
original.getValueGeneration()
|
||||||
);
|
);
|
||||||
|
@ -417,7 +466,7 @@ public class ToOneAttributeMapping
|
||||||
this.targetKeyPropertyNames = original.targetKeyPropertyNames;
|
this.targetKeyPropertyNames = original.targetKeyPropertyNames;
|
||||||
this.cardinality = original.cardinality;
|
this.cardinality = original.cardinality;
|
||||||
this.bidirectionalAttributeName = original.bidirectionalAttributeName;
|
this.bidirectionalAttributeName = original.bidirectionalAttributeName;
|
||||||
this.declaringTableGroupProducer = original.declaringTableGroupProducer;
|
this.declaringTableGroupProducer = declaringTableGroupProducer;
|
||||||
this.isConstrained = original.isConstrained;
|
this.isConstrained = original.isConstrained;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,10 +487,19 @@ public class ToOneAttributeMapping
|
||||||
return true;
|
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,
|
Set<String> targetKeyPropertyNames,
|
||||||
String prefix,
|
String prefix,
|
||||||
Type type) {
|
Type type,
|
||||||
|
SessionFactoryImplementor factory) {
|
||||||
if ( prefix != null ) {
|
if ( prefix != null ) {
|
||||||
targetKeyPropertyNames.add( prefix );
|
targetKeyPropertyNames.add( prefix );
|
||||||
}
|
}
|
||||||
|
@ -457,13 +515,32 @@ public class ToOneAttributeMapping
|
||||||
else {
|
else {
|
||||||
newPrefix = prefix + "." + propertyNames[i];
|
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() {
|
public ToOneAttributeMapping copy(ManagedMappingType declaringType, TableGroupProducer declaringTableGroupProducer) {
|
||||||
return new ToOneAttributeMapping( this );
|
return new ToOneAttributeMapping( this, declaringType, declaringTableGroupProducer );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -538,7 +615,7 @@ public class ToOneAttributeMapping
|
||||||
public ModelPart findSubPart(String name, EntityMappingType targetType) {
|
public ModelPart findSubPart(String name, EntityMappingType targetType) {
|
||||||
// Prefer resolving the key part of the foreign key rather than the target part if possible
|
// 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
|
// 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 foreignKeyDescriptor.getKeyPart();
|
||||||
}
|
}
|
||||||
return EntityValuedFetchable.super.findSubPart( name, targetType );
|
return EntityValuedFetchable.super.findSubPart( name, targetType );
|
||||||
|
@ -606,7 +683,7 @@ public class ToOneAttributeMapping
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
fetchParent,
|
fetchParent,
|
||||||
parentNavigablePath,
|
parentNavigablePath,
|
||||||
LockMode.READ
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,14 +772,17 @@ public class ToOneAttributeMapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( parentModelPart instanceof PluralAttributeMapping ) {
|
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 ) {
|
else if ( parentModelPart instanceof EntityCollectionPart ) {
|
||||||
NavigablePath parentOfParent = parentNavigablePath.getParent();
|
NavigablePath parentOfParent = parentNavigablePath.getParent();
|
||||||
if ( parentOfParent instanceof EntityIdentifierNavigablePath ) {
|
if ( parentOfParent instanceof EntityIdentifierNavigablePath ) {
|
||||||
parentOfParent = parentOfParent.getParent();
|
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 );
|
.isBidirectionalAttributeName( fetchablePath, this );
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -723,11 +803,18 @@ public class ToOneAttributeMapping
|
||||||
this.mappedBy = "biologicalChild"
|
this.mappedBy = "biologicalChild"
|
||||||
parent.getFullPath() = "Mother.biologicalChild"
|
parent.getFullPath() = "Mother.biologicalChild"
|
||||||
*/
|
*/
|
||||||
final String fullPath = parentNavigablePath.getFullPath();
|
final NavigablePath grandparentNavigablePath = parentNavigablePath.getParent();
|
||||||
if ( fullPath.endsWith( bidirectionalAttributeName + "." + CollectionPart.Nature.ELEMENT.getName() ) ) {
|
if ( parentNavigablePath.getUnaliasedLocalName().equals( CollectionPart.Nature.ELEMENT.getName() )
|
||||||
final NavigablePath parentPath = parentNavigablePath.getParent().getParent();
|
&& grandparentNavigablePath != null
|
||||||
|
&& grandparentNavigablePath.getUnaliasedLocalName().equals( bidirectionalAttributeName ) ) {
|
||||||
|
final NavigablePath parentPath = grandparentNavigablePath.getParent();
|
||||||
// This can be null for a collection loader
|
// 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 the parent is null, this is a simple collection fetch of a root, in which case the types must match
|
||||||
if ( parentPath.getParent() == null ) {
|
if ( parentPath.getParent() == null ) {
|
||||||
final String entityName = entityMappingType.getPartName();
|
final String entityName = entityMappingType.getPartName();
|
||||||
|
@ -756,22 +843,83 @@ public class ToOneAttributeMapping
|
||||||
NavigablePath fetchablePath,
|
NavigablePath fetchablePath,
|
||||||
FetchParent fetchParent,
|
FetchParent fetchParent,
|
||||||
NavigablePath parentNavigablePath,
|
NavigablePath parentNavigablePath,
|
||||||
LockMode lockMode) {
|
DomainResultCreationState creationState) {
|
||||||
NavigablePath referencedNavigablePath;
|
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 ) {
|
if ( parentNavigablePath.getParent() == null ) {
|
||||||
referencedNavigablePath = parentNavigablePath;
|
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 {
|
else {
|
||||||
referencedNavigablePath = parentNavigablePath.getParent();
|
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
|
@Override
|
||||||
|
@ -791,7 +939,9 @@ public class ToOneAttributeMapping
|
||||||
);
|
);
|
||||||
|
|
||||||
final NavigablePath parentNavigablePath = fetchablePath.getParent();
|
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 ) {
|
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
|
||||||
final TableGroup tableGroup;
|
final TableGroup tableGroup;
|
||||||
|
@ -905,7 +1055,8 @@ public class ToOneAttributeMapping
|
||||||
fetchParent,
|
fetchParent,
|
||||||
this,
|
this,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
keyResult
|
keyResult,
|
||||||
|
selectByUniqueKey
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,7 +1068,10 @@ public class ToOneAttributeMapping
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// case 1.1
|
// 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
|
// 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
|
// 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 ) {
|
if ( sideNature == ForeignKeyDescriptor.Nature.TARGET || referencedPropertyName != null ) {
|
||||||
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
tableGroup,
|
np -> {
|
||||||
null,
|
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||||
getDefaultSqlAstJoinType( tableGroup ),
|
navigablePath,
|
||||||
true,
|
tableGroup,
|
||||||
creationState.getSqlAstCreationState()
|
null,
|
||||||
);
|
getDefaultSqlAstJoinType( tableGroup ),
|
||||||
tableGroup.addTableGroupJoin( tableGroupJoin );
|
true,
|
||||||
|
creationState.getSqlAstCreationState()
|
||||||
creationState.getSqlAstCreationState().getFromClauseAccess().registerTableGroup(
|
);
|
||||||
navigablePath,
|
tableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
tableGroupJoin.getJoinedGroup()
|
return tableGroupJoin.getJoinedGroup();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( referencedPropertyName == null ) {
|
if ( referencedPropertyName == null ) {
|
||||||
|
@ -955,12 +1110,15 @@ public class ToOneAttributeMapping
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We don't support proxies based on a non-PK yet, so we must fetch the whole entity
|
// 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,
|
navigablePath,
|
||||||
this,
|
this,
|
||||||
tableGroup, null,
|
tableGroup, null,
|
||||||
creationState
|
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
|
@Override
|
||||||
public int getNumberOfFetchables() {
|
public int getNumberOfFetchables() {
|
||||||
return getEntityMappingType().getNumberOfFetchables();
|
return getEntityMappingType().getNumberOfFetchables();
|
||||||
|
|
|
@ -401,7 +401,7 @@ public abstract class AbstractIdentifiableType<J>
|
||||||
else if ( nonAggregatedIdAttributes != null && ! nonAggregatedIdAttributes.isEmpty() ) {
|
else if ( nonAggregatedIdAttributes != null && ! nonAggregatedIdAttributes.isEmpty() ) {
|
||||||
// non-aggregate composite id
|
// non-aggregate composite id
|
||||||
if ( idClassType == null ) {
|
if ( idClassType == null ) {
|
||||||
return new NonAggregatedCompositeSqmPathSource(
|
return new NonAggregatedCompositeSqmPathSource<>(
|
||||||
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
||||||
Bindable.BindableType.SINGULAR_ATTRIBUTE,
|
Bindable.BindableType.SINGULAR_ATTRIBUTE,
|
||||||
this
|
this
|
||||||
|
|
|
@ -592,7 +592,7 @@ public class JpaMetamodelImpl implements JpaMetamodel, Serializable {
|
||||||
else {
|
else {
|
||||||
javaTypeDescriptor = context.getTypeConfiguration()
|
javaTypeDescriptor = context.getTypeConfiguration()
|
||||||
.getJavaTypeDescriptorRegistry()
|
.getJavaTypeDescriptorRegistry()
|
||||||
.resolveManagedTypeDescriptor( javaType );
|
.resolveEntityTypeDescriptor( javaType );
|
||||||
}
|
}
|
||||||
|
|
||||||
final EntityTypeImpl<?> entityType = new EntityTypeImpl(
|
final EntityTypeImpl<?> entityType = new EntityTypeImpl(
|
||||||
|
|
|
@ -16,11 +16,11 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class NonAggregatedCompositeSqmPathSource extends AbstractSqmPathSource implements CompositeSqmPathSource {
|
public class NonAggregatedCompositeSqmPathSource<J> extends AbstractSqmPathSource<J> implements CompositeSqmPathSource<J> {
|
||||||
public NonAggregatedCompositeSqmPathSource(
|
public NonAggregatedCompositeSqmPathSource(
|
||||||
String localName,
|
String localName,
|
||||||
BindableType bindableType,
|
BindableType bindableType,
|
||||||
ManagedDomainType container) {
|
ManagedDomainType<J> container) {
|
||||||
super( localName, container, bindableType );
|
super( localName, container, bindableType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ public class NonAggregatedCompositeSqmPathSource extends AbstractSqmPathSource i
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath createSqmPath(SqmPath lhs) {
|
public SqmPath<J> createSqmPath(SqmPath<?> lhs) {
|
||||||
return new NonAggregatedCompositeSimplePath(
|
return new NonAggregatedCompositeSimplePath<>(
|
||||||
lhs.getNavigablePath().append( getPathName() ),
|
lhs.getNavigablePath().append( getPathName() ),
|
||||||
this,
|
this,
|
||||||
lhs,
|
lhs,
|
||||||
|
|
|
@ -1171,7 +1171,7 @@ public abstract class AbstractCollectionPersister
|
||||||
null,
|
null,
|
||||||
() -> p -> {},
|
() -> p -> {},
|
||||||
new SqlAliasBaseConstant( alias ),
|
new SqlAliasBaseConstant( alias ),
|
||||||
sqlAstCreationState,
|
sqlAstCreationState.getSqlExpressionResolver(),
|
||||||
getFactory()
|
getFactory()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1828,7 +1828,7 @@ public abstract class AbstractCollectionPersister
|
||||||
buffer.append( " and " );
|
buffer.append( " and " );
|
||||||
}
|
}
|
||||||
assert elementPersister instanceof Joinable;
|
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() ) );
|
buffer.append( StringHelper.replace( manyToManyWhereTemplate, Template.TEMPLATE, tableReference.getIdentificationVariable() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -216,7 +216,6 @@ import org.hibernate.sql.ast.spi.SqlAliasBaseConstant;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
|
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
|
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
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.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.expression.AliasedExpression;
|
import org.hibernate.sql.ast.tree.expression.AliasedExpression;
|
||||||
|
@ -1266,8 +1265,16 @@ public abstract class AbstractEntityPersister
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
|
final EntityResultImpl entityResult = new EntityResultImpl(
|
||||||
|
navigablePath,
|
||||||
|
this,
|
||||||
|
tableGroup,
|
||||||
|
resultVariable,
|
||||||
|
creationState
|
||||||
|
);
|
||||||
|
entityResult.afterInitialize( entityResult, creationState );
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return new EntityResultImpl( navigablePath, this, tableGroup, resultVariable, creationState );
|
return entityResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1313,10 +1320,8 @@ public abstract class AbstractEntityPersister
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
SqlAstCreationState creationState,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlExpressionResolver();
|
|
||||||
|
|
||||||
final TableReference primaryTableReference = createPrimaryTableReference(
|
final TableReference primaryTableReference = createPrimaryTableReference(
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
|
@ -1905,7 +1910,7 @@ public abstract class AbstractEntityPersister
|
||||||
null,
|
null,
|
||||||
() -> p -> {},
|
() -> p -> {},
|
||||||
new SqlAliasBaseConstant( alias ),
|
new SqlAliasBaseConstant( alias ),
|
||||||
sqlAstCreationState,
|
sqlAstCreationState.getSqlExpressionResolver(),
|
||||||
getFactory()
|
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)
|
// EntityDefinition impl (walking model - deprecated)
|
||||||
|
|
|
@ -8,6 +8,8 @@ package org.hibernate.persister.entity;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -54,12 +56,14 @@ import org.hibernate.persister.spi.PersisterCreationContext;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.InFragment;
|
import org.hibernate.sql.InFragment;
|
||||||
import org.hibernate.sql.Insert;
|
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.CaseSearchedExpression;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
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.NullnessPredicate;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
|
@ -1293,14 +1297,79 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
if ( hasSubclasses() ) {
|
if ( hasSubclasses() ) {
|
||||||
|
final EntityResultJoinedSubclassImpl entityResultJoinedSubclass = new EntityResultJoinedSubclassImpl(
|
||||||
|
navigablePath,
|
||||||
|
this,
|
||||||
|
tableGroup,
|
||||||
|
resultVariable,
|
||||||
|
creationState
|
||||||
|
);
|
||||||
|
entityResultJoinedSubclass.afterInitialize( entityResultJoinedSubclass, creationState );
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return new EntityResultJoinedSubclassImpl( navigablePath, this, tableGroup, resultVariable, creationState );
|
return entityResultJoinedSubclass;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return super.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
|
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
|
@Override
|
||||||
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
|
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
|
||||||
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {
|
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {
|
||||||
|
|
|
@ -47,12 +47,12 @@ import org.hibernate.sql.InFragment;
|
||||||
import org.hibernate.sql.Insert;
|
import org.hibernate.sql.Insert;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
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.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.ComparisonPredicate;
|
||||||
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
|
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||||
|
@ -654,7 +654,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
||||||
if ( !queryable.isAbstract() ) {
|
if ( !queryable.isAbstract() ) {
|
||||||
values.add( queryable.getDiscriminatorSQLValue() );
|
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
|
// if the treat is an abstract class, add the concrete implementations to values if any
|
||||||
Set<String> actualSubClasses = queryable.getEntityMetamodel().getSubclassEntityNames();
|
Set<String> actualSubClasses = queryable.getEntityMetamodel().getSubclassEntityNames();
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
SqlAstCreationState creationState,
|
SqlExpressionResolver expressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final TableGroup tableGroup = super.createRootTableGroup(
|
final TableGroup tableGroup = super.createRootTableGroup(
|
||||||
canUseInnerJoins,
|
canUseInnerJoins,
|
||||||
|
@ -851,14 +851,14 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
additionalPredicateCollectorAccess,
|
additionalPredicateCollectorAccess,
|
||||||
sqlAliasBase,
|
sqlAliasBase,
|
||||||
creationState,
|
expressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( additionalPredicateCollectorAccess != null && needsDiscriminator() ) {
|
if ( additionalPredicateCollectorAccess != null && needsDiscriminator() ) {
|
||||||
final Predicate discriminatorPredicate = createDiscriminatorPredicate(
|
final Predicate discriminatorPredicate = createDiscriminatorPredicate(
|
||||||
tableGroup,
|
tableGroup,
|
||||||
creationState.getSqlExpressionResolver(),
|
expressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
additionalPredicateCollectorAccess.get().accept( discriminatorPredicate );
|
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
|
@Override
|
||||||
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
|
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
|
||||||
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {
|
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -42,12 +43,14 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Subclass;
|
import org.hibernate.mapping.Subclass;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
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.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
||||||
|
@ -251,7 +254,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAliasBase sqlAliasBase,
|
SqlAliasBase sqlAliasBase,
|
||||||
SqlAstCreationState creationState,
|
SqlExpressionResolver expressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final TableReference tableReference = resolvePrimaryTableReference( sqlAliasBase );
|
final TableReference tableReference = resolvePrimaryTableReference( sqlAliasBase );
|
||||||
|
|
||||||
|
@ -390,6 +393,14 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
return isAbstract() || hasSubclasses();
|
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
|
@Override
|
||||||
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
|
public void visitConstraintOrderedTables(ConstraintOrderedTableConsumer consumer) {
|
||||||
|
@ -509,6 +520,68 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
return buf.append( " )" ).toString();
|
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
|
@Override
|
||||||
protected String[] getSubclassTableKeyColumns(int j) {
|
protected String[] getSubclassTableKeyColumns(int j) {
|
||||||
if ( j != 0 ) {
|
if ( j != 0 ) {
|
||||||
|
|
|
@ -88,6 +88,7 @@ public class ProcedureParameterImpl<T> extends AbstractQueryParameter<T> impleme
|
||||||
return javaType;
|
return javaType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public NamedCallableQueryMemento.ParameterMemento toMemento() {
|
public NamedCallableQueryMemento.ParameterMemento toMemento() {
|
||||||
return session -> {
|
return session -> {
|
||||||
if ( getName() != null ) {
|
if ( getName() != null ) {
|
||||||
|
|
|
@ -101,6 +101,25 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
|
||||||
this( "" );
|
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) {
|
public NavigablePath append(String property) {
|
||||||
return new NavigablePath( this, property );
|
return new NavigablePath( this, property );
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,39 @@ package org.hibernate.query;
|
||||||
*/
|
*/
|
||||||
public class TreatedNavigablePath extends NavigablePath {
|
public class TreatedNavigablePath extends NavigablePath {
|
||||||
|
|
||||||
public static final String ROLE_LOCAL_NAME = "{treated}";
|
|
||||||
|
|
||||||
public TreatedNavigablePath(NavigablePath parent, String entityTypeName) {
|
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
|
@Override
|
||||||
public String getLocalName() {
|
public String getLocalName() {
|
||||||
return ROLE_LOCAL_NAME;
|
return getUnaliasedLocalName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return getParent().getFullPath().hashCode();
|
return getFullPath().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.criteria;
|
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.CollectionJoin;
|
||||||
import jakarta.persistence.criteria.Expression;
|
import jakarta.persistence.criteria.Expression;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
@ -15,7 +19,7 @@ import jakarta.persistence.criteria.Predicate;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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
|
@Override
|
||||||
JpaCollectionJoin<O, T> on(JpaExpression<Boolean> restriction);
|
JpaCollectionJoin<O, T> on(JpaExpression<Boolean> restriction);
|
||||||
|
@ -31,4 +35,7 @@ public interface JpaCollectionJoin<O, T> extends JpaJoin<O, T>, CollectionJoin<O
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
<S extends T> JpaCollectionJoin<O, S> treatAs(Class<S> treatAsType);
|
<S extends T> JpaCollectionJoin<O, S> treatAs(Class<S> treatAsType);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
<S extends T> JpaCollectionJoin<O, S> treatAs(EntityDomainType<S> treatAsType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import jakarta.persistence.criteria.Fetch;
|
||||||
import jakarta.persistence.criteria.Join;
|
import jakarta.persistence.criteria.Join;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,4 +33,10 @@ public interface JpaJoin<O, T> extends JpaJoinedFrom<O, T>, Join<O, T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
JpaJoin<O, T> on(Predicate... restrictions);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.criteria;
|
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.Expression;
|
||||||
import jakarta.persistence.criteria.ListJoin;
|
import jakarta.persistence.criteria.ListJoin;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
@ -15,7 +19,7 @@ import jakarta.persistence.criteria.Predicate;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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
|
@Override
|
||||||
JpaListJoin<O, T> on(JpaExpression<Boolean> restriction);
|
JpaListJoin<O, T> on(JpaExpression<Boolean> restriction);
|
||||||
|
|
||||||
|
@ -30,4 +34,7 @@ public interface JpaListJoin<O, T> extends JpaJoin<O, T>, ListJoin<O, T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
<S extends T> JpaListJoin<O, S> treatAs(Class<S> treatAsType);
|
<S extends T> JpaListJoin<O, S> treatAs(Class<S> treatAsType);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
<S extends T> JpaListJoin<O, S> treatAs(EntityDomainType<S> treatAsType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.criteria;
|
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.Expression;
|
||||||
import jakarta.persistence.criteria.MapJoin;
|
import jakarta.persistence.criteria.MapJoin;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
@ -15,7 +20,7 @@ import jakarta.persistence.criteria.Predicate;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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
|
@Override
|
||||||
JpaMapJoin<O, K, V> on(JpaExpression<Boolean> restriction);
|
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);
|
JpaMapJoin<O, K, V> on(Predicate... restrictions);
|
||||||
|
|
||||||
<S extends V> JpaMapJoin<O, K, S> treatAs(Class<S> treatAsType);
|
<S extends V> JpaMapJoin<O, K, S> treatAs(Class<S> treatAsType);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
<S extends V> JpaMapJoin<O, K, S> treatAs(EntityDomainType<S> treatJavaType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,12 @@ public interface JpaPath<T> extends JpaExpression<T>, Path<T> {
|
||||||
/**
|
/**
|
||||||
* Support for JPA's explicit (TREAT) down-casting.
|
* 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.
|
* 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);
|
||||||
|
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -6,6 +6,11 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.criteria;
|
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.Expression;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
import jakarta.persistence.criteria.SetJoin;
|
import jakarta.persistence.criteria.SetJoin;
|
||||||
|
@ -15,7 +20,7 @@ import jakarta.persistence.criteria.SetJoin;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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);
|
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);
|
JpaSetJoin<O, T> on(Predicate... restrictions);
|
||||||
|
|
||||||
<S extends T> JpaSetJoin<O, S> treatAs(Class<S> treatAsType);
|
<S extends T> JpaSetJoin<O, S> treatAs(Class<S> treatAsType);
|
||||||
|
|
||||||
|
<S extends T> JpaSetJoin<O, S> treatAs(EntityDomainType<S> treatAsType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.reflect.Field;
|
||||||
|
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
|
import org.hibernate.query.criteria.JpaPath;
|
||||||
import org.hibernate.query.hql.HqlLogging;
|
import org.hibernate.query.hql.HqlLogging;
|
||||||
import org.hibernate.query.hql.spi.DotIdentifierConsumer;
|
import org.hibernate.query.hql.spi.DotIdentifierConsumer;
|
||||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
import org.hibernate.query.hql.spi.SemanticPathPart;
|
||||||
|
@ -93,6 +94,13 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
|
||||||
currentPart = currentPart.resolvePathPart( identifier, isTerminal, creationState );
|
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() {
|
protected void reset() {
|
||||||
pathSoFar = null;
|
pathSoFar = null;
|
||||||
currentPart = createBasePart();
|
currentPart = createBasePart();
|
||||||
|
@ -249,13 +257,13 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
|
||||||
throw new ParsingException( "Could not interpret dot-ident : " + pathSoFar );
|
throw new ParsingException( "Could not interpret dot-ident : " + pathSoFar );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void validateAsRoot(SqmFrom pathRoot) {
|
protected void validateAsRoot(SqmFrom<?, ?> pathRoot) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath resolveIndexedAccess(
|
public SqmPath<?> resolveIndexedAccess(
|
||||||
SqmExpression selector,
|
SqmExpression<?> selector,
|
||||||
boolean isTerminal,
|
boolean isTerminal,
|
||||||
SqmCreationState processingState) {
|
SqmCreationState processingState) {
|
||||||
return currentPart.resolveIndexedAccess( selector, isTerminal, processingState );
|
return currentPart.resolveIndexedAccess( selector, isTerminal, processingState );
|
||||||
|
|
|
@ -144,8 +144,8 @@ public class DomainPathPart implements SemanticPathPart {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath resolveIndexedAccess(
|
public SqmPath<?> resolveIndexedAccess(
|
||||||
SqmExpression selector,
|
SqmExpression<?> selector,
|
||||||
boolean isTerminal,
|
boolean isTerminal,
|
||||||
SqmCreationState creationState) {
|
SqmCreationState creationState) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class FullyQualifiedReflectivePath implements SemanticPathPart, FullyQual
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath<?> resolveIndexedAccess(
|
public SqmPath<?> resolveIndexedAccess(
|
||||||
SqmExpression selector,
|
SqmExpression<?> selector,
|
||||||
boolean isTerminal,
|
boolean isTerminal,
|
||||||
SqmCreationState creationState) {
|
SqmCreationState creationState) {
|
||||||
throw new UnsupportedOperationException( "Fully qualified reflective paths cannot contain indexed access" );
|
throw new UnsupportedOperationException( "Fully qualified reflective paths cannot contain indexed access" );
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
||||||
private final String alias;
|
private final String alias;
|
||||||
|
|
||||||
private ConsumerDelegate delegate;
|
private ConsumerDelegate delegate;
|
||||||
|
private boolean treated;
|
||||||
|
|
||||||
public QualifiedJoinPathConsumer(
|
public QualifiedJoinPathConsumer(
|
||||||
SqmRoot<?> sqmRoot,
|
SqmRoot<?> sqmRoot,
|
||||||
|
@ -78,6 +79,10 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTreated(boolean treated) {
|
||||||
|
this.treated = treated;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SemanticPathPart getConsumedPart() {
|
public SemanticPathPart getConsumedPart() {
|
||||||
return delegate.getConsumedPart();
|
return delegate.getConsumedPart();
|
||||||
|
@ -87,14 +92,20 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
||||||
public void consumeIdentifier(String identifier, boolean isBase, boolean isTerminal) {
|
public void consumeIdentifier(String identifier, boolean isBase, boolean isTerminal) {
|
||||||
if ( isBase ) {
|
if ( isBase ) {
|
||||||
assert delegate == null;
|
assert delegate == null;
|
||||||
delegate = resolveBase( identifier, isTerminal );
|
delegate = resolveBase( identifier, !treated && isTerminal );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert delegate != null;
|
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) {
|
private ConsumerDelegate resolveBase(String identifier, boolean isTerminal) {
|
||||||
final SqmCreationProcessingState processingState = creationState.getCurrentProcessingState();
|
final SqmCreationProcessingState processingState = creationState.getCurrentProcessingState();
|
||||||
final SqmPathRegistry pathRegistry = processingState.getPathRegistry();
|
final SqmPathRegistry pathRegistry = processingState.getPathRegistry();
|
||||||
|
@ -187,6 +198,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
||||||
|
|
||||||
private interface ConsumerDelegate {
|
private interface ConsumerDelegate {
|
||||||
void consumeIdentifier(String identifier, boolean isTerminal);
|
void consumeIdentifier(String identifier, boolean isTerminal);
|
||||||
|
void consumeTreat(String entityName, boolean isTerminal);
|
||||||
SemanticPathPart getConsumedPart();
|
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
|
@Override
|
||||||
public SemanticPathPart getConsumedPart() {
|
public SemanticPathPart getConsumedPart() {
|
||||||
return currentPath;
|
return currentPath;
|
||||||
|
@ -240,7 +260,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
||||||
private final boolean fetch;
|
private final boolean fetch;
|
||||||
private final String alias;
|
private final String alias;
|
||||||
|
|
||||||
private NavigablePath path = new NavigablePath();
|
private final StringBuilder path = new StringBuilder();
|
||||||
|
|
||||||
private SqmEntityJoin<?> join;
|
private SqmEntityJoin<?> join;
|
||||||
|
|
||||||
|
@ -263,14 +283,17 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consumeIdentifier(String identifier, boolean isTerminal) {
|
public void consumeIdentifier(String identifier, boolean isTerminal) {
|
||||||
path = path.append( identifier );
|
if ( path.length() != 0 ) {
|
||||||
|
path.append( '.' );
|
||||||
|
}
|
||||||
|
path.append( identifier );
|
||||||
if ( isTerminal ) {
|
if ( isTerminal ) {
|
||||||
|
final String fullPath = path.toString();
|
||||||
final EntityDomainType<?> joinedEntityType = creationState.getCreationContext()
|
final EntityDomainType<?> joinedEntityType = creationState.getCreationContext()
|
||||||
.getJpaMetamodel()
|
.getJpaMetamodel()
|
||||||
.resolveHqlEntityReference( path.getFullPath() );
|
.resolveHqlEntityReference( fullPath );
|
||||||
if ( joinedEntityType == null ) {
|
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 );
|
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
|
@Override
|
||||||
public SemanticPathPart getConsumedPart() {
|
public SemanticPathPart getConsumedPart() {
|
||||||
return join;
|
return join;
|
||||||
|
|
|
@ -11,8 +11,12 @@ import java.util.Locale;
|
||||||
import org.hibernate.query.SemanticException;
|
import org.hibernate.query.SemanticException;
|
||||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
import org.hibernate.query.hql.spi.SemanticPathPart;
|
||||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
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.SqmFrom;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
|
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
|
* Specialized consumer for processing domain model paths occurring as part
|
||||||
|
@ -34,8 +38,19 @@ public class QualifiedJoinPredicatePathConsumer extends BasicDotIdentifierConsum
|
||||||
protected SemanticPathPart createBasePart() {
|
protected SemanticPathPart createBasePart() {
|
||||||
return new BaseLocalSequencePart() {
|
return new BaseLocalSequencePart() {
|
||||||
@Override
|
@Override
|
||||||
protected void validateAsRoot(SqmFrom pathRoot) {
|
protected void validateAsRoot(SqmFrom<?, ?> pathRoot) {
|
||||||
if ( pathRoot.findRoot() != sqmJoin.findRoot() ) {
|
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(
|
throw new SemanticException(
|
||||||
String.format(
|
String.format(
|
||||||
Locale.ROOT,
|
Locale.ROOT,
|
||||||
|
|
|
@ -272,8 +272,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
|
|
||||||
private final Stack<DotIdentifierConsumer> dotIdentifierConsumerStack;
|
private final Stack<DotIdentifierConsumer> dotIdentifierConsumerStack;
|
||||||
|
|
||||||
private final Stack<TreatHandler> treatHandlerStack = new StandardStack<>( new TreatHandlerNormal() );
|
|
||||||
|
|
||||||
private final Stack<ParameterDeclarationContext> parameterDeclarationContextStack = new StandardStack<>();
|
private final Stack<ParameterDeclarationContext> parameterDeclarationContextStack = new StandardStack<>();
|
||||||
private final Stack<SqmCreationProcessingState> processingStateStack = 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 final JavaType<Map<?,?>> mapJavaTypeDescriptor;
|
||||||
|
|
||||||
private ParameterCollector parameterCollector;
|
private ParameterCollector parameterCollector;
|
||||||
|
private ParameterStyle parameterStyle;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public SemanticQueryBuilder(SqmCreationOptions creationOptions, SqmCreationContext creationContext) {
|
public SemanticQueryBuilder(SqmCreationOptions creationOptions, SqmCreationContext creationContext) {
|
||||||
this.creationOptions = creationOptions;
|
this.creationOptions = creationOptions;
|
||||||
this.creationContext = creationContext;
|
this.creationContext = creationContext;
|
||||||
this.dotIdentifierConsumerStack = new StandardStack<>( new BasicDotIdentifierConsumer( this ) );
|
this.dotIdentifierConsumerStack = new StandardStack<>( new BasicDotIdentifierConsumer( this ) );
|
||||||
|
this.parameterStyle = creationOptions.useStrictJpaCompliance()
|
||||||
|
? ParameterStyle.UNKNOWN
|
||||||
|
: ParameterStyle.MIXED;
|
||||||
|
|
||||||
this.integerDomainType = creationContext
|
this.integerDomainType = creationContext
|
||||||
.getNodeBuilder()
|
.getNodeBuilder()
|
||||||
|
@ -787,13 +789,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
}
|
}
|
||||||
|
|
||||||
// visit from-clause first!!!
|
// visit from-clause first!!!
|
||||||
treatHandlerStack.push( new TreatHandlerFromClause() );
|
sqmQuerySpec.setFromClause( visitFromClause( (HqlParser.FromClauseContext) ctx.getChild( fromIndex ) ) );
|
||||||
try {
|
|
||||||
sqmQuerySpec.setFromClause( visitFromClause( (HqlParser.FromClauseContext) ctx.getChild( fromIndex ) ) );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
treatHandlerStack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
final SqmSelectClause selectClause;
|
final SqmSelectClause selectClause;
|
||||||
if ( fromIndex == 1 ) {
|
if ( fromIndex == 1 ) {
|
||||||
|
@ -817,13 +813,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
int currentIndex = fromIndex + 1;
|
int currentIndex = fromIndex + 1;
|
||||||
final SqmWhereClause whereClause = new SqmWhereClause( creationContext.getNodeBuilder() );
|
final SqmWhereClause whereClause = new SqmWhereClause( creationContext.getNodeBuilder() );
|
||||||
if ( currentIndex < ctx.getChildCount() && ctx.getChild( currentIndex ) instanceof HqlParser.WhereClauseContext ) {
|
if ( currentIndex < ctx.getChildCount() && ctx.getChild( currentIndex ) instanceof HqlParser.WhereClauseContext ) {
|
||||||
treatHandlerStack.push( new TreatHandlerNormal( DowncastLocation.WHERE ) );
|
whereClause.setPredicate( (SqmPredicate) ctx.getChild( currentIndex++ ).accept( this ) );
|
||||||
try {
|
|
||||||
whereClause.setPredicate( (SqmPredicate) ctx.getChild( currentIndex++ ).accept( this ) );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
treatHandlerStack.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sqmQuerySpec.setWhereClause( whereClause );
|
sqmQuerySpec.setWhereClause( whereClause );
|
||||||
|
|
||||||
|
@ -862,8 +852,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmSelectClause visitSelectClause(HqlParser.SelectClauseContext ctx) {
|
public SqmSelectClause visitSelectClause(HqlParser.SelectClauseContext ctx) {
|
||||||
treatHandlerStack.push( new TreatHandlerNormal( DowncastLocation.SELECT ) );
|
|
||||||
|
|
||||||
// todo (6.0) : primer a select-clause-specific SemanticPathPart into the stack
|
// todo (6.0) : primer a select-clause-specific SemanticPathPart into the stack
|
||||||
final int selectionListIndex;
|
final int selectionListIndex;
|
||||||
if ( ctx.getChild( 1 ) instanceof HqlParser.SelectionListContext ) {
|
if ( ctx.getChild( 1 ) instanceof HqlParser.SelectionListContext ) {
|
||||||
|
@ -873,24 +861,19 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
selectionListIndex = 2;
|
selectionListIndex = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
final SqmSelectClause selectClause = new SqmSelectClause(
|
||||||
final SqmSelectClause selectClause = new SqmSelectClause(
|
selectionListIndex == 2,
|
||||||
selectionListIndex == 2,
|
creationContext.getNodeBuilder()
|
||||||
creationContext.getNodeBuilder()
|
);
|
||||||
);
|
final HqlParser.SelectionListContext selectionListContext = (HqlParser.SelectionListContext) ctx.getChild(
|
||||||
final HqlParser.SelectionListContext selectionListContext = (HqlParser.SelectionListContext) ctx.getChild(
|
selectionListIndex
|
||||||
selectionListIndex
|
);
|
||||||
);
|
for ( ParseTree subCtx : selectionListContext.children ) {
|
||||||
for ( ParseTree subCtx : selectionListContext.children ) {
|
if ( subCtx instanceof HqlParser.SelectionContext ) {
|
||||||
if ( subCtx instanceof HqlParser.SelectionContext ) {
|
selectClause.addSelection( visitSelection( (HqlParser.SelectionContext) subCtx ) );
|
||||||
selectClause.addSelection( visitSelection( (HqlParser.SelectionContext) subCtx ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return selectClause;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
treatHandlerStack.pop();
|
|
||||||
}
|
}
|
||||||
|
return selectClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1409,30 +1392,23 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmFromClause visitFromClause(HqlParser.FromClauseContext parserFromClause) {
|
public SqmFromClause visitFromClause(HqlParser.FromClauseContext parserFromClause) {
|
||||||
treatHandlerStack.push( new TreatHandlerFromClause() );
|
final SqmFromClause fromClause;
|
||||||
|
if ( parserFromClause == null ) {
|
||||||
try {
|
fromClause = new SqmFromClause();
|
||||||
final SqmFromClause fromClause;
|
}
|
||||||
if ( parserFromClause == null ) {
|
else {
|
||||||
fromClause = new SqmFromClause();
|
final int size = parserFromClause.getChildCount();
|
||||||
}
|
// Shift 1 bit instead of division by 2
|
||||||
else {
|
final int estimatedSize = size >> 1;
|
||||||
final int size = parserFromClause.getChildCount();
|
fromClause = new SqmFromClause( estimatedSize );
|
||||||
// Shift 1 bit instead of division by 2
|
for ( int i = 0; i < size; i++ ) {
|
||||||
final int estimatedSize = size >> 1;
|
final ParseTree parseTree = parserFromClause.getChild( i );
|
||||||
fromClause = new SqmFromClause( estimatedSize );
|
if ( parseTree instanceof HqlParser.FromClauseSpaceContext ) {
|
||||||
for ( int i = 0; i < size; i++ ) {
|
fromClause.addRoot( visitFromClauseSpace( (HqlParser.FromClauseSpaceContext) parseTree ) );
|
||||||
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
|
@Override
|
||||||
|
@ -1679,10 +1655,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
final SqmQualifiedJoin<X, ?> join = (SqmQualifiedJoin<X, ?>) qualifiedJoinRhsContext.getChild( 0 ).accept( this );
|
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();
|
final HqlParser.QualifiedJoinPredicateContext qualifiedJoinPredicateContext = parserJoin.qualifiedJoinPredicate();
|
||||||
if ( join instanceof SqmEntityJoin<?> ) {
|
if ( join instanceof SqmEntityJoin<?> ) {
|
||||||
sqmRoot.addSqmJoin( join );
|
sqmRoot.addSqmJoin( join );
|
||||||
|
@ -3129,6 +3101,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmNamedParameter<?> visitNamedParameter(HqlParser.NamedParameterContext ctx) {
|
public SqmNamedParameter<?> visitNamedParameter(HqlParser.NamedParameterContext ctx) {
|
||||||
|
parameterStyle = parameterStyle.withNamed();
|
||||||
final SqmNamedParameter<?> param = new SqmNamedParameter<>(
|
final SqmNamedParameter<?> param = new SqmNamedParameter<>(
|
||||||
ctx.getChild( 1 ).getText(),
|
ctx.getChild( 1 ).getText(),
|
||||||
parameterDeclarationContextStack.getCurrent().isMultiValuedBindingAllowed(),
|
parameterDeclarationContextStack.getCurrent().isMultiValuedBindingAllowed(),
|
||||||
|
@ -3143,6 +3116,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
if ( ctx.getChildCount() == 1 ) {
|
if ( ctx.getChildCount() == 1 ) {
|
||||||
throw new SemanticException( "Encountered positional parameter which did not declare position (? instead of, e.g., ?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<>(
|
final SqmPositionalParameter<?> param = new SqmPositionalParameter<>(
|
||||||
Integer.parseInt( ctx.getChild( 1 ).getText() ),
|
Integer.parseInt( ctx.getChild( 1 ).getText() ),
|
||||||
parameterDeclarationContextStack.getCurrent().isMultiValuedBindingAllowed(),
|
parameterDeclarationContextStack.getCurrent().isMultiValuedBindingAllowed(),
|
||||||
|
@ -4128,15 +4102,20 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath<?> visitTreatedNavigablePath(HqlParser.TreatedNavigablePathContext ctx) {
|
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 treatTargetName = ctx.getChild( 4 ).getText();
|
||||||
final String treatTargetEntityName = getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName );
|
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(
|
dotIdentifierConsumerStack.push(
|
||||||
new BasicDotIdentifierConsumer( result, this ) {
|
new BasicDotIdentifierConsumer( result, this ) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -4155,11 +4134,6 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
||||||
private SqmTreatedPath<?, ?> resolveTreatedPath(SqmPath<?> sqmPath, EntityDomainType<?> treatTarget) {
|
|
||||||
return sqmPath.treatAs( (EntityDomainType) treatTarget );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath<?> visitCollectionElementNavigablePath(HqlParser.CollectionElementNavigablePathContext ctx) {
|
public SqmPath<?> visitCollectionElementNavigablePath(HqlParser.CollectionElementNavigablePathContext ctx) {
|
||||||
final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
|
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 SqmPath<?> sqmPath = consumeDomainPath( parserPath );
|
||||||
|
|
||||||
final SqmPathSource<?> pathSource = sqmPath.getReferencedPathSource();
|
final SqmPathSource<?> pathSource = sqmPath.getReferencedPathSource();
|
||||||
|
if ( pathSource.getSqmPathType() instanceof ManagedDomainType<?> ) {
|
||||||
try {
|
|
||||||
// use the `#sqmAs` call to validate the path is a ManagedType
|
|
||||||
pathSource.sqmAs( ManagedDomainType.class );
|
|
||||||
return sqmPath;
|
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) {
|
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() );
|
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) {
|
private void checkFQNEntityNameJpaComplianceViolationIfNeeded(String name, EntityDomainType<?> entityDescriptor) {
|
||||||
if ( getCreationOptions().useStrictJpaCompliance() && ! name.equals( entityDescriptor.getName() ) ) {
|
if ( getCreationOptions().useStrictJpaCompliance() && ! name.equals( entityDescriptor.getName() ) ) {
|
||||||
// FQN is the only possible reason
|
// 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,15 @@ public interface DotIdentifierConsumer {
|
||||||
*/
|
*/
|
||||||
void consumeIdentifier(String identifier, boolean isBase, boolean isTerminal);
|
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
|
* 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
|
* has been processed at which point this will return the final outcome of the
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan> creator) {
|
public <R> SelectQueryPlan<R> resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan<R>> creator) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,17 +76,18 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SelectQueryPlan resolveSelectQueryPlan(
|
public <R> SelectQueryPlan<R> resolveSelectQueryPlan(
|
||||||
Key key,
|
Key key,
|
||||||
Supplier<SelectQueryPlan> creator) {
|
Supplier<SelectQueryPlan<R>> creator) {
|
||||||
log.tracef( "QueryPlan#getSelectQueryPlan(%s)", key );
|
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 ) {
|
if ( cached != null ) {
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
final SelectQueryPlan plan = creator.get();
|
final SelectQueryPlan<R> plan = creator.get();
|
||||||
queryPlanCache.put( key.prepareForStore(), plan );
|
queryPlanCache.put( key.prepareForStore(), plan );
|
||||||
return plan;
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,8 +240,8 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
||||||
final TypeConfiguration typeConfiguration = session.getFactory().getTypeConfiguration();
|
final TypeConfiguration typeConfiguration = session.getFactory().getTypeConfiguration();
|
||||||
|
|
||||||
if ( binding.getBindType() instanceof JavaTypedExpressable ) {
|
if ( binding.getBindType() instanceof JavaTypedExpressable ) {
|
||||||
final JavaTypedExpressable javaTypedExpressable = (JavaTypedExpressable) binding.getBindType();
|
final JavaTypedExpressable<?> javaTypedExpressable = (JavaTypedExpressable<?>) binding.getBindType();
|
||||||
final JavaType jtd = javaTypedExpressable.getExpressableJavaTypeDescriptor();
|
final JavaType<?> jtd = javaTypedExpressable.getExpressableJavaTypeDescriptor();
|
||||||
if ( jtd.getJavaTypeClass() != null ) {
|
if ( jtd.getJavaTypeClass() != null ) {
|
||||||
// avoid dynamic models
|
// avoid dynamic models
|
||||||
return typeConfiguration.getBasicTypeForJavaType( jtd.getJavaTypeClass() );
|
return typeConfiguration.getBasicTypeForJavaType( jtd.getJavaTypeClass() );
|
||||||
|
|
|
@ -131,7 +131,7 @@ public class TableGroupImpl implements TableGroup {
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
String tableExpression,
|
String tableExpression,
|
||||||
boolean allowFkOptimization) {
|
boolean allowFkOptimization) {
|
||||||
final TableReference tableReference = getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
final TableReference tableReference = getTableReference( navigablePath, tableExpression, allowFkOptimization, true );
|
||||||
if ( tableReference == null ) {
|
if ( tableReference == null ) {
|
||||||
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
|
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
|
||||||
}
|
}
|
||||||
|
@ -143,14 +143,15 @@ public class TableGroupImpl implements TableGroup {
|
||||||
public TableReference getTableReference(
|
public TableReference getTableReference(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
String tableExpression,
|
String tableExpression,
|
||||||
boolean allowFkOptimization) {
|
boolean allowFkOptimization,
|
||||||
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, allowFkOptimization ) != null ) {
|
boolean resolve) {
|
||||||
|
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||||
return primaryTableReference;
|
return primaryTableReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
|
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||||
return primaryTableReference;
|
return primaryTableReference;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, Basi
|
||||||
final String mappedColumn = referencedModelPart.getSelectionExpression();
|
final String mappedColumn = referencedModelPart.getSelectionExpression();
|
||||||
|
|
||||||
final TableGroup tableGroup = creationState.getFromClauseAccess().getTableGroup( parent.getNavigablePath() );
|
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 String selectedAlias;
|
||||||
final int jdbcPosition;
|
final int jdbcPosition;
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class CompleteFetchBuilderEntityValuedModelPart
|
||||||
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
|
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
|
||||||
modelPart.forEachSelectable(
|
modelPart.forEachSelectable(
|
||||||
(selectionIndex, selectableMapping) -> {
|
(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 mappedColumn = selectableMapping.getSelectionExpression();
|
||||||
final String columnAlias = columnAliases.get( selectionIndex );
|
final String columnAlias = columnAliases.get( selectionIndex );
|
||||||
creationStateImpl.resolveSqlSelection(
|
creationStateImpl.resolveSqlSelection(
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class CompleteResultBuilderBasicModelPart
|
||||||
final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState );
|
final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState );
|
||||||
|
|
||||||
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
|
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 String mappedColumn = modelPart.getSelectionExpression();
|
||||||
|
|
||||||
final SqlSelection sqlSelection = creationStateImpl.resolveSqlSelection(
|
final SqlSelection sqlSelection = creationStateImpl.resolveSqlSelection(
|
||||||
|
|
|
@ -146,7 +146,7 @@ public class CompleteResultBuilderCollectionStandard implements CompleteResultBu
|
||||||
creationStateImpl.resolveSqlSelection(
|
creationStateImpl.resolveSqlSelection(
|
||||||
creationStateImpl.resolveSqlExpression(
|
creationStateImpl.resolveSqlExpression(
|
||||||
SqlExpressionResolver.createColumnReferenceKey(
|
SqlExpressionResolver.createColumnReferenceKey(
|
||||||
tableGroup.getTableReference( selectableMapping.getContainingTableExpression() ),
|
tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() ),
|
||||||
selectableMapping.getSelectionExpression()
|
selectableMapping.getSelectionExpression()
|
||||||
),
|
),
|
||||||
processingState -> {
|
processingState -> {
|
||||||
|
|
|
@ -58,7 +58,6 @@ public class DelayedFetchBuilderBasicPart
|
||||||
parent,
|
parent,
|
||||||
fetchPath,
|
fetchPath,
|
||||||
referencedModelPart,
|
referencedModelPart,
|
||||||
true,
|
|
||||||
null,
|
null,
|
||||||
FetchTiming.DELAYED,
|
FetchTiming.DELAYED,
|
||||||
isEnhancedForLazyLoading,
|
isEnhancedForLazyLoading,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.internal.util.MutableObject;
|
import org.hibernate.internal.util.MutableObject;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||||
|
@ -19,7 +20,6 @@ import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.results.ResultsHelper;
|
import org.hibernate.query.results.ResultsHelper;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
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.DomainResultAssembler;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.Fetch;
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
|
@ -37,7 +37,7 @@ public class EntityResultImpl implements EntityResult {
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
private final EntityValuedModelPart entityValuedModelPart;
|
private final EntityValuedModelPart entityValuedModelPart;
|
||||||
|
|
||||||
private final DomainResult<?> identifierResult;
|
private final Fetch identifierFetch;
|
||||||
private final BasicFetch<?> discriminatorFetch;
|
private final BasicFetch<?> discriminatorFetch;
|
||||||
private final List<Fetch> fetches;
|
private final List<Fetch> fetches;
|
||||||
|
|
||||||
|
@ -102,17 +102,20 @@ public class EntityResultImpl implements EntityResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( idFetchRef.isNotSet() ) {
|
if ( idFetchRef.isNotSet() ) {
|
||||||
identifierResult = ResultsHelper.implicitIdentifierResult(
|
identifierFetch = ( (Fetchable) identifierMapping ).generateFetch(
|
||||||
identifierMapping,
|
this,
|
||||||
new EntityIdentifierNavigablePath(
|
new EntityIdentifierNavigablePath(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
ResultsHelper.attributeName( identifierMapping )
|
ResultsHelper.attributeName( identifierMapping )
|
||||||
),
|
),
|
||||||
|
FetchTiming.IMMEDIATE,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.identifierResult = idFetchRef.get().asResult( creationState );
|
this.identifierFetch = idFetchRef.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +164,7 @@ public class EntityResultImpl implements EntityResult {
|
||||||
this,
|
this,
|
||||||
getNavigablePath(),
|
getNavigablePath(),
|
||||||
lockMode,
|
lockMode,
|
||||||
identifierResult,
|
identifierFetch,
|
||||||
discriminatorFetch,
|
discriminatorFetch,
|
||||||
null,
|
null,
|
||||||
creationState
|
creationState
|
||||||
|
|
|
@ -148,7 +148,7 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
|
||||||
resolveSqlSelection(
|
resolveSqlSelection(
|
||||||
columnNames.get( selectionIndex ),
|
columnNames.get( selectionIndex ),
|
||||||
createColumnReferenceKey(
|
createColumnReferenceKey(
|
||||||
tableGroup.getTableReference( selectableMapping.getContainingTableExpression() ),
|
tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() ),
|
||||||
selectableMapping.getSelectionExpression()
|
selectableMapping.getSelectionExpression()
|
||||||
),
|
),
|
||||||
selectableMapping.getJdbcMapping(),
|
selectableMapping.getJdbcMapping(),
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class DynamicFetchBuilderStandard
|
||||||
final SqlExpressionResolver sqlExpressionResolver = domainResultCreationState.getSqlAstCreationState().getSqlExpressionResolver();
|
final SqlExpressionResolver sqlExpressionResolver = domainResultCreationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||||
|
|
||||||
final SelectableConsumer selectableConsumer = (selectionIndex, selectableMapping) -> {
|
final SelectableConsumer selectableConsumer = (selectionIndex, selectableMapping) -> {
|
||||||
final TableReference tableReference = ownerTableGroup.getTableReference(
|
final TableReference tableReference = ownerTableGroup.resolveTableReference(
|
||||||
fetchPath,
|
fetchPath,
|
||||||
selectableMapping.getContainingTableExpression()
|
selectableMapping.getContainingTableExpression()
|
||||||
);
|
);
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicVal
|
||||||
|
|
||||||
final Expression expression = creationStateImpl.resolveSqlExpression(
|
final Expression expression = creationStateImpl.resolveSqlExpression(
|
||||||
createColumnReferenceKey(
|
createColumnReferenceKey(
|
||||||
parentTableGroup.getTableReference( fetchPath, table ),
|
parentTableGroup.resolveTableReference( fetchPath, table ),
|
||||||
fetchable.getSelectionExpression()
|
fetchable.getSelectionExpression()
|
||||||
),
|
),
|
||||||
processingState -> {
|
processingState -> {
|
||||||
|
@ -99,8 +99,6 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicVal
|
||||||
parent,
|
parent,
|
||||||
fetchPath,
|
fetchPath,
|
||||||
fetchable,
|
fetchable,
|
||||||
// todo (6.0) - we don't know
|
|
||||||
true,
|
|
||||||
valueConverter,
|
valueConverter,
|
||||||
FetchTiming.IMMEDIATE,
|
FetchTiming.IMMEDIATE,
|
||||||
domainResultCreationState
|
domainResultCreationState
|
||||||
|
|
|
@ -101,7 +101,7 @@ import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public abstract class AbstractQuery<R> implements QueryImplementor<R> {
|
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;
|
private final SharedSessionContractImplementor session;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ public interface QueryInterpretationCache {
|
||||||
|
|
||||||
HqlInterpretation resolveHqlInterpretation(String queryString, Function<String, SqmStatement<?>> creator);
|
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);
|
NonSelectQueryPlan getNonSelectQueryPlan(Key key);
|
||||||
void cacheNonSelectQueryPlan(Key key, NonSelectQueryPlan plan);
|
void cacheNonSelectQueryPlan(Key key, NonSelectQueryPlan plan);
|
||||||
|
|
|
@ -13,18 +13,12 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
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.DomainQueryExecutionContext;
|
||||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
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.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
|
||||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
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.internal.StandardJdbcMutationExecutor;
|
||||||
import org.hibernate.sql.exec.spi.JdbcMutation;
|
import org.hibernate.sql.exec.spi.JdbcMutation;
|
||||||
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
|
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
|
||||||
|
@ -39,12 +33,12 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
|
||||||
private final String sql;
|
private final String sql;
|
||||||
private final Set<String> affectedTableNames;
|
private final Set<String> affectedTableNames;
|
||||||
|
|
||||||
private final List<QueryParameterImplementor<?>> parameterList;
|
private final List<ParameterOccurrence> parameterList;
|
||||||
|
|
||||||
public NativeNonSelectQueryPlanImpl(
|
public NativeNonSelectQueryPlanImpl(
|
||||||
String sql,
|
String sql,
|
||||||
Set<String> affectedTableNames,
|
Set<String> affectedTableNames,
|
||||||
List<QueryParameterImplementor<?>> parameterList) {
|
List<ParameterOccurrence> parameterList) {
|
||||||
this.sql = sql;
|
this.sql = sql;
|
||||||
this.affectedTableNames = affectedTableNames;
|
this.affectedTableNames = affectedTableNames;
|
||||||
this.parameterList = parameterList;
|
this.parameterList = parameterList;
|
||||||
|
@ -66,26 +60,12 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
|
||||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
||||||
|
|
||||||
for ( QueryParameterImplementor<?> param : parameterList ) {
|
jdbcParameterBindings.registerNativeQueryParameters(
|
||||||
QueryParameterBinding<?> binding = queryParameterBindings.getBinding( param );
|
queryParameterBindings,
|
||||||
AllowableParameterType<?> type = binding.getBindType();
|
parameterList,
|
||||||
if ( type == null ) {
|
jdbcParameterBinders,
|
||||||
type = param.getHibernateType();
|
executionContext.getSession().getFactory()
|
||||||
}
|
);
|
||||||
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() )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final JdbcMutation jdbcMutation = new NativeJdbcMutation(
|
final JdbcMutation jdbcMutation = new NativeJdbcMutation(
|
||||||
|
|
|
@ -11,11 +11,13 @@ import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -30,6 +32,8 @@ import org.hibernate.LockOptions;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.ScrollMode;
|
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.query.spi.NativeQueryInterpreter;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
@ -37,6 +41,7 @@ import org.hibernate.graph.GraphSemantic;
|
||||||
import org.hibernate.graph.RootGraph;
|
import org.hibernate.graph.RootGraph;
|
||||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||||
import org.hibernate.internal.AbstractSharedSessionContract;
|
import org.hibernate.internal.AbstractSharedSessionContract;
|
||||||
|
import org.hibernate.internal.util.MathHelper;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
|
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.ParameterMetadataImplementor;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
import org.hibernate.query.spi.QueryInterpretationCache;
|
import org.hibernate.query.spi.QueryInterpretationCache;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
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.NativeSelectQueryPlan;
|
||||||
import org.hibernate.query.sql.spi.NonSelectInterpretationsKey;
|
import org.hibernate.query.sql.spi.NonSelectInterpretationsKey;
|
||||||
import org.hibernate.query.sql.spi.ParameterInterpretation;
|
import org.hibernate.query.sql.spi.ParameterInterpretation;
|
||||||
|
import org.hibernate.query.sql.spi.ParameterOccurrence;
|
||||||
import org.hibernate.query.sql.spi.SelectInterpretationsKey;
|
import org.hibernate.query.sql.spi.SelectInterpretationsKey;
|
||||||
import org.hibernate.sql.exec.internal.CallbackImpl;
|
import org.hibernate.sql.exec.internal.CallbackImpl;
|
||||||
import org.hibernate.sql.exec.spi.Callback;
|
import org.hibernate.sql.exec.spi.Callback;
|
||||||
|
@ -110,7 +117,7 @@ public class NativeQueryImpl<R>
|
||||||
private final String sqlString;
|
private final String sqlString;
|
||||||
|
|
||||||
private final ParameterMetadataImplementor parameterMetadata;
|
private final ParameterMetadataImplementor parameterMetadata;
|
||||||
private final List<QueryParameterImplementor<?>> occurrenceOrderedParamList;
|
private final List<ParameterOccurrence> parameterOccurrences;
|
||||||
private final QueryParameterBindings parameterBindings;
|
private final QueryParameterBindings parameterBindings;
|
||||||
|
|
||||||
private final ResultSetMappingImpl resultSetMapping;
|
private final ResultSetMappingImpl resultSetMapping;
|
||||||
|
@ -190,7 +197,7 @@ public class NativeQueryImpl<R>
|
||||||
|
|
||||||
this.sqlString = parameterInterpretation.getAdjustedSqlString();
|
this.sqlString = parameterInterpretation.getAdjustedSqlString();
|
||||||
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
|
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
|
||||||
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
|
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
|
||||||
this.parameterBindings = QueryParameterBindingsImpl.from(
|
this.parameterBindings = QueryParameterBindingsImpl.from(
|
||||||
parameterMetadata,
|
parameterMetadata,
|
||||||
session.getFactory(),
|
session.getFactory(),
|
||||||
|
@ -327,7 +334,7 @@ public class NativeQueryImpl<R>
|
||||||
|
|
||||||
this.sqlString = parameterInterpretation.getAdjustedSqlString();
|
this.sqlString = parameterInterpretation.getAdjustedSqlString();
|
||||||
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
|
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
|
||||||
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
|
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
|
||||||
this.parameterBindings = QueryParameterBindingsImpl.from(
|
this.parameterBindings = QueryParameterBindingsImpl.from(
|
||||||
parameterMetadata,
|
parameterMetadata,
|
||||||
session.getFactory(),
|
session.getFactory(),
|
||||||
|
@ -386,7 +393,7 @@ public class NativeQueryImpl<R>
|
||||||
|
|
||||||
this.sqlString = parameterInterpretation.getAdjustedSqlString();
|
this.sqlString = parameterInterpretation.getAdjustedSqlString();
|
||||||
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
|
this.parameterMetadata = parameterInterpretation.toParameterMetadata( session );
|
||||||
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
|
this.parameterOccurrences = parameterInterpretation.getOrderedParameterOccurrences();
|
||||||
this.parameterBindings = QueryParameterBindingsImpl.from(
|
this.parameterBindings = QueryParameterBindingsImpl.from(
|
||||||
parameterMetadata,
|
parameterMetadata,
|
||||||
session.getFactory(),
|
session.getFactory(),
|
||||||
|
@ -571,11 +578,9 @@ public class NativeQueryImpl<R>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<R> doList() {
|
protected List<R> doList() {
|
||||||
//noinspection unchecked
|
|
||||||
return resolveSelectQueryPlan().performList( this );
|
return resolveSelectQueryPlan().performList( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
||||||
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
|
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
|
||||||
if ( cacheKey != null ) {
|
if ( cacheKey != null ) {
|
||||||
|
@ -590,10 +595,11 @@ public class NativeQueryImpl<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
private NativeSelectQueryPlan<R> createQueryPlan(ResultSetMapping resultSetMapping) {
|
private NativeSelectQueryPlan<R> createQueryPlan(ResultSetMapping resultSetMapping) {
|
||||||
final NativeSelectQueryDefinition queryDefinition = new NativeSelectQueryDefinition() {
|
final String sqlString = expandParameterLists();
|
||||||
|
final NativeSelectQueryDefinition<R> queryDefinition = new NativeSelectQueryDefinition<R>() {
|
||||||
@Override
|
@Override
|
||||||
public String getSqlString() {
|
public String getSqlString() {
|
||||||
return NativeQueryImpl.this.getQueryString();
|
return sqlString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -602,8 +608,8 @@ public class NativeQueryImpl<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<QueryParameterImplementor<?>> getQueryParameterList() {
|
public List<ParameterOccurrence> getQueryParameterOccurrences() {
|
||||||
return NativeQueryImpl.this.occurrenceOrderedParamList;
|
return NativeQueryImpl.this.parameterOccurrences;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -622,6 +628,142 @@ public class NativeQueryImpl<R>
|
||||||
.createQueryPlan( queryDefinition, getSessionFactory() );
|
.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) {
|
private SelectInterpretationsKey generateSelectInterpretationsKey(JdbcValuesMappingProducer resultSetMapping) {
|
||||||
if ( !isCacheable( this ) ) {
|
if ( !isCacheable( this ) ) {
|
||||||
return null;
|
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
|
// 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.
|
// 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
|
// 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 false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return true;
|
// For now, don't cache plans that have parameter lists
|
||||||
|
return !query.parameterBindings.hasAnyMultiValuedBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasLimit(Limit limit) {
|
private static boolean hasLimit(Limit limit) {
|
||||||
|
@ -669,7 +811,8 @@ public class NativeQueryImpl<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( queryPlan == null ) {
|
if ( queryPlan == null ) {
|
||||||
queryPlan = new NativeNonSelectQueryPlanImpl( sqlString, querySpaces, occurrenceOrderedParamList );
|
final String sqlString = expandParameterLists();
|
||||||
|
queryPlan = new NativeNonSelectQueryPlanImpl( sqlString, querySpaces, parameterOccurrences );
|
||||||
if ( cacheKey != null ) {
|
if ( cacheKey != null ) {
|
||||||
getSession().getFactory().getQueryEngine().getInterpretationCache().cacheNonSelectQueryPlan( cacheKey, queryPlan );
|
getSession().getFactory().getQueryEngine().getInterpretationCache().cacheNonSelectQueryPlan( cacheKey, queryPlan );
|
||||||
}
|
}
|
||||||
|
@ -680,6 +823,10 @@ public class NativeQueryImpl<R>
|
||||||
|
|
||||||
|
|
||||||
protected NonSelectInterpretationsKey generateNonSelectInterpretationsKey() {
|
protected NonSelectInterpretationsKey generateNonSelectInterpretationsKey() {
|
||||||
|
if ( !isCacheable( this ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// todo (6.0) - should this account for query-spaces in determining "cacheable"?
|
// todo (6.0) - should this account for query-spaces in determining "cacheable"?
|
||||||
return new NonSelectInterpretationsKey(
|
return new NonSelectInterpretationsKey(
|
||||||
getQueryString(),
|
getQueryString(),
|
||||||
|
@ -1412,7 +1559,7 @@ public class NativeQueryImpl<R>
|
||||||
|
|
||||||
private static class ParameterInterpretationImpl implements ParameterInterpretation {
|
private static class ParameterInterpretationImpl implements ParameterInterpretation {
|
||||||
private final String sqlString;
|
private final String sqlString;
|
||||||
private final List<QueryParameterImplementor<?>> parameterList;
|
private final List<ParameterOccurrence> parameterList;
|
||||||
private final Map<Integer, QueryParameterImplementor<?>> positionalParameters;
|
private final Map<Integer, QueryParameterImplementor<?>> positionalParameters;
|
||||||
private final Map<String, QueryParameterImplementor<?>> namedParameters;
|
private final Map<String, QueryParameterImplementor<?>> namedParameters;
|
||||||
|
|
||||||
|
@ -1424,7 +1571,7 @@ public class NativeQueryImpl<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<QueryParameterImplementor<?>> getOccurrenceOrderedParameters() {
|
public List<ParameterOccurrence> getOrderedParameterOccurrences() {
|
||||||
return parameterList;
|
return parameterList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,20 +15,14 @@ import java.util.Set;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.EmptyScrollableResults;
|
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.results.ResultSetMapping;
|
||||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
|
||||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||||
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
|
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
|
||||||
|
import org.hibernate.query.sql.spi.ParameterOccurrence;
|
||||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
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.JdbcParameterBindingsImpl;
|
||||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
|
||||||
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
|
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||||
|
@ -44,14 +38,14 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
private final String sql;
|
private final String sql;
|
||||||
private final Set<String> affectedTableNames;
|
private final Set<String> affectedTableNames;
|
||||||
|
|
||||||
private final List<QueryParameterImplementor<?>> parameterList;
|
private final List<ParameterOccurrence> parameterList;
|
||||||
|
|
||||||
private final JdbcValuesMappingProducer resultSetMapping;
|
private final JdbcValuesMappingProducer resultSetMapping;
|
||||||
|
|
||||||
public NativeSelectQueryPlanImpl(
|
public NativeSelectQueryPlanImpl(
|
||||||
String sql,
|
String sql,
|
||||||
Set<String> affectedTableNames,
|
Set<String> affectedTableNames,
|
||||||
List<QueryParameterImplementor<?>> parameterList,
|
List<ParameterOccurrence> parameterList,
|
||||||
ResultSetMapping resultSetMapping,
|
ResultSetMapping resultSetMapping,
|
||||||
SessionFactoryImplementor sessionFactory) {
|
SessionFactoryImplementor sessionFactory) {
|
||||||
final ResultSetMappingProcessor processor = new ResultSetMappingProcessor( resultSetMapping, sessionFactory );
|
final ResultSetMappingProcessor processor = new ResultSetMappingProcessor( resultSetMapping, sessionFactory );
|
||||||
|
@ -85,26 +79,12 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
||||||
|
|
||||||
for ( QueryParameterImplementor<?> param : parameterList ) {
|
jdbcParameterBindings.registerNativeQueryParameters(
|
||||||
QueryParameterBinding<?> binding = queryParameterBindings.getBinding( param );
|
queryParameterBindings,
|
||||||
AllowableParameterType<?> type = binding.getBindType();
|
parameterList,
|
||||||
if ( type == null ) {
|
jdbcParameterBinders,
|
||||||
type = param.getHibernateType();
|
executionContext.getSession().getFactory()
|
||||||
}
|
);
|
||||||
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() )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
executionContext.getSession().autoFlushIfRequired( affectedTableNames );
|
executionContext.getSession().autoFlushIfRequired( affectedTableNames );
|
||||||
|
@ -150,26 +130,11 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
||||||
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
jdbcParameterBinders = new ArrayList<>( parameterList.size() );
|
||||||
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
jdbcParameterBindings = new JdbcParameterBindingsImpl( parameterList.size() );
|
||||||
|
|
||||||
queryParameterBindings.visitBindings(
|
jdbcParameterBindings.registerNativeQueryParameters(
|
||||||
(param, binding) -> {
|
queryParameterBindings,
|
||||||
AllowableParameterType<?> type = binding.getBindType();
|
parameterList,
|
||||||
if ( type == null ) {
|
jdbcParameterBinders,
|
||||||
type = param.getHibernateType();
|
executionContext.getSession().getFactory()
|
||||||
}
|
|
||||||
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() )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.query.QueryParameter;
|
||||||
import org.hibernate.query.internal.QueryParameterNamedImpl;
|
import org.hibernate.query.internal.QueryParameterNamedImpl;
|
||||||
import org.hibernate.query.internal.QueryParameterPositionalImpl;
|
import org.hibernate.query.internal.QueryParameterPositionalImpl;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
|
import org.hibernate.query.sql.spi.ParameterOccurrence;
|
||||||
import org.hibernate.query.sql.spi.ParameterRecognizer;
|
import org.hibernate.query.sql.spi.ParameterRecognizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,8 +38,8 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
|
||||||
|
|
||||||
private int ordinalParameterImplicitPosition;
|
private int ordinalParameterImplicitPosition;
|
||||||
|
|
||||||
private List<QueryParameterImplementor<?>> parameterList;
|
private List<ParameterOccurrence> parameterList;
|
||||||
private StringBuilder sqlStringBuffer = new StringBuilder();
|
private final StringBuilder sqlStringBuffer = new StringBuilder();
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public ParameterRecognizerImpl(SessionFactoryImplementor factory) {
|
public ParameterRecognizerImpl(SessionFactoryImplementor factory) {
|
||||||
|
@ -77,7 +78,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
|
||||||
return positionalQueryParameters;
|
return positionalQueryParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<QueryParameterImplementor<?>> getParameterList() {
|
public List<ParameterOccurrence> getParameterList() {
|
||||||
return parameterList;
|
return parameterList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +118,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
|
||||||
parameterList = new ArrayList<>();
|
parameterList = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterList.add( parameter );
|
parameterList.add( new ParameterOccurrence( parameter, sqlStringBuffer.length() ) );
|
||||||
sqlStringBuffer.append( "?" );
|
sqlStringBuffer.append( "?" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
|
||||||
parameterList = new ArrayList<>();
|
parameterList = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterList.add( parameter );
|
parameterList.add( new ParameterOccurrence( parameter, sqlStringBuffer.length() ) );
|
||||||
sqlStringBuffer.append( "?" );
|
sqlStringBuffer.append( "?" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ public class ParameterRecognizerImpl implements ParameterRecognizer {
|
||||||
parameterList = new ArrayList<>();
|
parameterList = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterList.add( parameter );
|
parameterList.add( new ParameterOccurrence( parameter, sqlStringBuffer.length() ) );
|
||||||
sqlStringBuffer.append( "?" );
|
sqlStringBuffer.append( "?" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,9 +165,6 @@ public class SQLQueryParser {
|
||||||
result.append( '{' ).append( aliasPath ).append( '}' );
|
result.append( '{' ).append( aliasPath ).append( '}' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Possibly handle :something parameters for the query ?
|
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ public interface NativeSelectQueryDefinition<R> {
|
||||||
* @apiNote This returns query parameters in the order they were
|
* @apiNote This returns query parameters in the order they were
|
||||||
* encountered - potentially including "duplicate references" to a single parameter
|
* encountered - potentially including "duplicate references" to a single parameter
|
||||||
*/
|
*/
|
||||||
List<QueryParameterImplementor<?>> getQueryParameterList();
|
List<ParameterOccurrence> getQueryParameterOccurrences();
|
||||||
|
|
||||||
ResultSetMapping getResultSetMapping();
|
ResultSetMapping getResultSetMapping();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ public interface ParameterInterpretation {
|
||||||
* Access to the defined parameters in the order they were encountered,
|
* Access to the defined parameters in the order they were encountered,
|
||||||
* potentially including "duplicate references" to a single parameter
|
* potentially including "duplicate references" to a single parameter
|
||||||
*/
|
*/
|
||||||
List<QueryParameterImplementor<?>> getOccurrenceOrderedParameters();
|
List<ParameterOccurrence> getOrderedParameterOccurrences();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the ParameterMetadata representation of this interpretation
|
* Create the ParameterMetadata representation of this interpretation
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,11 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.sqm;
|
package org.hibernate.query.sqm;
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import jakarta.persistence.metamodel.Bindable;
|
import jakarta.persistence.metamodel.Bindable;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.DomainType;
|
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.SqmExpressableAccessor;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
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() {
|
default SqmExpressable<J> getExpressable() {
|
||||||
return (SqmExpressable<J>) getSqmPathType();
|
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()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" ),
|
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" ),
|
FQN_ENTITY_NAME( "use of FQN for entity name" ),
|
||||||
IMPLICIT_TREAT( "use of implicit treat" ),
|
IMPLICIT_TREAT( "use of implicit treat" ),
|
||||||
|
MIXED_POSITIONAL_NAMED_PARAMETERS( "mix of positional and named parameters" ),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|
|
@ -47,16 +47,16 @@ public class DomainParameterXref {
|
||||||
final Map<SqmParameter,QueryParameterImplementor<?>> xrefMap = new TreeMap<>(
|
final Map<SqmParameter,QueryParameterImplementor<?>> xrefMap = new TreeMap<>(
|
||||||
(o1, o2) -> {
|
(o1, o2) -> {
|
||||||
if ( o1 instanceof SqmNamedParameter ) {
|
if ( o1 instanceof SqmNamedParameter ) {
|
||||||
final SqmNamedParameter one = (SqmNamedParameter) o1;
|
final SqmNamedParameter<?> one = (SqmNamedParameter<?>) o1;
|
||||||
final SqmNamedParameter another = (SqmNamedParameter) o2;
|
return o2 instanceof SqmNamedParameter<?>
|
||||||
|
? one.getName().compareTo( ((SqmNamedParameter<?>) o2).getName() )
|
||||||
return one.getName().compareTo( another.getName() );
|
: -1;
|
||||||
}
|
}
|
||||||
else if ( o1 instanceof SqmPositionalParameter ) {
|
else if ( o1 instanceof SqmPositionalParameter ) {
|
||||||
final SqmPositionalParameter one = (SqmPositionalParameter) o1;
|
final SqmPositionalParameter<?> one = (SqmPositionalParameter<?>) o1;
|
||||||
final SqmPositionalParameter another = (SqmPositionalParameter) o2;
|
return o2 instanceof SqmPositionalParameter<?>
|
||||||
|
? one.getPosition().compareTo( ( (SqmPositionalParameter<?>) o2 ).getPosition() )
|
||||||
return one.getPosition().compareTo( another.getPosition() );
|
: 1;
|
||||||
}
|
}
|
||||||
else if ( o1 instanceof SqmJpaCriteriaParameterWrapper
|
else if ( o1 instanceof SqmJpaCriteriaParameterWrapper
|
||||||
&& o2 instanceof SqmJpaCriteriaParameterWrapper ) {
|
&& o2 instanceof SqmJpaCriteriaParameterWrapper ) {
|
||||||
|
@ -101,7 +101,7 @@ public class DomainParameterXref {
|
||||||
sqmParameter,
|
sqmParameter,
|
||||||
p -> {
|
p -> {
|
||||||
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper ) {
|
if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper ) {
|
||||||
return ( (SqmJpaCriteriaParameterWrapper) sqmParameter ).getJpaCriteriaParameter();
|
return ( (SqmJpaCriteriaParameterWrapper<?>) sqmParameter ).getJpaCriteriaParameter();
|
||||||
}
|
}
|
||||||
else if ( sqmParameter.getName() != null ) {
|
else if ( sqmParameter.getName() != null ) {
|
||||||
return QueryParameterNamedImpl.fromSqm( sqmParameter );
|
return QueryParameterNamedImpl.fromSqm( sqmParameter );
|
||||||
|
|
|
@ -670,7 +670,6 @@ public class QuerySqmImpl<R>
|
||||||
return lockMode != null && lockMode.greaterThan( LockMode.READ );
|
return lockMode != null && lockMode.greaterThan( LockMode.READ );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
||||||
// resolve (or make) the QueryPlan. This QueryPlan might be an aggregation of multiple plans.
|
// resolve (or make) the QueryPlan. This QueryPlan might be an aggregation of multiple plans.
|
||||||
//
|
//
|
||||||
|
|
|
@ -201,7 +201,7 @@ public class MatchingIdSelectionHelper {
|
||||||
|
|
||||||
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(
|
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(
|
||||||
entityDescriptor,
|
entityDescriptor,
|
||||||
sqmMutationStatement.getTarget().getExplicitAlias(),
|
sqmMutationStatement.getTarget(),
|
||||||
domainParameterXref,
|
domainParameterXref,
|
||||||
executionContext.getQueryOptions(),
|
executionContext.getQueryOptions(),
|
||||||
executionContext.getSession().getLoadQueryInfluencers(),
|
executionContext.getSession().getLoadQueryInfluencers(),
|
||||||
|
|
|
@ -14,7 +14,6 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.internal.util.collections.Stack;
|
import org.hibernate.internal.util.collections.Stack;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
import org.hibernate.query.NavigablePath;
|
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
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.SqlAstProcessingStateImpl;
|
||||||
import org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl;
|
import org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
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.predicate.SqmWhereClause;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
|
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
|
||||||
import org.hibernate.query.sqm.tree.update.SqmAssignment;
|
import org.hibernate.query.sqm.tree.update.SqmAssignment;
|
||||||
|
@ -63,7 +63,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
|
||||||
|
|
||||||
public MultiTableSqmMutationConverter(
|
public MultiTableSqmMutationConverter(
|
||||||
EntityMappingType mutatingEntityDescriptor,
|
EntityMappingType mutatingEntityDescriptor,
|
||||||
String mutatingEntityExplicitAlias,
|
SqmRoot<?> sqmRoot,
|
||||||
DomainParameterXref domainParameterXref,
|
DomainParameterXref domainParameterXref,
|
||||||
QueryOptions queryOptions,
|
QueryOptions queryOptions,
|
||||||
LoadQueryInfluencers loadQueryInfluencers,
|
LoadQueryInfluencers loadQueryInfluencers,
|
||||||
|
@ -71,8 +71,8 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
this(
|
this(
|
||||||
mutatingEntityDescriptor,
|
mutatingEntityDescriptor,
|
||||||
mutatingEntityExplicitAlias,
|
sqmRoot,
|
||||||
mutatingEntityExplicitAlias,
|
sqmRoot.getExplicitAlias(),
|
||||||
domainParameterXref,
|
domainParameterXref,
|
||||||
queryOptions,
|
queryOptions,
|
||||||
loadQueryInfluencers,
|
loadQueryInfluencers,
|
||||||
|
@ -83,7 +83,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
|
||||||
|
|
||||||
public MultiTableSqmMutationConverter(
|
public MultiTableSqmMutationConverter(
|
||||||
EntityMappingType mutatingEntityDescriptor,
|
EntityMappingType mutatingEntityDescriptor,
|
||||||
String mutatingEntityExplicitAlias,
|
SqmRoot<?> sqmRoot,
|
||||||
String sourceAlias,
|
String sourceAlias,
|
||||||
DomainParameterXref domainParameterXref,
|
DomainParameterXref domainParameterXref,
|
||||||
QueryOptions queryOptions,
|
QueryOptions queryOptions,
|
||||||
|
@ -101,10 +101,9 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
|
||||||
|
|
||||||
pushProcessingState( rootProcessingState );
|
pushProcessingState( rootProcessingState );
|
||||||
|
|
||||||
final NavigablePath navigablePath = new NavigablePath( mutatingEntityDescriptor.getEntityName(), mutatingEntityExplicitAlias );
|
|
||||||
this.mutatingTableGroup = mutatingEntityDescriptor.createRootTableGroup(
|
this.mutatingTableGroup = mutatingEntityDescriptor.createRootTableGroup(
|
||||||
true,
|
true,
|
||||||
navigablePath,
|
sqmRoot.getNavigablePath(),
|
||||||
sourceAlias,
|
sourceAlias,
|
||||||
// We don't care about the discriminator predicate,
|
// We don't care about the discriminator predicate,
|
||||||
// but we pass non-null to ensure table reference join predicates are generated
|
// but we pass non-null to ensure table reference join predicates are generated
|
||||||
|
@ -112,7 +111,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter<Sta
|
||||||
this,
|
this,
|
||||||
creationContext.getSessionFactory() );
|
creationContext.getSessionFactory() );
|
||||||
|
|
||||||
getFromClauseAccess().registerTableGroup( navigablePath, mutatingTableGroup );
|
getFromClauseAccess().registerTableGroup( sqmRoot.getNavigablePath(), mutatingTableGroup );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
|
|
@ -117,7 +117,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
||||||
|
|
||||||
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(
|
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(
|
||||||
entityDescriptor,
|
entityDescriptor,
|
||||||
sqmMutationStatement.getTarget().getExplicitAlias(),
|
sqmMutationStatement.getTarget(),
|
||||||
explicitDmlTargetAlias,
|
explicitDmlTargetAlias,
|
||||||
domainParameterXref,
|
domainParameterXref,
|
||||||
executionContext.getQueryOptions(),
|
executionContext.getQueryOptions(),
|
||||||
|
@ -324,7 +324,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression );
|
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression, true, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
||||||
|
|
||||||
converter = new MultiTableSqmMutationConverter(
|
converter = new MultiTableSqmMutationConverter(
|
||||||
entityDescriptor,
|
entityDescriptor,
|
||||||
sqmDelete.getTarget().getExplicitAlias(),
|
sqmDelete.getTarget(),
|
||||||
domainParameterXref,
|
domainParameterXref,
|
||||||
queryOptions,
|
queryOptions,
|
||||||
loadQueryInfluencers,
|
loadQueryInfluencers,
|
||||||
|
@ -288,7 +288,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression );
|
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression, true, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ public class TableBasedUpdateHandler
|
||||||
|
|
||||||
final MultiTableSqmMutationConverter converterDelegate = new MultiTableSqmMutationConverter(
|
final MultiTableSqmMutationConverter converterDelegate = new MultiTableSqmMutationConverter(
|
||||||
entityDescriptor,
|
entityDescriptor,
|
||||||
getSqmDeleteOrUpdateStatement().getTarget().getExplicitAlias(),
|
getSqmDeleteOrUpdateStatement().getTarget(),
|
||||||
domainParameterXref,
|
domainParameterXref,
|
||||||
executionContext.getQueryOptions(),
|
executionContext.getQueryOptions(),
|
||||||
executionContext.getSession().getLoadQueryInfluencers(),
|
executionContext.getSession().getLoadQueryInfluencers(),
|
||||||
|
|
|
@ -230,7 +230,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression );
|
return tableGroup.getTableReference( tableGroup.getNavigablePath(), tableExpression, true, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,17 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
*/
|
*/
|
||||||
public class SqmCreationHelper {
|
public class SqmCreationHelper {
|
||||||
public static NavigablePath buildRootNavigablePath(String base, String alias) {
|
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
|
return alias == null
|
||||||
? new NavigablePath( base )
|
? new NavigablePath( base, Long.toString( System.nanoTime() ) )
|
||||||
: new NavigablePath( base, alias );
|
: new NavigablePath( base, alias );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NavigablePath buildSubNavigablePath(NavigablePath lhs, String base, String 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) {
|
public static NavigablePath buildSubNavigablePath(SqmPath<?> lhs, String subNavigable, String alias) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
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.domain.SqmCorrelation;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
|
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
|
||||||
import org.hibernate.sql.ast.tree.expression.ModifiedSubQueryExpression;
|
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.sql.exec.internal.VersionTypeSeedParameterSpecification;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -597,6 +599,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
final SqmStatement<?> sqmStatement = getStatement();
|
final SqmStatement<?> sqmStatement = getStatement();
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
final T statement = (T) sqmStatement.accept( this );
|
final T statement = (T) sqmStatement.accept( this );
|
||||||
|
pruneTableGroupJoins();
|
||||||
return new StandardSqmTranslation<>(
|
return new StandardSqmTranslation<>(
|
||||||
statement,
|
statement,
|
||||||
getJdbcParamsBySqmParam(),
|
getJdbcParamsBySqmParam(),
|
||||||
|
@ -1988,13 +1991,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
additionalRestrictions,
|
additionalRestrictions,
|
||||||
new ComparisonPredicate(
|
new ComparisonPredicate(
|
||||||
new ColumnReference(
|
new ColumnReference(
|
||||||
parentTableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
parentTableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
||||||
selectable,
|
selectable,
|
||||||
sessionFactory
|
sessionFactory
|
||||||
),
|
),
|
||||||
ComparisonOperator.EQUAL,
|
ComparisonOperator.EQUAL,
|
||||||
new ColumnReference(
|
new ColumnReference(
|
||||||
tableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
tableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
||||||
selectable,
|
selectable,
|
||||||
sessionFactory
|
sessionFactory
|
||||||
)
|
)
|
||||||
|
@ -2009,14 +2012,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
(index, selectable) -> {
|
(index, selectable) -> {
|
||||||
lhs.add(
|
lhs.add(
|
||||||
new ColumnReference(
|
new ColumnReference(
|
||||||
parentTableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
parentTableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
||||||
selectable,
|
selectable,
|
||||||
sessionFactory
|
sessionFactory
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
rhs.add(
|
rhs.add(
|
||||||
new ColumnReference(
|
new ColumnReference(
|
||||||
tableGroup.getTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
tableGroup.resolveTableReference( navigablePath, selectable.getContainingTableExpression() ),
|
||||||
selectable,
|
selectable,
|
||||||
sessionFactory
|
sessionFactory
|
||||||
)
|
)
|
||||||
|
@ -2095,13 +2098,58 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
return creationContext.getDomainModel().getEntityDescriptor( entityDomainType.getHibernateEntityName() );
|
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) {
|
protected void consumeExplicitJoins(SqmFrom<?, ?> sqmFrom, TableGroup lhsTableGroup) {
|
||||||
if ( log.isTraceEnabled() ) {
|
if ( log.isTraceEnabled() ) {
|
||||||
log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() );
|
log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() );
|
||||||
}
|
}
|
||||||
sqmFrom.visitSqmJoins(
|
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")
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
@ -2221,7 +2269,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
|
|
||||||
private NavigablePath getJoinNavigablePath(
|
private NavigablePath getJoinNavigablePath(
|
||||||
NavigablePath sqmJoinNavigablePath,
|
NavigablePath sqmJoinNavigablePath,
|
||||||
NavigablePath parentNavigablePath, String partName) {
|
NavigablePath parentNavigablePath,
|
||||||
|
String partName) {
|
||||||
if ( parentNavigablePath == null ) {
|
if ( parentNavigablePath == null ) {
|
||||||
return sqmJoinNavigablePath;
|
return sqmJoinNavigablePath;
|
||||||
}
|
}
|
||||||
|
@ -2327,7 +2376,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
JpaPath<?> sqmPath,
|
JpaPath<?> sqmPath,
|
||||||
boolean useInnerJoin,
|
boolean useInnerJoin,
|
||||||
Consumer<TableGroup> implicitJoinChecker) {
|
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() );
|
final TableGroup tableGroup = fromClauseIndex.findTableGroup( parentPath.getNavigablePath() );
|
||||||
if ( tableGroup == null ) {
|
if ( tableGroup == null ) {
|
||||||
final TableGroup parentTableGroup = prepareReusablePath(
|
final TableGroup parentTableGroup = prepareReusablePath(
|
||||||
|
@ -2336,17 +2391,31 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
useInnerJoin,
|
useInnerJoin,
|
||||||
implicitJoinChecker
|
implicitJoinChecker
|
||||||
);
|
);
|
||||||
|
if ( parentPath instanceof SqmTreatedPath<?, ?> ) {
|
||||||
|
fromClauseIndex.register( (SqmPath<?>) parentPath, parentTableGroup );
|
||||||
|
}
|
||||||
final TableGroup newTableGroup = createTableGroup( parentTableGroup, (SqmPath<?>) parentPath, useInnerJoin );
|
final TableGroup newTableGroup = createTableGroup( parentTableGroup, (SqmPath<?>) parentPath, useInnerJoin );
|
||||||
if ( newTableGroup != null ) {
|
if ( newTableGroup != null ) {
|
||||||
implicitJoinChecker.accept( newTableGroup );
|
implicitJoinChecker.accept( newTableGroup );
|
||||||
|
if ( sqmPath instanceof SqmFrom<?, ?> ) {
|
||||||
|
registerUsage( (SqmFrom<?, ?>) sqmPath, newTableGroup );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 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;
|
return tableGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareForSelection(SqmPath<?> joinedPath) {
|
private void prepareForSelection(SqmPath<?> joinedPath) {
|
||||||
final SqmPath<?> lhsPath = joinedPath.getLhs();
|
|
||||||
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
|
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
|
||||||
final TableGroup tableGroup = fromClauseIndex.findTableGroup( joinedPath.getNavigablePath() );
|
final TableGroup tableGroup = fromClauseIndex.findTableGroup( joinedPath.getNavigablePath() );
|
||||||
if ( tableGroup == null ) {
|
if ( tableGroup == null ) {
|
||||||
|
@ -2354,24 +2423,29 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
|
|
||||||
final NavigablePath navigablePath;
|
final NavigablePath navigablePath;
|
||||||
if ( CollectionPart.Nature.fromNameExact( joinedPath.getNavigablePath().getUnaliasedLocalName() ) != null ) {
|
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 {
|
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.
|
// 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
|
// 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;
|
final boolean useInnerJoin = true;
|
||||||
// INNER join semantics are required per the JPA spec for select items.
|
// INNER join semantics are required per the JPA spec for select items.
|
||||||
createTableGroup( fromClauseIndex.getTableGroup( navigablePath ), joinedPath, useInnerJoin );
|
final TableGroup createdTableGroup = createTableGroup(
|
||||||
}
|
fromClauseIndex.getTableGroup( navigablePath ),
|
||||||
// When we select a treated path, we must add the type restriction as where clause predicate
|
joinedPath,
|
||||||
if ( joinedPath instanceof SqmTreatedPath<?, ?> ) {
|
useInnerJoin
|
||||||
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() )
|
|
||||||
);
|
);
|
||||||
|
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) -> {
|
(selectionIndex, selectionMapping) -> {
|
||||||
tupleElements.add(
|
tupleElements.add(
|
||||||
new ColumnReference(
|
new ColumnReference(
|
||||||
tableGroup.getTableReference(
|
tableGroup.resolveTableReference(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
selectionMapping.getContainingTableExpression()
|
selectionMapping.getContainingTableExpression()
|
||||||
),
|
),
|
||||||
|
@ -5254,9 +5328,18 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
tableGroup
|
tableGroup
|
||||||
);
|
);
|
||||||
if ( manyToManyFilterPredicate != null ) {
|
if ( manyToManyFilterPredicate != null ) {
|
||||||
assert tableGroup.getTableReferenceJoins() != null &&
|
TableGroupJoin elementTableGroupJoin = null;
|
||||||
tableGroup.getTableReferenceJoins().size() == 1;
|
for ( TableGroupJoin nestedTableGroupJoin : tableGroup.getNestedTableGroupJoins() ) {
|
||||||
tableGroup.getTableReferenceJoins().get( 0 ).applyPredicate( manyToManyFilterPredicate );
|
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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import java.util.List;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
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.EntityValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
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.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.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||||
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
|
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.TableReference;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
|
|
||||||
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
|
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(
|
public static <T> EntityValuedPathInterpretation<T> from(
|
||||||
SqmEntityValuedSimplePath<T> sqmPath,
|
SqmEntityValuedSimplePath<T> sqmPath,
|
||||||
SqmToSqlAstConverter sqlAstCreationState) {
|
SqmToSqlAstConverter sqlAstCreationState) {
|
||||||
final SqmPath<?> realPath;
|
|
||||||
if ( CollectionPart.Nature.fromNameExact( sqmPath.getNavigablePath().getUnaliasedLocalName() ) != null ) {
|
|
||||||
realPath = sqmPath.getLhs();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
realPath = sqmPath;
|
|
||||||
}
|
|
||||||
final TableGroup tableGroup = sqlAstCreationState
|
final TableGroup tableGroup = sqlAstCreationState
|
||||||
.getFromClauseAccess()
|
.getFromClauseAccess()
|
||||||
.findTableGroup( realPath.getLhs().getNavigablePath() );
|
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||||
|
|
||||||
final EntityValuedModelPart mapping = (EntityValuedModelPart) sqlAstCreationState
|
final EntityValuedModelPart mapping = (EntityValuedModelPart) sqlAstCreationState
|
||||||
.getFromClauseAccess()
|
.getFromClauseAccess()
|
||||||
|
@ -124,19 +108,6 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
||||||
final String lhsTable;
|
final String lhsTable;
|
||||||
final ModelPart lhsPart;
|
final ModelPart lhsPart;
|
||||||
boolean useKeyPart = associationMapping.getSideNature() == ForeignKeyDescriptor.Nature.KEY;
|
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 ) {
|
if ( useKeyPart ) {
|
||||||
lhsTable = fkDescriptor.getKeyTable();
|
lhsTable = fkDescriptor.getKeyTable();
|
||||||
lhsPart = fkDescriptor.getKeyPart();
|
lhsPart = fkDescriptor.getKeyPart();
|
||||||
|
@ -281,46 +252,4 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
||||||
return (EntityValuedModelPart) super.getExpressionType();
|
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import jakarta.persistence.criteria.JoinType;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.criteria.JpaExpression;
|
import org.hibernate.query.criteria.JpaExpression;
|
||||||
import org.hibernate.query.criteria.JpaPredicate;
|
import org.hibernate.query.criteria.JpaPredicate;
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
|
@ -48,9 +49,28 @@ public abstract class AbstractSqmAttributeJoin<O,T>
|
||||||
SqmJoinType joinType,
|
SqmJoinType joinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
NodeBuilder nodeBuilder) {
|
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
|
//noinspection unchecked
|
||||||
super(
|
super(
|
||||||
SqmCreationHelper.buildSubNavigablePath( lhs, joinedNavigable.getName(), alias ),
|
navigablePath,
|
||||||
(SqmPathSource<T>) joinedNavigable,
|
(SqmPathSource<T>) joinedNavigable,
|
||||||
lhs,
|
lhs,
|
||||||
alias,
|
alias,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -39,7 +40,6 @@ import org.hibernate.query.sqm.NodeBuilder;
|
||||||
import org.hibernate.query.SemanticException;
|
import org.hibernate.query.SemanticException;
|
||||||
import org.hibernate.query.sqm.SqmPathSource;
|
import org.hibernate.query.sqm.SqmPathSource;
|
||||||
import org.hibernate.query.sqm.UnknownPathException;
|
import org.hibernate.query.sqm.UnknownPathException;
|
||||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
|
||||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||||
import org.hibernate.query.sqm.spi.SqmCreationHelper;
|
import org.hibernate.query.sqm.spi.SqmCreationHelper;
|
||||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
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 String alias;
|
||||||
|
|
||||||
private List<SqmJoin<T, ?>> joins;
|
private List<SqmJoin<T, ?>> joins;
|
||||||
|
private List<SqmFrom<?, ?>> treats;
|
||||||
|
|
||||||
protected AbstractSqmFrom(
|
protected AbstractSqmFrom(
|
||||||
NavigablePath navigablePath,
|
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
|
// JPA
|
||||||
|
|
|
@ -59,18 +59,6 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
|
||||||
return (SqmPathSource<T>) super.getNodeType();
|
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
|
@Override
|
||||||
public NavigablePath getNavigablePath() {
|
public NavigablePath getNavigablePath() {
|
||||||
return navigablePath;
|
return navigablePath;
|
||||||
|
|
|
@ -9,8 +9,10 @@ package org.hibernate.query.sqm.tree.domain;
|
||||||
import jakarta.persistence.criteria.PluralJoin;
|
import jakarta.persistence.criteria.PluralJoin;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.criteria.JpaJoin;
|
import org.hibernate.query.criteria.JpaJoin;
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
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.SqmJoinType;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
||||||
|
|
||||||
|
@ -27,14 +29,18 @@ public abstract class AbstractSqmPluralJoin<O,C,E> extends AbstractSqmAttributeJ
|
||||||
SqmJoinType joinType,
|
SqmJoinType joinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
NodeBuilder nodeBuilder) {
|
NodeBuilder nodeBuilder) {
|
||||||
super(
|
super( lhs, joinedNavigable, alias, joinType, fetched, nodeBuilder );
|
||||||
lhs,
|
}
|
||||||
joinedNavigable,
|
|
||||||
alias,
|
protected AbstractSqmPluralJoin(
|
||||||
joinType,
|
SqmFrom<?, O> lhs,
|
||||||
fetched,
|
NavigablePath navigablePath,
|
||||||
nodeBuilder
|
PluralPersistentAttribute<O,C,E> joinedNavigable,
|
||||||
);
|
String alias,
|
||||||
|
SqmJoinType joinType,
|
||||||
|
boolean fetched,
|
||||||
|
NodeBuilder nodeBuilder) {
|
||||||
|
super( lhs, navigablePath, joinedNavigable, alias, joinType, fetched, nodeBuilder );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -12,7 +12,7 @@ import jakarta.persistence.criteria.Predicate;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
|
import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
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.JpaCollectionJoin;
|
||||||
import org.hibernate.query.criteria.JpaExpression;
|
import org.hibernate.query.criteria.JpaExpression;
|
||||||
import org.hibernate.query.criteria.JpaPredicate;
|
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 );
|
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
|
@Override
|
||||||
public BagPersistentAttribute<O,E> getReferencedPathSource() {
|
public BagPersistentAttribute<O,E> getReferencedPathSource() {
|
||||||
return (BagPersistentAttribute<O,E>) super.getReferencedPathSource();
|
return (BagPersistentAttribute<O,E>) super.getReferencedPathSource();
|
||||||
|
@ -85,15 +96,27 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
|
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) {
|
||||||
//noinspection unchecked
|
return treatAs( treatTarget, null );
|
||||||
return new SqmTreatedBagJoin( this, treatTarget, null );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) {
|
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) {
|
||||||
//noinspection unchecked
|
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias );
|
||||||
return new SqmBagJoin(
|
}
|
||||||
|
|
||||||
|
@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() ),
|
creationProcessingState.getPathRegistry().findFromByPath( getLhs().getNavigablePath() ),
|
||||||
getReferencedPathSource(),
|
getReferencedPathSource(),
|
||||||
getExplicitAlias(),
|
getExplicitAlias(),
|
||||||
|
|
|
@ -12,6 +12,8 @@ import jakarta.persistence.criteria.Predicate;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
|
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.PathException;
|
||||||
import org.hibernate.query.criteria.JpaExpression;
|
import org.hibernate.query.criteria.JpaExpression;
|
||||||
import org.hibernate.query.criteria.JpaListJoin;
|
import org.hibernate.query.criteria.JpaListJoin;
|
||||||
|
@ -39,6 +41,17 @@ public class SqmListJoin<O,E>
|
||||||
super( lhs, listAttribute, alias, sqmJoinType, fetched, nodeBuilder );
|
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
|
@Override
|
||||||
public ListPersistentAttribute<O, E> getReferencedPathSource() {
|
public ListPersistentAttribute<O, E> getReferencedPathSource() {
|
||||||
return (ListPersistentAttribute<O, E>) super.getReferencedPathSource();
|
return (ListPersistentAttribute<O, E>) super.getReferencedPathSource();
|
||||||
|
@ -88,12 +101,26 @@ public class SqmListJoin<O,E>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatAsType) {
|
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
|
@Override
|
||||||
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
|
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(EntityDomainType<S> treatTarget) {
|
||||||
return new SqmTreatedListJoin<>( this, treatTarget, null );
|
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
|
@Override
|
||||||
|
|
|
@ -13,6 +13,8 @@ import jakarta.persistence.criteria.Predicate;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
|
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.PathException;
|
||||||
import org.hibernate.query.criteria.JpaExpression;
|
import org.hibernate.query.criteria.JpaExpression;
|
||||||
import org.hibernate.query.criteria.JpaMapJoin;
|
import org.hibernate.query.criteria.JpaMapJoin;
|
||||||
|
@ -40,6 +42,17 @@ public class SqmMapJoin<O, K, V>
|
||||||
super( lhs, pluralValuedNavigable, alias, sqmJoinType, fetched, nodeBuilder );
|
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
|
@Override
|
||||||
public MapPersistentAttribute<O, K, V> getReferencedPathSource() {
|
public MapPersistentAttribute<O, K, V> getReferencedPathSource() {
|
||||||
return(MapPersistentAttribute<O, K, V>) super.getReferencedPathSource();
|
return(MapPersistentAttribute<O, K, V>) super.getReferencedPathSource();
|
||||||
|
@ -103,13 +116,27 @@ public class SqmMapJoin<O, K, V>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 ) );
|
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
|
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(EntityDomainType<S> treatTarget) {
|
||||||
return new SqmTreatedMapJoin<>( this, treatTarget, null );
|
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
|
@Override
|
||||||
|
|
|
@ -114,10 +114,10 @@ public interface SqmPath<T> extends SqmExpression<T>, SemanticPathPart, JpaPath<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
<S extends T> SqmTreatedPath<T,S> treatAs(Class<S> treatJavaType) throws PathException;
|
<S extends T> SqmPath<S> treatAs(Class<S> treatJavaType);
|
||||||
|
|
||||||
@Override
|
@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() {
|
default SqmRoot<?> findRoot() {
|
||||||
final SqmPath<?> lhs = getLhs();
|
final SqmPath<?> lhs = getLhs();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue