Search in sources :

Example 6 with SortSpecification

use of org.hibernate.sql.ast.tree.select.SortSpecification 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;
}
Also used : JdbcMapping(org.hibernate.metamodel.mapping.JdbcMapping) BasicType(org.hibernate.type.BasicType) CteContainer(org.hibernate.sql.ast.tree.cte.CteContainer) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference) HashMap(java.util.HashMap) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) ArrayList(java.util.ArrayList) ExpressionReplacementWalker(org.hibernate.sql.ast.spi.ExpressionReplacementWalker) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) Map(java.util.Map) SqlAstNode(org.hibernate.sql.ast.tree.SqlAstNode) ComparisonOperator(org.hibernate.query.sqm.ComparisonOperator) ReturnableType(org.hibernate.query.ReturnableType) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) SqlSelection(org.hibernate.sql.ast.spi.SqlSelection) SelfRenderingAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression) Predicate(org.hibernate.sql.ast.tree.predicate.Predicate) ResolvedSqlSelection(org.hibernate.sql.results.internal.ResolvedSqlSelection) SqlSelectionExpression(org.hibernate.sql.ast.tree.expression.SqlSelectionExpression) NavigablePath(org.hibernate.query.spi.NavigablePath) BasicValuedMapping(org.hibernate.metamodel.mapping.BasicValuedMapping) Expression(org.hibernate.sql.ast.tree.expression.Expression) SqmToSqlAstConverter(org.hibernate.query.sqm.sql.SqmToSqlAstConverter) QueryTransformer(org.hibernate.sql.ast.tree.expression.QueryTransformer) SelectClause(org.hibernate.sql.ast.tree.select.SelectClause) List(java.util.List) JdbcParameter(org.hibernate.sql.ast.tree.expression.JdbcParameter) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) Literal(org.hibernate.sql.ast.tree.expression.Literal) SqlTuple(org.hibernate.sql.ast.tree.expression.SqlTuple) Over(org.hibernate.sql.ast.tree.expression.Over) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) Collections(java.util.Collections) SqmPathInterpretation(org.hibernate.query.sqm.sql.internal.SqmPathInterpretation) SelectClause(org.hibernate.sql.ast.tree.select.SelectClause) SelfRenderingAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression) NavigablePath(org.hibernate.query.spi.NavigablePath) BasicType(org.hibernate.type.BasicType) JdbcMapping(org.hibernate.metamodel.mapping.JdbcMapping) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) SqlSelection(org.hibernate.sql.ast.spi.SqlSelection) ResolvedSqlSelection(org.hibernate.sql.results.internal.ResolvedSqlSelection) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) Predicate(org.hibernate.sql.ast.tree.predicate.Predicate) ReturnableType(org.hibernate.query.ReturnableType) ExpressionReplacementWalker(org.hibernate.sql.ast.spi.ExpressionReplacementWalker) Literal(org.hibernate.sql.ast.tree.expression.Literal) ResolvedSqlSelection(org.hibernate.sql.results.internal.ResolvedSqlSelection) SqmPathInterpretation(org.hibernate.query.sqm.sql.internal.SqmPathInterpretation) ArrayList(java.util.ArrayList) List(java.util.List) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) JdbcParameter(org.hibernate.sql.ast.tree.expression.JdbcParameter) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) SqlSelectionExpression(org.hibernate.sql.ast.tree.expression.SqlSelectionExpression) BasicValuedMapping(org.hibernate.metamodel.mapping.BasicValuedMapping) SelfRenderingAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression) SqlSelectionExpression(org.hibernate.sql.ast.tree.expression.SqlSelectionExpression) Expression(org.hibernate.sql.ast.tree.expression.Expression) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) SqlTuple(org.hibernate.sql.ast.tree.expression.SqlTuple) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Example 7 with SortSpecification

use of org.hibernate.sql.ast.tree.select.SortSpecification in project hibernate-orm by hibernate.

the class InverseDistributionWindowEmulation method generateSqmOrderedSetAggregateFunctionExpression.

