Search in sources :

Example 1 with Expression

use of com.blazebit.persistence.parser.expression.Expression in project blaze-persistence by Blazebit.

the class OrderByManager method applyFrom.

String[] applyFrom(OrderByManager orderByManager, Map<String, Integer> identifierExpressionStringMap) {
    String[] identifierToUseSelectAliases = new String[identifierExpressionStringMap.size()];
    for (int i = 0; i < orderByManager.orderByInfos.size(); i++) {
        OrderByInfo info = orderByManager.orderByInfos.get(i);
        String potentialSelectAlias = info.getExpressionString();
        AliasInfo aliasInfo = orderByManager.aliasManager.getAliasInfo(potentialSelectAlias);
        Expression expression;
        if (aliasInfo instanceof SelectInfo) {
            SelectInfo selectInfo = (SelectInfo) aliasInfo;
            Integer selectItemIndex = identifierExpressionStringMap.get(selectInfo.getExpression().toString());
            if (selectItemIndex != null) {
                // We need to use the same alias as in the SQL because Hibernate for some reason does not resolve aliases in the order by clause of subqueries
                String alias = ColumnTruncFunction.SYNTHETIC_COLUMN_PREFIX + selectItemIndex;
                identifierToUseSelectAliases[selectItemIndex] = alias;
                expression = new PathExpression(new PropertyExpression(alias));
            } else {
                // We have an order by item with an alias that is not part of the identifier expression map
                Expression copiedSelectExpression = selectInfo.getExpression().copy(ExpressionCopyContext.EMPTY);
                if (selectInfo.getExpression() instanceof PathExpression) {
                    expression = copiedSelectExpression;
                } else {
                    String alias = aliasManager.generateRootAlias("_generated_alias");
                    selectManager.select(copiedSelectExpression, alias);
                    List<Expression> args = new ArrayList<>(2);
                    args.add(new PathExpression(new PropertyExpression(alias)));
                    args.add(new StringLiteral(alias));
                    expression = new FunctionExpression(AliasFunction.FUNCTION_NAME, args);
                }
            }
        } else {
            expression = info.getExpression().copy(ExpressionCopyContext.EMPTY);
        }
        orderBy(subqueryInitFactory.reattachSubqueries(expression, ClauseType.ORDER_BY), info.ascending, info.nullFirst);
    }
    return identifierToUseSelectAliases;
}
Also used : ArrayList(java.util.ArrayList) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) StringLiteral(com.blazebit.persistence.parser.expression.StringLiteral) WhenClauseExpression(com.blazebit.persistence.parser.expression.WhenClauseExpression) Expression(com.blazebit.persistence.parser.expression.Expression) GeneralCaseExpression(com.blazebit.persistence.parser.expression.GeneralCaseExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression)

Example 2 with Expression

use of com.blazebit.persistence.parser.expression.Expression in project blaze-persistence by Blazebit.

the class OrderByManager method splitEmbeddables.

void splitEmbeddables(JoinVisitor joinVisitor) {
    List<OrderByInfo> infos = orderByInfos;
    int size = infos.size();
    for (int i = 0; i < size; i++) {
        final OrderByInfo orderByInfo = infos.get(i);
        String potentialSelectAlias = orderByInfo.getExpressionString();
        AliasInfo aliasInfo = aliasManager.getAliasInfo(potentialSelectAlias);
        Expression expr;
        if (aliasInfo instanceof SelectInfo) {
            SelectInfo selectInfo = (SelectInfo) aliasInfo;
            expr = selectInfo.getExpression();
        } else {
            expr = orderByInfo.getExpression();
        }
        List<Expression> splittedOffExpressions = embeddableSplittingVisitor.splitOff(expr, false);
        if (splittedOffExpressions != null && !splittedOffExpressions.isEmpty()) {
            if (!jpaProvider.supportsSingleValuedAssociationIdExpressions() && joinVisitor != null) {
                ClauseType fromClause = joinVisitor.getFromClause();
                try {
                    joinVisitor.setFromClause(ClauseType.ORDER_BY);
                    for (int j = 0; j < splittedOffExpressions.size(); j++) {
                        splittedOffExpressions.get(j).accept(joinVisitor);
                    }
                } finally {
                    joinVisitor.setFromClause(fromClause);
                }
            }
            infos.set(i, new OrderByInfo(splittedOffExpressions.get(0), orderByInfo.ascending, orderByInfo.nullFirst));
            List<OrderByInfo> newOrderByInfos = new ArrayList<>(splittedOffExpressions.size() - 1);
            for (int j = 1; j < splittedOffExpressions.size(); j++) {
                newOrderByInfos.add(new OrderByInfo(splittedOffExpressions.get(j), orderByInfo.ascending, orderByInfo.nullFirst));
            }
            infos.addAll(i + 1, newOrderByInfos);
            size += newOrderByInfos.size();
        }
    }
}
Also used : WhenClauseExpression(com.blazebit.persistence.parser.expression.WhenClauseExpression) Expression(com.blazebit.persistence.parser.expression.Expression) GeneralCaseExpression(com.blazebit.persistence.parser.expression.GeneralCaseExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) ArrayList(java.util.ArrayList)

