use of org.hibernate.metamodel.mapping.EntityAssociationMapping in project hibernate-orm by hibernate.
the class EntityValuedPathInterpretation method from.
public static <T> EntityValuedPathInterpretation<T> from(SqmEntityValuedSimplePath<T> sqmPath, MappingModelExpressible<?> inferredMapping, SqmToSqlAstConverter sqlAstCreationState) {
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().findTableGroup(sqmPath.getLhs().getNavigablePath());
final EntityValuedModelPart pathMapping = (EntityValuedModelPart) sqlAstCreationState.getFromClauseAccess().findTableGroup(sqmPath.getLhs().getNavigablePath()).getModelPart().findSubPart(sqmPath.getReferencedPathSource().getPathName(), null);
final EntityValuedModelPart mapping;
if (inferredMapping instanceof EntityAssociationMapping) {
final EntityAssociationMapping inferredAssociation = (EntityAssociationMapping) inferredMapping;
if (pathMapping instanceof EntityAssociationMapping && inferredMapping != pathMapping) {
// In here, the inferred mapping and the actual path mapping are association mappings,
// but for different associations, so we have to check if both associations point to the same target
final EntityAssociationMapping pathAssociation = (EntityAssociationMapping) pathMapping;
final ModelPart pathTargetPart = pathAssociation.getForeignKeyDescriptor().getPart(pathAssociation.getSideNature().inverse());
final ModelPart inferredTargetPart = inferredAssociation.getForeignKeyDescriptor().getPart(inferredAssociation.getSideNature().inverse());
// which will render the FK of the path association
if (pathTargetPart == inferredTargetPart) {
mapping = pathMapping;
} else {
// Otherwise, we need to use the entity mapping type to force rendering the PK
// for e.g. `a.assoc1 = a.assoc2` when both associations have different target join columns
mapping = pathMapping.getEntityMappingType();
}
} else {
// This is the case when the inferred mapping is an association, but the path mapping is not,
// or the path mapping and the inferred mapping are for the same association
mapping = (EntityValuedModelPart) inferredMapping;
}
} else {
mapping = pathMapping;
}
final ModelPart resultModelPart;
if (mapping instanceof EntityAssociationMapping) {
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) mapping;
final ModelPart keyTargetMatchPart = associationMapping.getKeyTargetMatchPart();
if (keyTargetMatchPart instanceof ToOneAttributeMapping) {
resultModelPart = ((ToOneAttributeMapping) keyTargetMatchPart).getKeyTargetMatchPart();
} else {
resultModelPart = keyTargetMatchPart;
}
} else {
resultModelPart = mapping.getEntityMappingType().getIdentifierMapping();
}
return from(sqmPath.getNavigablePath(), tableGroup, resultModelPart, mapping, mapping, sqlAstCreationState);
}
use of org.hibernate.metamodel.mapping.EntityAssociationMapping in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method createLateralJoinExpression.
protected Expression createLateralJoinExpression(AbstractSqmSpecificPluralPartPath<?> pluralPartPath, boolean index, String functionName) {
prepareReusablePath(pluralPartPath.getLhs(), () -> null);
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(pluralPartPath.getPluralDomainPath());
final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
final TableGroup parentTableGroup = parentFromClauseAccess.findTableGroup(pluralPartPath.getNavigablePath().getParent());
final CollectionPart collectionPart = index ? pluralAttributeMapping.getIndexDescriptor() : pluralAttributeMapping.getElementDescriptor();
final ModelPart modelPart;
if (collectionPart instanceof EntityAssociationMapping) {
modelPart = ((EntityAssociationMapping) collectionPart).getKeyTargetMatchPart();
} else {
modelPart = collectionPart;
}
final int jdbcTypeCount = modelPart.getJdbcTypeCount();
final String pathName = functionName + (index ? "_index" : "_element");
final String identifierVariable = parentTableGroup.getPrimaryTableReference().getIdentificationVariable() + "_" + pathName;
final NavigablePath queryPath = new NavigablePath(parentTableGroup.getNavigablePath(), pathName, identifierVariable);
TableGroup lateralTableGroup = parentFromClauseAccess.findTableGroup(queryPath);
if (lateralTableGroup == null) {
final QuerySpec subQuerySpec = new QuerySpec(false);
pushProcessingState(new SqlAstQueryPartProcessingStateImpl(subQuerySpec, getCurrentProcessingState(), this, currentClauseStack::getCurrent, false));
try {
final TableGroup tableGroup = pluralAttributeMapping.createRootTableGroup(true, pluralPartPath.getNavigablePath(), null, () -> subQuerySpec::applyPredicate, this, creationContext);
pluralAttributeMapping.applyBaseRestrictions(subQuerySpec::applyPredicate, tableGroup, true, getLoadQueryInfluencers().getEnabledFilters(), null, this);
getFromClauseAccess().registerTableGroup(pluralPartPath.getNavigablePath(), tableGroup);
registerPluralTableGroupParts(tableGroup);
subQuerySpec.getFromClause().addRoot(tableGroup);
final List<String> columnNames = new ArrayList<>(jdbcTypeCount);
final List<ColumnReference> resultColumnReferences = new ArrayList<>(jdbcTypeCount);
final NavigablePath navigablePath = pluralPartPath.getNavigablePath();
final Boolean max = functionName.equalsIgnoreCase("max") ? Boolean.TRUE : (functionName.equalsIgnoreCase("min") ? Boolean.FALSE : null);
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext.getSessionFactory().getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor(functionName);
final List<ColumnReference> subQueryColumns = new ArrayList<>(jdbcTypeCount);
modelPart.forEachSelectable((selectionIndex, selectionMapping) -> {
final ColumnReference columnReference = new ColumnReference(tableGroup.resolveTableReference(navigablePath, selectionMapping.getContainingTableExpression()), selectionMapping, creationContext.getSessionFactory());
final String columnName;
if (selectionMapping.isFormula()) {
columnName = "col" + columnNames.size();
} else {
columnName = selectionMapping.getSelectionExpression();
}
columnNames.add(columnName);
subQueryColumns.add(columnReference);
if (max != null) {
subQuerySpec.addSortSpecification(new SortSpecification(columnReference, max ? SortOrder.DESCENDING : SortOrder.ASCENDING));
}
});
if (max != null) {
for (int i = 0; i < subQueryColumns.size(); i++) {
subQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(i + 1, i, subQueryColumns.get(i)));
resultColumnReferences.add(new ColumnReference(identifierVariable, columnNames.get(i), false, null, null, subQueryColumns.get(i).getJdbcMapping(), creationContext.getSessionFactory()));
}
subQuerySpec.setFetchClauseExpression(new QueryLiteral<>(1, basicType(Integer.class)), FetchClauseType.ROWS_ONLY);
} else {
final List<? extends SqlAstNode> arguments;
if (jdbcTypeCount == 1) {
arguments = subQueryColumns;
} else {
arguments = Collections.singletonList(new SqlTuple(subQueryColumns, modelPart));
}
final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression(functionDescriptor.getName(), functionDescriptor, arguments, null, (ReturnableType<?>) functionDescriptor.getReturnTypeResolver().resolveFunctionReturnType(() -> null, arguments).getJdbcMapping(), modelPart);
subQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, expression));
resultColumnReferences.add(new ColumnReference(identifierVariable, columnNames.get(0), false, null, null, expression.getExpressionType().getJdbcMappings().get(0), creationContext.getSessionFactory()));
}
subQuerySpec.applyPredicate(pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(parentFromClauseAccess.findTableGroup(pluralPartPath.getPluralDomainPath().getNavigablePath().getParent()), tableGroup, getSqlExpressionResolver(), creationContext));
final String compatibleTableExpression;
if (modelPart instanceof BasicValuedModelPart) {
compatibleTableExpression = ((BasicValuedModelPart) modelPart).getContainingTableExpression();
} else if (modelPart instanceof EmbeddableValuedModelPart) {
compatibleTableExpression = ((EmbeddableValuedModelPart) modelPart).getContainingTableExpression();
} else {
compatibleTableExpression = null;
}
lateralTableGroup = new QueryPartTableGroup(queryPath, null, subQuerySpec, identifierVariable, columnNames, compatibleTableExpression, true, false, creationContext.getSessionFactory());
if (currentlyProcessingJoin == null) {
parentTableGroup.addTableGroupJoin(new TableGroupJoin(lateralTableGroup.getNavigablePath(), SqlAstJoinType.LEFT, lateralTableGroup));
} else {
// In case this is used in the ON condition, we must prepend this lateral join
final TableGroup targetTableGroup;
if (currentlyProcessingJoin.getLhs() == null) {
targetTableGroup = parentFromClauseAccess.getTableGroup(currentlyProcessingJoin.findRoot().getNavigablePath());
} else {
targetTableGroup = parentFromClauseAccess.getTableGroup(currentlyProcessingJoin.getLhs().getNavigablePath());
}
// Many databases would support modelling this as nested table group join,
// but at least SQL Server doesn't like that, saying that the correlated columns can't be "bound"
// Since there is no dependency on the currentlyProcessingJoin, we can safely prepend this join
targetTableGroup.prependTableGroupJoin(currentlyProcessingJoin.getNavigablePath(), new TableGroupJoin(lateralTableGroup.getNavigablePath(), SqlAstJoinType.LEFT, lateralTableGroup));
}
parentFromClauseAccess.registerTableGroup(lateralTableGroup.getNavigablePath(), lateralTableGroup);
if (jdbcTypeCount == 1) {
return new SelfRenderingFunctionSqlAstExpression(pathName, (sqlAppender, sqlAstArguments, walker) -> {
sqlAstArguments.get(0).accept(walker);
}, resultColumnReferences, (ReturnableType<?>) resultColumnReferences.get(0).getJdbcMapping(), resultColumnReferences.get(0).getJdbcMapping());
} else {
return new SqlTuple(resultColumnReferences, modelPart);
}
} finally {
popProcessingStateStack();
}
}
final QueryPartTableReference tableReference = (QueryPartTableReference) lateralTableGroup.getPrimaryTableReference();
if (jdbcTypeCount == 1) {
final List<SqlSelection> sqlSelections = tableReference.getQueryPart().getFirstQuerySpec().getSelectClause().getSqlSelections();
return new SelfRenderingFunctionSqlAstExpression(pathName, (sqlAppender, sqlAstArguments, walker) -> {
sqlAstArguments.get(0).accept(walker);
}, Collections.singletonList(new ColumnReference(identifierVariable, tableReference.getColumnNames().get(0), false, null, null, sqlSelections.get(0).getExpressionType().getJdbcMappings().get(0), creationContext.getSessionFactory())), (ReturnableType<?>) sqlSelections.get(0).getExpressionType().getJdbcMappings().get(0), sqlSelections.get(0).getExpressionType());
} else {
final List<ColumnReference> resultColumnReferences = new ArrayList<>(jdbcTypeCount);
modelPart.forEachSelectable((selectionIndex, selectionMapping) -> resultColumnReferences.add(new ColumnReference(identifierVariable, tableReference.getColumnNames().get(selectionIndex), false, null, null, selectionMapping.getJdbcMapping(), creationContext.getSessionFactory())));
return new SqlTuple(resultColumnReferences, modelPart);
}
}
use of org.hibernate.metamodel.mapping.EntityAssociationMapping in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method createCorrelatedAggregateSubQuery.
protected Expression createCorrelatedAggregateSubQuery(AbstractSqmSpecificPluralPartPath<?> pluralPartPath, boolean index, String function) {
prepareReusablePath(pluralPartPath.getLhs(), () -> null);
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(pluralPartPath.getPluralDomainPath());
final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
final QuerySpec subQuerySpec = new QuerySpec(false);
pushProcessingState(new SqlAstQueryPartProcessingStateImpl(subQuerySpec, getCurrentProcessingState(), this, currentClauseStack::getCurrent, false));
try {
final TableGroup tableGroup = pluralAttributeMapping.createRootTableGroup(true, pluralPartPath.getNavigablePath(), null, () -> subQuerySpec::applyPredicate, this, creationContext);
pluralAttributeMapping.applyBaseRestrictions(subQuerySpec::applyPredicate, tableGroup, true, getLoadQueryInfluencers().getEnabledFilters(), null, this);
getFromClauseAccess().registerTableGroup(pluralPartPath.getNavigablePath(), tableGroup);
registerPluralTableGroupParts(tableGroup);
subQuerySpec.getFromClause().addRoot(tableGroup);
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext.getSessionFactory().getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor(function);
final CollectionPart collectionPart = index ? pluralAttributeMapping.getIndexDescriptor() : pluralAttributeMapping.getElementDescriptor();
final ModelPart modelPart;
if (collectionPart instanceof EntityAssociationMapping) {
modelPart = ((EntityAssociationMapping) collectionPart).getKeyTargetMatchPart();
} else {
modelPart = collectionPart;
}
final List<Expression> arguments = new ArrayList<>(1);
final NavigablePath navigablePath = pluralPartPath.getNavigablePath();
final int jdbcTypeCount = modelPart.getJdbcTypeCount();
final List<Expression> tupleElements;
if (jdbcTypeCount == 1) {
tupleElements = arguments;
} else {
tupleElements = new ArrayList<>(jdbcTypeCount);
}
modelPart.forEachSelectable((selectionIndex, selectionMapping) -> tupleElements.add(new ColumnReference(tableGroup.resolveTableReference(navigablePath, selectionMapping.getContainingTableExpression()), selectionMapping, creationContext.getSessionFactory())));
if (jdbcTypeCount != 1) {
arguments.add(new SqlTuple(tupleElements, modelPart));
}
final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression(functionDescriptor.getName(), functionDescriptor, arguments, null, (ReturnableType<?>) functionDescriptor.getReturnTypeResolver().resolveFunctionReturnType(() -> null, arguments).getJdbcMapping(), modelPart);
subQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, expression));
NavigablePath parent = pluralPartPath.getPluralDomainPath().getNavigablePath().getParent();
subQuerySpec.applyPredicate(pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(parentFromClauseAccess.findTableGroup(parent), tableGroup, getSqlExpressionResolver(), creationContext));
} finally {
popProcessingStateStack();
}
return subQuerySpec;
}
use of org.hibernate.metamodel.mapping.EntityAssociationMapping in project hibernate-orm by hibernate.
the class SqmUtil method createValueBindings.
private static void createValueBindings(JdbcParameterBindings jdbcParameterBindings, QueryParameterImplementor<?> domainParam, QueryParameterBinding<?> domainParamBinding, Bindable parameterType, List<JdbcParameter> jdbcParams, Object bindValue, Function<NavigablePath, TableGroup> tableGroupLocator, SharedSessionContractImplementor session) {
if (parameterType == null) {
throw new SqlTreeCreationException("Unable to interpret mapping-model type for Query parameter : " + domainParam);
}
if (parameterType instanceof EntityIdentifierMapping) {
final EntityIdentifierMapping identifierMapping = (EntityIdentifierMapping) parameterType;
final EntityMappingType entityMapping = identifierMapping.findContainingEntityMapping();
if (entityMapping.getRepresentationStrategy().getInstantiator().isInstance(bindValue, session.getFactory())) {
bindValue = identifierMapping.getIdentifier(bindValue);
}
} else if (parameterType instanceof EntityMappingType) {
final EntityIdentifierMapping identifierMapping = ((EntityMappingType) parameterType).getIdentifierMapping();
final EntityMappingType entityMapping = identifierMapping.findContainingEntityMapping();
parameterType = identifierMapping;
if (entityMapping.getRepresentationStrategy().getInstantiator().isInstance(bindValue, session.getFactory())) {
bindValue = identifierMapping.getIdentifier(bindValue);
}
} else if (parameterType instanceof EntityAssociationMapping) {
EntityAssociationMapping association = (EntityAssociationMapping) parameterType;
bindValue = association.getForeignKeyDescriptor().getAssociationKeyFromSide(bindValue, association.getSideNature().inverse(), session);
parameterType = association.getForeignKeyDescriptor();
} else if (parameterType instanceof PluralAttributeMapping) {
// for now, let's blow up and see where this happens and fix the specifics...
throw new NotYetImplementedFor6Exception("Binding parameters whose inferred type comes from plural attribute not yet implemented");
}
int offset = jdbcParameterBindings.registerParametersForEachJdbcValue(bindValue, Clause.IRRELEVANT, parameterType, jdbcParams, session);
assert offset == jdbcParams.size();
}
use of org.hibernate.metamodel.mapping.EntityAssociationMapping in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method resolveSqmParameter.
private void resolveSqmParameter(SqmParameter<?> expression, MappingModelExpressible<?> valueMapping, BiConsumer<Integer, JdbcParameter> jdbcParameterConsumer) {
sqmParameterMappingModelTypes.put(expression, valueMapping);
final Bindable bindable;
if (valueMapping instanceof EntityAssociationMapping) {
final EntityAssociationMapping mapping = (EntityAssociationMapping) valueMapping;
bindable = mapping.getForeignKeyDescriptor().getPart(mapping.getSideNature());
} else if (valueMapping instanceof EntityMappingType) {
bindable = ((EntityMappingType) valueMapping).getIdentifierMapping();
} else {
bindable = valueMapping;
}
if (bindable instanceof SelectableMappings) {
((SelectableMappings) bindable).forEachSelectable((index, selectableMapping) -> jdbcParameterConsumer.accept(index, new SqlTypedMappingJdbcParameter(selectableMapping)));
} else if (bindable instanceof SelectableMapping) {
jdbcParameterConsumer.accept(0, new SqlTypedMappingJdbcParameter((SelectableMapping) bindable));
} else {
SqlTypedMapping sqlTypedMapping = null;
if (bindable instanceof BasicType<?>) {
final int sqlTypeCode = ((BasicType<?>) bindable).getJdbcType().getDefaultSqlTypeCode();
if (sqlTypeCode == SqlTypes.NUMERIC || sqlTypeCode == SqlTypes.DECIMAL) {
// For numeric and decimal parameter types we must determine the precision/scale of the value.
// When we need to cast the parameter later, it is necessary to know the size to avoid truncation.
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding(domainParameterXref.getQueryParameter(expression));
final Object bindValue = binding.getBindValue();
if (bindValue != null) {
if (bindValue instanceof BigInteger) {
int precision = bindValue.toString().length() - (((BigInteger) bindValue).signum() < 0 ? 1 : 0);
sqlTypedMapping = new SqlTypedMappingImpl(null, null, precision, 0, ((BasicType<?>) bindable).getJdbcMapping());
} else if (bindValue instanceof BigDecimal) {
final BigDecimal bigDecimal = (BigDecimal) bindValue;
sqlTypedMapping = new SqlTypedMappingImpl(null, null, bigDecimal.precision(), bigDecimal.scale(), ((BasicType<?>) bindable).getJdbcMapping());
}
}
}
}
if (sqlTypedMapping == null) {
bindable.forEachJdbcType((index, jdbcMapping) -> jdbcParameterConsumer.accept(index, new JdbcParameterImpl(jdbcMapping)));
} else {
jdbcParameterConsumer.accept(0, new SqlTypedMappingJdbcParameter(sqlTypedMapping));
}
}
}
Aggregations