@Override
public <T> SelfRenderingSqmOrderedSetAggregateFunction<T> generateSqmOrderedSetAggregateFunctionExpression(List<? extends SqmTypedNode<?>> arguments, SqmPredicate filter, SqmOrderByClause withinGroupClause, ReturnableType<T> impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) {
    return new SelfRenderingInverseDistributionFunction<>(arguments, filter, withinGroupClause, impliedResultType, queryEngine) {

        @Override
        public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
            final Clause currentClause = walker.getCurrentClauseStack().getCurrent();
            if (currentClause == Clause.OVER) {
                return super.convertToSqlAst(walker);
            } else if (currentClause != Clause.SELECT) {
                throw new IllegalArgumentException("Can't emulate [" + getName() + "] in clause " + currentClause + ". Only the SELECT clause is supported!");
            }
            final ReturnableType<?> resultType = resolveResultType(walker.getCreationContext().getMappingMetamodel().getTypeConfiguration());
            List<SqlAstNode> arguments = resolveSqlAstArguments(getArguments(), walker);
            ArgumentsValidator argumentsValidator = getArgumentsValidator();
            if (argumentsValidator != null) {
                argumentsValidator.validateSqlTypes(arguments, getFunctionName());
            }
            List<SortSpecification> withinGroup;
            if (this.getWithinGroup() == null) {
                withinGroup = Collections.emptyList();
            } else {
                walker.getCurrentClauseStack().push(Clause.ORDER);
                try {
                    final List<SqmSortSpecification> sortSpecifications = this.getWithinGroup().getSortSpecifications();
                    withinGroup = new ArrayList<>(sortSpecifications.size());
                    for (SqmSortSpecification sortSpecification : sortSpecifications) {
                        final SortSpecification specification = (SortSpecification) walker.visitSortSpecification(sortSpecification);
                        if (specification != null) {
                            withinGroup.add(specification);
                        }
                    }
                } finally {
                    walker.getCurrentClauseStack().pop();
                }
            }
            final SelfRenderingFunctionSqlAstExpression function = new SelfRenderingOrderedSetAggregateFunctionSqlAstExpression(getFunctionName(), getRenderingSupport(), arguments, getFilter() == null ? null : (Predicate) getFilter().accept(walker), withinGroup, resultType, getMappingModelExpressible(walker, resultType));
            final Over<Object> windowFunction = new Over<>(function, new ArrayList<>(), Collections.emptyList());
            walker.registerQueryTransformer(new AggregateWindowEmulationQueryTransformer(windowFunction, withinGroup, null));
            return windowFunction;
        }
    };
}
Also used : SqlAstNode(org.hibernate.sql.ast.tree.SqlAstNode) SqmToSqlAstConverter(org.hibernate.query.sqm.sql.SqmToSqlAstConverter) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification) SqmPredicate(org.hibernate.query.sqm.tree.predicate.SqmPredicate) Predicate(org.hibernate.sql.ast.tree.predicate.Predicate) Over(org.hibernate.sql.ast.tree.expression.Over) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) SelfRenderingOrderedSetAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingOrderedSetAggregateFunctionSqlAstExpression) Clause(org.hibernate.sql.ast.Clause) SqmOrderByClause(org.hibernate.query.sqm.tree.select.SqmOrderByClause) ArgumentsValidator(org.hibernate.query.sqm.produce.function.ArgumentsValidator)

Example 8 with SortSpecification

use of org.hibernate.sql.ast.tree.select.SortSpecification in project hibernate-orm by hibernate.

the class BaseSqmToSqlAstConverter method visitOrderByOffsetAndFetch.

protected void visitOrderByOffsetAndFetch(SqmQueryPart<?> sqmQueryPart, QueryPart sqlQueryPart) {
    if (sqmQueryPart.getOrderByClause() != null) {
        currentClauseStack.push(Clause.ORDER);
        inferrableTypeAccessStack.push(() -> null);
        try {
            for (SqmSortSpecification sortSpecification : sqmQueryPart.getOrderByClause().getSortSpecifications()) {
                final SortSpecification specification = visitSortSpecification(sortSpecification);
                if (specification != null) {
                    sqlQueryPart.addSortSpecification(specification);
                }
            }
        } finally {
            inferrableTypeAccessStack.pop();
            currentClauseStack.pop();
        }
    }
    if (!containsCollectionFetches || !currentClauseStack.isEmpty()) {
        // Strip off the root offset and limit expressions in case the query contains collection fetches to retain
        // the proper cardinality. We could implement pagination for single select statements differently in this
        // case by using a subquery e.g. `... where alias in (select subAlias from ... limit ...)`
        // or use window functions e.g. `select ... from (select ..., dense_rank() over(order by ..., id) rn from ...) tmp where tmp.rn between ...`
        // but these transformations/translations are non-trivial and can be done later
        inferrableTypeAccessStack.push(() -> getTypeConfiguration().getBasicTypeForJavaType(Integer.class));
        sqlQueryPart.setOffsetClauseExpression(visitOffsetExpression(sqmQueryPart.getOffsetExpression()));
        if (sqmQueryPart.getFetchClauseType() == FetchClauseType.PERCENT_ONLY || sqmQueryPart.getFetchClauseType() == FetchClauseType.PERCENT_WITH_TIES) {
            inferrableTypeAccessStack.pop();
            inferrableTypeAccessStack.push(() -> getTypeConfiguration().getBasicTypeForJavaType(Double.class));
        }
        sqlQueryPart.setFetchClauseExpression(visitFetchExpression(sqmQueryPart.getFetchExpression()), sqmQueryPart.getFetchClauseType());
        inferrableTypeAccessStack.pop();
    }
}
Also used : BigInteger(java.math.BigInteger) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification)