Example 3 with Expression

use of com.blazebit.persistence.parser.expression.Expression in project blaze-persistence by Blazebit.

the class OrderByManager method getOrderByExpressions.

List<OrderByExpression> getOrderByExpressions(boolean hasCollections, CompoundPredicate rootPredicate, Collection<ResolvedExpression> groupByClauses, JoinVisitor joinVisitor) {
    if (orderByInfos.isEmpty()) {
        return Collections.emptyList();
    }
    Set<String> clausesRequiredForResultUniqueness;
    if (groupByClauses.isEmpty()) {
        clausesRequiredForResultUniqueness = null;
    } else {
        clausesRequiredForResultUniqueness = new HashSet<>(groupByClauses.size());
        for (ResolvedExpression groupByClause : groupByClauses) {
            clausesRequiredForResultUniqueness.add(groupByClause.getExpressionString());
        }
    }
    List<OrderByExpression> realExpressions = new ArrayList<>(orderByInfos.size());
    List<OrderByInfo> infos = orderByInfos;
    int size = infos.size();
    boolean resultUnique = false;
    StringBuilder expressionStringBuilder = new StringBuilder();
    queryGenerator.setQueryBuffer(expressionStringBuilder);
    functionalDependencyAnalyzerVisitor.clear(rootPredicate, joinManager.getRoots().get(0), true);
    for (int i = 0; i < size; i++) {
        final OrderByInfo orderByInfo = infos.get(i);
        String expressionString = orderByInfo.getExpressionString();
        AliasInfo aliasInfo = aliasManager.getAliasInfo(expressionString);
        Expression expr;
        if (aliasInfo instanceof SelectInfo) {
            SelectInfo selectInfo = (SelectInfo) aliasInfo;
            expr = selectInfo.getExpression();
            if (clausesRequiredForResultUniqueness != null && !clausesRequiredForResultUniqueness.isEmpty()) {
                expressionStringBuilder.setLength(0);
                expr.accept(queryGenerator);
                clausesRequiredForResultUniqueness.remove(expressionStringBuilder.toString());
            }
        } else {
            expr = orderByInfo.getExpression();
            if (clausesRequiredForResultUniqueness != null && !clausesRequiredForResultUniqueness.isEmpty()) {
                expressionStringBuilder.setLength(0);
                expr.accept(queryGenerator);
                clausesRequiredForResultUniqueness.remove(expressionStringBuilder.toString());
            }
        }
        // We analyze the model and join node structure and also detect top-level EQ predicates that constantify attributes which makes them non-null
        boolean nullable = joinManager.hasFullJoin() || ExpressionUtils.isNullable(metamodel, functionalDependencyAnalyzerVisitor.getConstantifiedJoinNodeAttributeCollector(), expr);
        // Since we generate the null precedence emulation expressions, we must also generate them in the uniqueness determination code
        if (nullable && clausesRequiredForResultUniqueness != null && !clausesRequiredForResultUniqueness.isEmpty() && !jpaProvider.supportsNullPrecedenceExpression()) {
            expressionStringBuilder.insert(0, "CASE WHEN ");
            expressionStringBuilder.append(" IS NULL THEN ");
            if (orderByInfo.nullFirst) {
                expressionStringBuilder.append("0 ELSE 1 END");
            } else {
                expressionStringBuilder.append("1 ELSE 0 END");
            }
            clausesRequiredForResultUniqueness.remove(expressionStringBuilder.toString());
        }
        // Note that there are actually two notions of uniqueness that we have to check for
        // There is a result uniqueness which is relevant for the safety checks we do
        // and there is a also the general uniqueness which is what is relevant for keyset pagination
        // 
        // The general uniqueness can be inferred, when a path expression refers to a unique attribute and parent joins are "uniqueness preserving"
        // A join node is uniqueness preserving when it is a join of a one-to-one or more generally, when there is a top-level equality predicate between unique keys
        // Detecting top-level equality predicates is out of scope right now and will be done as part of #610
        // Normally, when there are multiple query roots, we can only determine uniqueness when query roots are somehow joined by a unique attributes
        // Since that is out of scope now, we require that there must be a single root in order for us to detect uniqueness properly
        boolean unique;
        List<Expression> splitOffExpressions;
        // Determining general uniqueness requires that no collection joins are involved in a query which is kind of guaranteed by design by the PaginatedCriteriaBuilder
        if (!joinManager.hasFullJoin() && joinManager.getRoots().size() == 1 && !hasCollections) {
            unique = functionalDependencyAnalyzerVisitor.analyzeFormsUniqueTuple(expr);
            splitOffExpressions = functionalDependencyAnalyzerVisitor.getSplittedOffExpressions();
        } else {
            unique = false;
            splitOffExpressions = embeddableSplittingVisitor.splitOff(expr, false);
        }
        resultUnique = !joinManager.hasFullJoin() && (resultUnique || unique || clausesRequiredForResultUniqueness != null && clausesRequiredForResultUniqueness.isEmpty());
        boolean resUnique = resultUnique || (i + 1) == size && functionalDependencyAnalyzerVisitor.isResultUnique();
        if (splitOffExpressions == null || splitOffExpressions.isEmpty()) {
            realExpressions.add(new OrderByExpression(orderByInfo.ascending, orderByInfo.nullFirst, expr, nullable, unique, resUnique));
        } else {
            if (jpaProvider.supportsSingleValuedAssociationIdExpressions() || joinVisitor == null) {
                for (Expression splitOffExpression : splitOffExpressions) {
                    realExpressions.add(new OrderByExpression(orderByInfo.ascending, orderByInfo.nullFirst, splitOffExpression, nullable, unique, resUnique));
                }
            } else {
                for (Expression splitOffExpression : splitOffExpressions) {
                    splitOffExpression.accept(joinVisitor);
                    realExpressions.add(new OrderByExpression(orderByInfo.ascending, orderByInfo.nullFirst, splitOffExpression, nullable, unique, resUnique));
                }
            }
        }
    }
    queryGenerator.setQueryBuffer(null);
    return realExpressions;
}
Also used : ArrayList(java.util.ArrayList) WhenClauseExpression(com.blazebit.persistence.parser.expression.WhenClauseExpression) Expression(com.blazebit.persistence.parser.expression.Expression) GeneralCaseExpression(com.blazebit.persistence.parser.expression.GeneralCaseExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression)

