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