Example 9 with SortSpecification

use of org.hibernate.sql.ast.tree.select.SortSpecification 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);
    }
}
Also used : SelfRenderingAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression) NavigablePath(org.hibernate.query.spi.NavigablePath) ConvertibleModelPart(org.hibernate.metamodel.mapping.ConvertibleModelPart) ModelPart(org.hibernate.metamodel.mapping.ModelPart) EntityValuedModelPart(org.hibernate.metamodel.mapping.EntityValuedModelPart) BasicValuedModelPart(org.hibernate.metamodel.mapping.BasicValuedModelPart) EmbeddableValuedModelPart(org.hibernate.metamodel.mapping.EmbeddableValuedModelPart) PluralAttributeMapping(org.hibernate.metamodel.mapping.PluralAttributeMapping) ArrayList(java.util.ArrayList) SqlSelection(org.hibernate.sql.ast.spi.SqlSelection) AbstractSqmSelfRenderingFunctionDescriptor(org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) SqlAstQueryPartProcessingStateImpl(org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl) EntityCollectionPart(org.hibernate.metamodel.mapping.internal.EntityCollectionPart) CollectionPart(org.hibernate.metamodel.mapping.CollectionPart) EmbeddedCollectionPart(org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart) VirtualTableGroup(org.hibernate.sql.ast.tree.from.VirtualTableGroup) LazyTableGroup(org.hibernate.sql.ast.tree.from.LazyTableGroup) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) CorrelatedTableGroup(org.hibernate.sql.ast.tree.from.CorrelatedTableGroup) CorrelatedPluralTableGroup(org.hibernate.sql.ast.tree.from.CorrelatedPluralTableGroup) PluralTableGroup(org.hibernate.sql.ast.tree.from.PluralTableGroup) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) BasicValuedModelPart(org.hibernate.metamodel.mapping.BasicValuedModelPart) EntityAssociationMapping(org.hibernate.metamodel.mapping.EntityAssociationMapping) QueryPartTableGroup(org.hibernate.sql.ast.tree.from.QueryPartTableGroup) FromClauseAccess(org.hibernate.sql.ast.spi.FromClauseAccess) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) BinaryArithmeticExpression(org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression) SqmModifiedSubQueryExpression(org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) SelfRenderingAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression) CaseSearchedExpression(org.hibernate.sql.ast.tree.expression.CaseSearchedExpression) SelfRenderingSqlFragmentExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression) Expression(org.hibernate.sql.ast.tree.expression.Expression) SelfRenderingExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingExpression) SqmExpression(org.hibernate.query.sqm.tree.expression.SqmExpression) CaseSimpleExpression(org.hibernate.sql.ast.tree.expression.CaseSimpleExpression) SqlSelectionExpression(org.hibernate.sql.ast.tree.expression.SqlSelectionExpression) ModifiedSubQueryExpression(org.hibernate.sql.ast.tree.expression.ModifiedSubQueryExpression) EmbeddableValuedModelPart(org.hibernate.metamodel.mapping.EmbeddableValuedModelPart) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) SqlTuple(org.hibernate.sql.ast.tree.expression.SqlTuple) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) SqmQuerySpec(org.hibernate.query.sqm.tree.select.SqmQuerySpec) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) QueryPartTableReference(org.hibernate.sql.ast.tree.from.QueryPartTableReference) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Example 10 with SortSpecification

use of org.hibernate.sql.ast.tree.select.SortSpecification in project hibernate-orm by hibernate.

the class HypotheticalSetWindowEmulation method generateSqmOrderedSetAggregateFunctionExpression.