Example 4 with Expression

use of com.blazebit.persistence.parser.expression.Expression in project blaze-persistence by Blazebit.

the class OrderByManager method buildImplicitGroupByClauses.

/**
 * Builds the clauses needed for the group by clause for a query that uses aggregate functions to work.
 *
 * @return
 */
void buildImplicitGroupByClauses(GroupByManager groupByManager, boolean hasGroupBy, JoinVisitor joinVisitor) {
    if (orderByInfos.isEmpty()) {
        return;
    }
    SimpleQueryGenerator.BooleanLiteralRenderingContext oldBooleanLiteralRenderingContext = queryGenerator.setBooleanLiteralRenderingContext(SimpleQueryGenerator.BooleanLiteralRenderingContext.CASE_WHEN);
    StringBuilder sb = new StringBuilder();
    List<OrderByInfo> infos = orderByInfos;
    boolean hasFullJoin = !jpaProvider.supportsNullPrecedenceExpression() && joinManager.hasFullJoin();
    int size = infos.size();
    for (int i = 0; i < size; i++) {
        final OrderByInfo orderByInfo = infos.get(i);
        String potentialSelectAlias = orderByInfo.getExpressionString();
        AliasInfo aliasInfo = aliasManager.getAliasInfo(potentialSelectAlias);
        Expression expr;
        if (aliasInfo instanceof SelectInfo) {
            SelectInfo selectInfo = (SelectInfo) aliasInfo;
            expr = selectInfo.getExpression();
        } else {
            expr = orderByInfo.getExpression();
        }
        Set<Expression> extractedGroupByExpressions = groupByExpressionGatheringVisitor.extractGroupByExpressions(expr, getClauseType());
        if (!extractedGroupByExpressions.isEmpty()) {
            queryGenerator.setClauseType(ClauseType.GROUP_BY);
            queryGenerator.setQueryBuffer(sb);
            for (Expression extractedExpression : extractedGroupByExpressions) {
                sb.setLength(0);
                queryGenerator.generate(extractedExpression);
                String expressionString = sb.toString();
                if (!jpaProvider.supportsNullPrecedenceExpression()) {
                    boolean nullable = hasFullJoin || ExpressionUtils.isNullable(metamodel, functionalDependencyAnalyzerVisitor.getConstantifiedJoinNodeAttributeCollector(), extractedExpression);
                    Expression resultExpression;
                    Expression defaultExpression;
                    if (nullable) {
                        sb.insert(0, "CASE WHEN ");
                        sb.append(" IS NULL THEN ");
                        if (orderByInfo.nullFirst) {
                            resultExpression = new NumericLiteral("0", NumericType.INTEGER);
                            defaultExpression = new NumericLiteral("1", NumericType.INTEGER);
                            sb.append("0 ELSE 1 END");
                        } else {
                            resultExpression = new NumericLiteral("1", NumericType.INTEGER);
                            defaultExpression = new NumericLiteral("0", NumericType.INTEGER);
                            sb.append("1 ELSE 0 END");
                        }
                        List<WhenClauseExpression> whenClauses = new ArrayList<>(1);
                        whenClauses.add(new WhenClauseExpression(new IsNullPredicate(extractedExpression.copy(ExpressionCopyContext.CLONE)), resultExpression));
                        Expression nullEmulationExpression = new GeneralCaseExpression(whenClauses, defaultExpression);
                        String nullPrecedenceEmulationExpression = sb.toString();
                        groupByManager.collect(new ResolvedExpression(nullPrecedenceEmulationExpression, nullEmulationExpression), ClauseType.ORDER_BY, hasGroupBy, joinVisitor);
                    }
                }
                groupByManager.collect(new ResolvedExpression(expressionString, extractedExpression), ClauseType.ORDER_BY, hasGroupBy, joinVisitor);
            }
            queryGenerator.setClauseType(null);
        }
    }
    queryGenerator.setBooleanLiteralRenderingContext(oldBooleanLiteralRenderingContext);
    groupByExpressionGatheringVisitor.clear();
}
Also used : WhenClauseExpression(com.blazebit.persistence.parser.expression.WhenClauseExpression) NumericLiteral(com.blazebit.persistence.parser.expression.NumericLiteral) ArrayList(java.util.ArrayList) WhenClauseExpression(com.blazebit.persistence.parser.expression.WhenClauseExpression) Expression(com.blazebit.persistence.parser.expression.Expression) GeneralCaseExpression(com.blazebit.persistence.parser.expression.GeneralCaseExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) IsNullPredicate(com.blazebit.persistence.parser.predicate.IsNullPredicate) GeneralCaseExpression(com.blazebit.persistence.parser.expression.GeneralCaseExpression) SimpleQueryGenerator(com.blazebit.persistence.parser.SimpleQueryGenerator)

