use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class AggregateWindowEmulationQueryTransformer method transform.
@Override
public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmToSqlAstConverter converter) {
final SessionFactoryImplementor factory = converter.getCreationContext().getSessionFactory();
final QuerySpec outerQuerySpec = new QuerySpec(querySpec.isRoot());
final String identifierVariable = "hhh_";
final NavigablePath navigablePath = new NavigablePath(identifierVariable, identifierVariable);
final SelectClause selectClause = outerQuerySpec.getSelectClause();
final QuerySpec subQuerySpec = querySpec.asSubQuery();
final SelectClause subSelectClause = subQuerySpec.getSelectClause();
final List<SqlSelection> subSelections = subSelectClause.getSqlSelections();
final List<String> columnNames = new ArrayList<>(subSelections.size());
// A map to find the select item position for an expression
// which is needed to decide if we need to introduce synthetic select items
// for group by items, since these group by items are migrated to the outer query
final Map<Expression, Integer> selectionMapping = new HashMap<>(subSelections.size());
// for the QueryPartTableGroup within which the sub query spec is embedded
for (int i = 0; i < subSelections.size(); i++) {
final BasicValuedMapping mapping = (BasicValuedMapping) subSelections.get(i).getExpressionType();
final String columnName = "col" + i;
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, mapping.getJdbcMapping(), factory);
final Expression expression = subSelections.get(i).getExpression();
final Expression finalExpression;
if (expression == windowFunction) {
finalExpression = new SelfRenderingAggregateFunctionSqlAstExpression("min", (sqlAppender, sqlAstArguments, walker1) -> {
sqlAppender.appendSql("min(");
sqlAstArguments.get(0).accept(walker1);
sqlAppender.append(')');
}, Collections.singletonList(columnReference), null, (ReturnableType<?>) mapping.getMappedType(), expression.getExpressionType());
} else {
finalExpression = columnReference;
selectionMapping.put(expression, i);
}
columnNames.add(columnName);
selectClause.addSqlSelection(new ResolvedSqlSelection(i + 1, i, finalExpression, (BasicType<Object>) mapping.getJdbcMapping()));
}
// Migrate the group by clause to the outer query
// and push group by expressions into the partition by clause of the window function
final List<Expression> groupByExpressions = new ArrayList<>(subQuerySpec.getGroupByClauseExpressions().size());
for (Expression groupByClauseExpression : subQuerySpec.getGroupByClauseExpressions()) {
final Expression realExpression;
final Expression outerGroupByExpression;
if (groupByClauseExpression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) groupByClauseExpression).getSelection();
outerGroupByExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(selection.getValuesArrayPosition()));
realExpression = selection.getExpression();
} else {
if (groupByClauseExpression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) groupByClauseExpression).getSqlExpression();
} else {
realExpression = groupByClauseExpression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// Group by something that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerGroupByExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerGroupByExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(position));
}
}
windowFunction.getPartitions().add(realExpression);
groupByExpressions.add(outerGroupByExpression);
}
outerQuerySpec.setGroupByClauseExpressions(groupByExpressions);
subQuerySpec.setGroupByClauseExpressions(null);
// Migrate the having clause to the outer query
if (subQuerySpec.getHavingClauseRestrictions() != null) {
final Predicate predicate = new ExpressionReplacementWalker() {
@Override
protected <X extends SqlAstNode> X replaceExpression(X expression) {
if (expression instanceof Literal || expression instanceof JdbcParameter) {
return expression;
}
final Expression outerExpression;
if (expression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) expression).getSelection();
outerExpression = selectClause.getSqlSelections().get(selection.getValuesArrayPosition()).getExpression();
} else {
final Expression realExpression;
if (expression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) expression).getSqlExpression();
} else {
realExpression = (Expression) expression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// An expression that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerExpression = selectClause.getSqlSelections().get(position).getExpression();
}
}
return (X) outerExpression;
}
}.replaceExpressions(subQuerySpec.getHavingClauseRestrictions());
outerQuerySpec.setHavingClauseRestrictions(predicate);
subQuerySpec.setHavingClauseRestrictions(null);
}
// Migrate the order by clause to the outer query
if (subQuerySpec.hasSortSpecifications()) {
for (SortSpecification sortSpecification : subQuerySpec.getSortSpecifications()) {
final Expression sortExpression = sortSpecification.getSortExpression();
final Expression outerSortExpression;
if (sortExpression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) sortExpression).getSelection();
outerSortExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(selection.getValuesArrayPosition()));
} else {
final Expression realExpression;
if (sortExpression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) sortExpression).getSqlExpression();
} else {
realExpression = sortExpression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// Group by something that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerSortExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerSortExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(position));
}
}
outerQuerySpec.addSortSpecification(new SortSpecification(outerSortExpression, sortSpecification.getSortOrder(), sortSpecification.getNullPrecedence()));
}
subQuerySpec.getSortSpecifications().clear();
}
// We need to add selection items for the expressions we order by to the sub query spec.
final int selectionOffset = columnNames.size();
// Collect the sorting column references so we can apply the filter later
final List<ColumnReference> sortingColumns = new ArrayList<>(withinGroup.size());
for (int i = 0; i < withinGroup.size(); i++) {
final int valueIndex = selectionOffset + i;
final Expression sortExpression = withinGroup.get(i).getSortExpression();
final BasicValuedMapping mapping = (BasicValuedMapping) sortExpression.getExpressionType();
final String columnName = "col" + valueIndex;
final int oldValueIndex = subSelectClause.getSqlSelections().size();
columnNames.add(columnName);
subSelectClause.addSqlSelection(new ResolvedSqlSelection(oldValueIndex + 1, oldValueIndex, sortExpression, (BasicType<Object>) mapping.getJdbcMapping()));
sortingColumns.add(new ColumnReference(identifierVariable, columnName, false, null, null, mapping.getJdbcMapping(), factory));
}
if (arguments != null) {
// So we add a filter to the outer query so we can extract the rank
switch(arguments.size()) {
case 0:
break;
case 1:
outerQuerySpec.applyPredicate(new ComparisonPredicate(sortingColumns.get(0), ComparisonOperator.EQUAL, (Expression) arguments.get(0)));
break;
default:
outerQuerySpec.applyPredicate(new ComparisonPredicate(new SqlTuple(sortingColumns, null), ComparisonOperator.EQUAL, new SqlTuple((List<? extends Expression>) (List<?>) arguments, null)));
}
}
final QueryPartTableGroup queryPartTableGroup = new QueryPartTableGroup(navigablePath, null, subQuerySpec, identifierVariable, columnNames, false, true, factory);
outerQuerySpec.getFromClause().addRoot(queryPartTableGroup);
// Migrate the offset/fetch clause
outerQuerySpec.setOffsetClauseExpression(subQuerySpec.getOffsetClauseExpression());
outerQuerySpec.setFetchClauseExpression(subQuerySpec.getFetchClauseExpression(), subQuerySpec.getFetchClauseType());
subQuerySpec.setOffsetClauseExpression(null);
subQuerySpec.setFetchClauseExpression(null, null);
return outerQuerySpec;
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class CountFunction method render.
@Override
public void render(SqlAppender sqlAppender, List<? extends SqlAstNode> sqlAstArguments, Predicate filter, SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && !translator.supportsFilterClause();
final SqlAstNode arg = sqlAstArguments.get(0);
sqlAppender.appendSql("count(");
final SqlTuple tuple;
if (arg instanceof Distinct) {
sqlAppender.appendSql("distinct ");
final Expression distinctArg = ((Distinct) arg).getExpression();
if ((tuple = SqlTupleContainer.getSqlTuple(distinctArg)) != null) {
final List<? extends Expression> expressions = tuple.getExpressions();
// Single element tuple
if (expressions.size() == 1) {
renderSimpleArgument(sqlAppender, filter, translator, caseWrapper, expressions.get(0));
} else // Emulate tuple distinct count
if (!dialect.supportsTupleDistinctCounts()) {
// count(distinct coalesce(nullif(coalesce(col1 || '', '\0'), ''), '\01') || '\0' || coalesce(nullif(coalesce(col2 || '', '\0'), ''), '\02'))
if (caseWrapper) {
translator.getCurrentClauseStack().push(Clause.WHERE);
sqlAppender.appendSql("case when ");
filter.accept(translator);
sqlAppender.appendSql(" then ");
translator.getCurrentClauseStack().pop();
}
if (castDistinctStringConcat) {
sqlAppender.appendSql("cast(");
}
sqlAppender.appendSql("coalesce(nullif(coalesce(");
boolean needsConcat = renderCastedArgument(sqlAppender, translator, expressions.get(0));
int argumentNumber = 1;
for (int i = 1; i < expressions.size(); i++, argumentNumber++) {
if (needsConcat) {
// Concat with empty string to get implicit conversion
sqlAppender.appendSql(concatOperator);
sqlAppender.appendSql("''");
}
sqlAppender.appendSql(",'\\0'),''),'\\0");
sqlAppender.appendSql(argumentNumber);
sqlAppender.appendSql("')");
sqlAppender.appendSql(concatOperator);
sqlAppender.appendSql("'\\0'");
sqlAppender.appendSql(concatOperator);
sqlAppender.appendSql("coalesce(nullif(coalesce(");
needsConcat = renderCastedArgument(sqlAppender, translator, expressions.get(i));
}
if (needsConcat) {
// Concat with empty string to get implicit conversion
sqlAppender.appendSql(concatOperator);
sqlAppender.appendSql("''");
}
sqlAppender.appendSql(",'\\0'),''),'\\0");
sqlAppender.appendSql(argumentNumber);
sqlAppender.appendSql("')");
if (castDistinctStringConcat) {
sqlAppender.appendSql(" as ");
sqlAppender.appendSql(concatArgumentCastType);
sqlAppender.appendSql(')');
}
if (caseWrapper) {
sqlAppender.appendSql(" else null end");
}
} else {
renderTupleCountSupported(sqlAppender, filter, translator, caseWrapper, tuple, expressions, dialect.requiresParensForTupleDistinctCounts());
}
} else {
renderSimpleArgument(sqlAppender, filter, translator, caseWrapper, distinctArg);
}
} else {
if (canReplaceWithStar(arg, translator)) {
renderSimpleArgument(sqlAppender, filter, translator, caseWrapper, Star.INSTANCE);
} else if ((tuple = SqlTupleContainer.getSqlTuple(arg)) != null) {
final List<? extends Expression> expressions = tuple.getExpressions();
// Single element tuple
if (expressions.size() == 1) {
renderSimpleArgument(sqlAppender, filter, translator, caseWrapper, expressions.get(0));
} else // Emulate the tuple count with a case when expression
if (!dialect.supportsTupleCounts()) {
sqlAppender.appendSql("case when ");
if (caseWrapper) {
translator.getCurrentClauseStack().push(Clause.WHERE);
filter.accept(translator);
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql(" and ");
}
translator.render(expressions.get(0), defaultArgumentRenderingMode);
sqlAppender.appendSql(" is not null");
for (int i = 1; i < expressions.size(); i++) {
sqlAppender.appendSql(" and ");
translator.render(expressions.get(i), defaultArgumentRenderingMode);
sqlAppender.appendSql(" is not null");
}
sqlAppender.appendSql(" then 1 else null end");
} else // Tuple counts are supported
{
renderTupleCountSupported(sqlAppender, filter, translator, caseWrapper, tuple, expressions, dialect.requiresParensForTupleCounts());
}
} else {
renderSimpleArgument(sqlAppender, filter, translator, caseWrapper, arg);
}
}
sqlAppender.appendSql(')');
if (filter != null && !caseWrapper) {
translator.getCurrentClauseStack().push(Clause.WHERE);
sqlAppender.appendSql(" filter (where ");
filter.accept(translator);
sqlAppender.appendSql(')');
translator.getCurrentClauseStack().pop();
}
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class EntityValuedPathInterpretation method from.
public static <T> EntityValuedPathInterpretation<T> from(NavigablePath navigablePath, TableGroup tableGroup, ModelPart resultModelPart, EntityValuedModelPart mapping, EntityValuedModelPart treatedMapping, SqmToSqlAstConverter sqlAstCreationState) {
final SqlExpressionResolver sqlExprResolver = sqlAstCreationState.getSqlExpressionResolver();
final SessionFactoryImplementor sessionFactory = sqlAstCreationState.getCreationContext().getSessionFactory();
final Expression sqlExpression;
if (resultModelPart == null) {
final EntityMappingType entityMappingType = mapping.getEntityMappingType();
final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping();
final EntityDiscriminatorMapping discriminatorMapping = entityMappingType.getDiscriminatorMapping();
final List<Expression> expressions = new ArrayList<>(entityMappingType.getJdbcTypeCount() + identifierMapping.getJdbcTypeCount() + (discriminatorMapping == null ? 0 : 1));
final TableGroup parentTableGroup = tableGroup;
final SelectableConsumer selectableConsumer = (selectionIndex, selectableMapping) -> {
final TableReference tableReference = parentTableGroup.resolveTableReference(navigablePath, selectableMapping.getContainingTableExpression(), false);
expressions.add(sqlExprResolver.resolveSqlExpression(createColumnReferenceKey(tableReference, selectableMapping.getSelectionExpression()), processingState -> new ColumnReference(tableReference, selectableMapping, sessionFactory)));
};
identifierMapping.forEachSelectable(selectableConsumer);
if (discriminatorMapping != null) {
discriminatorMapping.forEachSelectable(selectableConsumer);
}
entityMappingType.forEachSelectable(selectableConsumer);
sqlExpression = new SqlTuple(expressions, entityMappingType);
} else {
if (resultModelPart instanceof BasicValuedModelPart) {
final BasicValuedModelPart basicValuedModelPart = (BasicValuedModelPart) resultModelPart;
final TableReference tableReference = tableGroup.resolveTableReference(navigablePath, basicValuedModelPart.getContainingTableExpression());
sqlExpression = sqlExprResolver.resolveSqlExpression(createColumnReferenceKey(tableReference, basicValuedModelPart.getSelectionExpression()), processingState -> new ColumnReference(tableReference, basicValuedModelPart, sessionFactory));
} else {
final List<Expression> expressions = new ArrayList<>(resultModelPart.getJdbcTypeCount());
resultModelPart.forEachSelectable((selectionIndex, selectableMapping) -> {
final TableReference tableReference = tableGroup.resolveTableReference(navigablePath, selectableMapping.getContainingTableExpression());
expressions.add(sqlExprResolver.resolveSqlExpression(createColumnReferenceKey(tableReference, selectableMapping.getSelectionExpression()), processingState -> new ColumnReference(tableReference, selectableMapping, sessionFactory)));
});
sqlExpression = new SqlTuple(expressions, resultModelPart);
}
}
return new EntityValuedPathInterpretation<>(sqlExpression, navigablePath, tableGroup, treatedMapping);
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple in project hibernate-orm by hibernate.
the class SqmParameterInterpretation method resolveSqlSelection.
public SqlSelection resolveSqlSelection(DomainResultCreationState creationState) {
final Expression resolvedExpression = getResolvedExpression();
if (resolvedExpression instanceof SqlTuple) {
throw new SemanticException("Composite query parameter cannot be used in select");
}
BindableType<?> nodeType = sqmParameter.getNodeType();
if (nodeType == null) {
final QueryParameterBinding<?> binding = queryParameterBindingResolver.apply(queryParameter);
nodeType = binding.getBindType();
}
final SessionFactoryImplementor sessionFactory = creationState.getSqlAstCreationState().getCreationContext().getSessionFactory();
final SqmExpressible<?> sqmExpressible = nodeType.resolveExpressible(sessionFactory);
return creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(resolvedExpression, sqmExpressible.getExpressibleJavaType(), sessionFactory.getTypeConfiguration());
}
use of org.hibernate.sql.ast.tree.expression.SqlTuple 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);
}
}
Aggregations