@Override
public <T> SelfRenderingSqmOrderedSetAggregateFunction<T> generateSqmOrderedSetAggregateFunctionExpression(List<? extends SqmTypedNode<?>> arguments, SqmPredicate filter, SqmOrderByClause withinGroupClause, ReturnableType<T> impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) {
    return new SelfRenderingSqmOrderedSetAggregateFunction<>(this, this, arguments, filter, withinGroupClause, impliedResultType, getArgumentsValidator(), getReturnTypeResolver(), queryEngine.getCriteriaBuilder(), getName()) {

        @Override
        public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
            final Clause currentClause = walker.getCurrentClauseStack().getCurrent();
            if (currentClause == Clause.OVER) {
                return super.convertToSqlAst(walker);
            } else if (currentClause != Clause.SELECT) {
                throw new IllegalArgumentException("Can't emulate [" + getName() + "] in clause " + currentClause + ". Only the SELECT clause is supported!");
            }
            final ReturnableType<?> resultType = resolveResultType(walker.getCreationContext().getMappingMetamodel().getTypeConfiguration());
            List<SqlAstNode> arguments = resolveSqlAstArguments(getArguments(), walker);
            ArgumentsValidator argumentsValidator = getArgumentsValidator();
            if (argumentsValidator != null) {
                argumentsValidator.validateSqlTypes(arguments, getFunctionName());
            }
            List<SortSpecification> withinGroup;
            if (this.getWithinGroup() == null) {
                withinGroup = Collections.emptyList();
            } else {
                walker.getCurrentClauseStack().push(Clause.ORDER);
                try {
                    final List<SqmSortSpecification> sortSpecifications = this.getWithinGroup().getSortSpecifications();
                    withinGroup = new ArrayList<>(sortSpecifications.size());
                    for (SqmSortSpecification sortSpecification : sortSpecifications) {
                        final SortSpecification specification = (SortSpecification) walker.visitSortSpecification(sortSpecification);
                        if (specification != null) {
                            withinGroup.add(specification);
                        }
                    }
                } finally {
                    walker.getCurrentClauseStack().pop();
                }
            }
            final SelfRenderingFunctionSqlAstExpression function = new SelfRenderingOrderedSetAggregateFunctionSqlAstExpression(getFunctionName(), getRenderingSupport(), Collections.emptyList(), getFilter() == null ? null : (Predicate) getFilter().accept(walker), Collections.emptyList(), resultType, getMappingModelExpressible(walker, resultType));
            final Over<Object> windowFunction = new Over<>(function, new ArrayList<>(), withinGroup);
            walker.registerQueryTransformer(new AggregateWindowEmulationQueryTransformer(windowFunction, withinGroup, arguments));
            return windowFunction;
        }
    };
}
Also used : SqlAstNode(org.hibernate.sql.ast.tree.SqlAstNode) SqmToSqlAstConverter(org.hibernate.query.sqm.sql.SqmToSqlAstConverter) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification) SqmPredicate(org.hibernate.query.sqm.tree.predicate.SqmPredicate) Predicate(org.hibernate.sql.ast.tree.predicate.Predicate) Over(org.hibernate.sql.ast.tree.expression.Over) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) SqmSortSpecification(org.hibernate.query.sqm.tree.select.SqmSortSpecification) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) SelfRenderingOrderedSetAggregateFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingOrderedSetAggregateFunctionSqlAstExpression) Clause(org.hibernate.sql.ast.Clause) SqmOrderByClause(org.hibernate.query.sqm.tree.select.SqmOrderByClause) ArgumentsValidator(org.hibernate.query.sqm.produce.function.ArgumentsValidator) SelfRenderingSqmOrderedSetAggregateFunction(org.hibernate.query.sqm.function.SelfRenderingSqmOrderedSetAggregateFunction)

Aggregations

SortSpecification (org.hibernate.sql.ast.tree.select.SortSpecification)15 Expression (org.hibernate.sql.ast.tree.expression.Expression)9 ArrayList (java.util.ArrayList)6 SelfRenderingFunctionSqlAstExpression (org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression)6 SqmSortSpecification (org.hibernate.query.sqm.tree.select.SqmSortSpecification)6 ColumnReference (org.hibernate.sql.ast.tree.expression.ColumnReference)5 Over (org.hibernate.sql.ast.tree.expression.Over)5 List (java.util.List)4 SelfRenderingSqlFragmentExpression (org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression)4 QuerySpec (org.hibernate.sql.ast.tree.select.QuerySpec)4 Collections (java.util.Collections)3 Map (java.util.Map)3 SessionFactoryImplementor (org.hibernate.engine.spi.SessionFactoryImplementor)3 NavigablePath (org.hibernate.query.spi.NavigablePath)3 ComparisonOperator (org.hibernate.query.sqm.ComparisonOperator)3 SelfRenderingAggregateFunctionSqlAstExpression (org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression)3 JdbcParameter (org.hibernate.sql.ast.tree.expression.JdbcParameter)3 TableGroup (org.hibernate.sql.ast.tree.from.TableGroup)3 ComparisonPredicate (org.hibernate.sql.ast.tree.predicate.ComparisonPredicate)3 SqlSelectionImpl (org.hibernate.sql.results.internal.SqlSelectionImpl)3