Example 5 with Expression

use of com.blazebit.persistence.parser.expression.Expression in project blaze-persistence by Blazebit.

the class JpaUtils method getAttributeForJoining.

public static AttributeHolder getAttributeForJoining(EntityMetamodel metamodel, PathExpression expression) {
    JoinNode expressionBaseNode = ((JoinNode) expression.getPathReference().getBaseNode());
    Expression p = expression.getExpressions().get(0);
    while (!(p instanceof PropertyExpression)) {
        if (p instanceof PathExpression) {
            p = ((PathExpression) p).getExpressions().get(0);
        } else if (p instanceof QualifiedExpression) {
            p = ((QualifiedExpression) p).getPath().getExpressions().get(0);
        } else if (p instanceof ArrayExpression) {
            p = ((ArrayExpression) p).getBase();
        } else {
            p = ((TreatExpression) p).getExpression();
        }
    }
    String firstElementString = p.toString();
    String baseNodeAlias;
    JoinNode baseNode = expressionBaseNode;
    do {
        baseNodeAlias = baseNode.getAlias();
    } while (!firstElementString.equals(baseNodeAlias) && (baseNode = baseNode.getParent()) != null);
    if (baseNode == null) {
        baseNodeAlias = null;
        if (expressionBaseNode.getParent() == null) {
            baseNode = expressionBaseNode;
        } else {
            baseNode = expressionBaseNode.getParent();
        }
    }
    return getAttributeForJoining(metamodel, baseNode.getNodeType(), expression, baseNodeAlias);
}
Also used : PathExpression(com.blazebit.persistence.parser.expression.PathExpression) QualifiedExpression(com.blazebit.persistence.parser.expression.QualifiedExpression) Expression(com.blazebit.persistence.parser.expression.Expression) QualifiedExpression(com.blazebit.persistence.parser.expression.QualifiedExpression) TreatExpression(com.blazebit.persistence.parser.expression.TreatExpression) ParameterExpression(com.blazebit.persistence.parser.expression.ParameterExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) ArrayExpression(com.blazebit.persistence.parser.expression.ArrayExpression) NullExpression(com.blazebit.persistence.parser.expression.NullExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) SubqueryExpression(com.blazebit.persistence.parser.expression.SubqueryExpression) ArrayExpression(com.blazebit.persistence.parser.expression.ArrayExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression)

Aggregations

Expression (com.blazebit.persistence.parser.expression.Expression)119 PathExpression (com.blazebit.persistence.parser.expression.PathExpression)78 SubqueryExpression (com.blazebit.persistence.parser.expression.SubqueryExpression)67 FunctionExpression (com.blazebit.persistence.parser.expression.FunctionExpression)51 ParameterExpression (com.blazebit.persistence.parser.expression.ParameterExpression)51 PropertyExpression (com.blazebit.persistence.parser.expression.PropertyExpression)49 PathElementExpression (com.blazebit.persistence.parser.expression.PathElementExpression)40 ArrayExpression (com.blazebit.persistence.parser.expression.ArrayExpression)37 MapKeyExpression (com.blazebit.persistence.parser.expression.MapKeyExpression)32 ListIndexExpression (com.blazebit.persistence.parser.expression.ListIndexExpression)25 MapValueExpression (com.blazebit.persistence.parser.expression.MapValueExpression)24 TreatExpression (com.blazebit.persistence.parser.expression.TreatExpression)23 ArrayList (java.util.ArrayList)21 GeneralCaseExpression (com.blazebit.persistence.parser.expression.GeneralCaseExpression)20 MapEntryExpression (com.blazebit.persistence.parser.expression.MapEntryExpression)16 NullExpression (com.blazebit.persistence.parser.expression.NullExpression)16 QualifiedExpression (com.blazebit.persistence.parser.expression.QualifiedExpression)13 WhenClauseExpression (com.blazebit.persistence.parser.expression.WhenClauseExpression)13 ArithmeticExpression (com.blazebit.persistence.parser.expression.ArithmeticExpression)12 AggregateExpression (com.blazebit.persistence.parser.expression.AggregateExpression)10