Search in sources :

Example 1 with OrderByExpression

use of com.blazebit.persistence.impl.OrderByExpression in project blaze-persistence by Blazebit.

the class KeysetManager method buildOptimizedKeysetPredicate.

public void buildOptimizedKeysetPredicate(StringBuilder sb, int positionalOffset) {
    KeysetLink keysetLink = getKeysetLink();
    KeysetMode keysetMode = keysetLink.getKeysetMode();
    Keyset keyset = keysetLink.getKeyset();
    Serializable[] key = keyset.getTuple();
    OrderByExpression extractedNonNullableExpression = null;
    if (key != null) {
        boolean hasNullableOrderBys = false;
        // TODO: Determine if order by expression has parameter as that will ruin reordering of expressions in row value constructor
        boolean hasParameterInOrderBy = false;
        for (OrderByExpression orderByExpression : orderByExpressions) {
            if (orderByExpression.isNullable()) {
                hasNullableOrderBys = true;
                break;
            }
        }
        extractedNonNullableExpression = orderByExpressions.get(0);
        // if all order bys are non-nullable because null elements would break the row value comparison.
        if (hasNullableOrderBys || hasParameterInOrderBy || !dbmsDialect.supportsFullRowValueComparison() || !jpaProvider.supportsCustomFunctions()) {
            // Under certain conditions, we cannot render an optimized form because we would need to include
            // null checks involving disjunction on the top predicate level which would contradict the main idea of the
            // optimization.
            boolean optimizationAllowed = !extractedNonNullableExpression.isNullable() || keysetMode == KeysetMode.NEXT && extractedNonNullableExpression.isNullFirst() && key[0] != null || keysetMode == KeysetMode.PREVIOUS && !extractedNonNullableExpression.isNullFirst() && key[0] != null;
            if (optimizationAllowed) {
                applyOptimizedKeysetNotNullItem(extractedNonNullableExpression, sb, 0, key[0], keysetMode, false, positionalOffset);
                if (orderByExpressions.size() > 1) {
                    sb.append(" AND NOT (");
                    applyKeysetItem(sb, extractedNonNullableExpression.getExpression(), "=", 0, key[0], positionalOffset);
                    sb.append(" AND ");
                    buildOptimizedPredicate0(keysetMode, key, sb, orderByExpressions, positionalOffset);
                    sb.append(")");
                }
            } else {
                buildKeysetPredicate0(keysetMode, key, sb, orderByExpressions, positionalOffset);
            }
        } else {
            // we can use row value constructor syntax
            // the rendering is heavily bound to the way this is parsed in RowValueComparisonFunction
            queryGenerator.setClauseType(ClauseType.WHERE);
            queryGenerator.setQueryBuffer(sb);
            queryGenerator.setClauseType(null);
            sb.append(jpaProvider.getCustomFunctionInvocation(RowValueComparisonFunction.FUNCTION_NAME, 1)).append('\'').append(keysetMode == KeysetMode.SAME ? "<=" : "<").append('\'');
            for (int i = 0; i < orderByExpressions.size(); i++) {
                OrderByExpression orderByExpression = orderByExpressions.get(i);
                sb.append(",CASE WHEN (1=NULLIF(1,1) AND ");
                if (orderByExpression.isDescending() && keysetMode != KeysetMode.PREVIOUS || orderByExpression.isAscending() && keysetMode == KeysetMode.PREVIOUS) {
                    // Placeholder is needed as we need to render the parameter at the end to retain JDBC parameter order
                    sb.append("1=NULLIF(1,1)");
                } else {
                    applyKeysetParameter(sb, i, key[i], positionalOffset);
                    sb.append('=');
                    queryGenerator.generate(orderByExpression.getExpression());
                }
                sb.append(") THEN 1 ELSE 0 END");
            }
            // We have to render right hand side parameters at the end to retain the correct order
            for (int i = 0; i < orderByExpressions.size(); i++) {
                OrderByExpression orderByExpression = orderByExpressions.get(i);
                if (orderByExpression.isDescending() && keysetMode != KeysetMode.PREVIOUS || orderByExpression.isAscending() && keysetMode == KeysetMode.PREVIOUS) {
                    sb.append(",CASE WHEN (1=NULLIF(1,1) AND ");
                    queryGenerator.generate(orderByExpression.getExpression());
                    sb.append('=');
                    applyKeysetParameter(sb, i, key[i], positionalOffset);
                    sb.append(") THEN 1 ELSE 0 END");
                }
            }
            sb.append(") = 0");
        }
    }
}
Also used : Keyset(com.blazebit.persistence.Keyset) Serializable(java.io.Serializable) OrderByExpression(com.blazebit.persistence.impl.OrderByExpression)

Example 2 with OrderByExpression

use of com.blazebit.persistence.impl.OrderByExpression in project blaze-persistence by Blazebit.

the class KeysetManager method buildKeysetPredicate0.

private void buildKeysetPredicate0(KeysetMode keysetMode, Serializable[] key, StringBuilder sb, List<OrderByExpression> orderByExpressions, int positionalOffset) {
    int expressionCount = orderByExpressions.size();
    boolean generateEqualPredicate = true;
    int brackets = 0;
    SimpleQueryGenerator.BooleanLiteralRenderingContext oldBooleanLiteralRenderingContext = queryGenerator.setBooleanLiteralRenderingContext(SimpleQueryGenerator.BooleanLiteralRenderingContext.CASE_WHEN);
    // We wrap the whole thing in brackets
    brackets++;
    sb.append('(');
    for (int i = 0; i < expressionCount; i++) {
        boolean isNotLast = i + 1 != expressionCount;
        OrderByExpression orderByExpr = orderByExpressions.get(i);
        Expression expr = orderByExpr.getExpression();
        if (orderByExpr.isNullable()) {
            boolean isPrevious = keysetMode == KeysetMode.PREVIOUS;
            if (key[i] == null) {
                if (orderByExpr.isNullFirst() == isPrevious) {
                    // Case for previous and null first or not previous and null last
                    generateEqualPredicate = false;
                    applyKeysetNullItem(sb, expr, false);
                } else {
                    // Case for previous and null last or not previous and null first
                    applyKeysetNullItem(sb, expr, true);
                }
            } else {
                if (orderByExpr.isNullFirst() == isPrevious) {
                    // Case for previous and null first or not previous and null last
                    sb.append('(');
                    applyKeysetNotNullableItem(orderByExpr, sb, i, key[i], keysetMode, !isNotLast, positionalOffset);
                    sb.append(" OR ");
                    applyKeysetNullItem(sb, expr, false);
                    sb.append(')');
                } else {
                    // Case for previous and null last or not previous and null first
                    applyKeysetNotNullableItem(orderByExpr, sb, i, key[i], keysetMode, !isNotLast, positionalOffset);
                }
            }
        } else {
            applyKeysetNotNullableItem(orderByExpr, sb, i, key[i], keysetMode, !isNotLast, positionalOffset);
        }
        if (isNotLast) {
            if (generateEqualPredicate) {
                brackets++;
                sb.append(" OR (");
                if (key[i] == null) {
                    applyKeysetNullItem(sb, expr, false);
                } else {
                    applyKeysetItem(sb, expr, "=", i, key[i], positionalOffset);
                }
            }
            sb.append(" AND ");
            if (i + 2 != expressionCount) {
                brackets++;
                sb.append('(');
            }
            generateEqualPredicate = true;
        }
    }
    for (int i = 0; i < brackets; i++) {
        sb.append(')');
    }
    queryGenerator.setBooleanLiteralRenderingContext(oldBooleanLiteralRenderingContext);
}
Also used : OrderByExpression(com.blazebit.persistence.impl.OrderByExpression) Expression(com.blazebit.persistence.parser.expression.Expression) OrderByExpression(com.blazebit.persistence.impl.OrderByExpression) SimpleQueryGenerator(com.blazebit.persistence.parser.SimpleQueryGenerator)

Example 3 with OrderByExpression

use of com.blazebit.persistence.impl.OrderByExpression in project blaze-persistence by Blazebit.

the class KeysetManager method buildOptimizedPredicate0.

private void buildOptimizedPredicate0(KeysetMode keysetMode, Serializable[] key, StringBuilder sb, List<OrderByExpression> orderByExpressions, int positionalOffset) {
    int expressionCount = orderByExpressions.size();
    int brackets = 1;
    sb.append('(');
    SimpleQueryGenerator.BooleanLiteralRenderingContext oldBooleanLiteralRenderingContext = queryGenerator.setBooleanLiteralRenderingContext(SimpleQueryGenerator.BooleanLiteralRenderingContext.CASE_WHEN);
    // WHERE firstOrderBy <= :keyset AND NOT(firstOrderBy = :keyset AND <predicate>)
    for (int i = 1; i < expressionCount; i++) {
        boolean itemRendered = true;
        boolean isNotLast = i + 1 != expressionCount;
        OrderByExpression orderByExpr = orderByExpressions.get(i);
        Expression expr = orderByExpr.getExpression();
        if (orderByExpr.isNullable()) {
            if (key[i] == null) {
                if ((keysetMode == KeysetMode.PREVIOUS) == orderByExpr.isNullFirst()) {
                    // we need to explicitely exclude non-null values
                    applyKeysetNullItem(sb, expr, true);
                } else {
                    itemRendered = false;
                }
            } else {
                if ((keysetMode == KeysetMode.NEXT) == orderByExpr.isNullFirst()) {
                    applyOptimizedKeysetNotNullItem(orderByExpr, sb, i, key[i], keysetMode, true, positionalOffset);
                } else {
                    applyKeysetNullItem(sb, expr, true);
                    sb.append(" AND ");
                    applyOptimizedKeysetNotNullItem(orderByExpr, sb, i, key[i], keysetMode, true, positionalOffset);
                }
            }
        } else {
            applyOptimizedKeysetNotNullItem(orderByExpr, sb, i, key[i], keysetMode, true, positionalOffset);
        }
        if (isNotLast) {
            if (itemRendered) {
                brackets++;
                sb.append(" OR (");
            }
            if (key[i] == null) {
                applyKeysetNullItem(sb, expr, false);
            } else {
                if (orderByExpr.isNullable() && (keysetMode == KeysetMode.PREVIOUS) == orderByExpr.isNullFirst()) {
                    applyKeysetNullItem(sb, expr, true);
                    sb.append(" AND ");
                }
                applyKeysetItem(sb, expr, "=", i, key[i], positionalOffset);
            }
            sb.append(" AND ");
            if (i + 2 != expressionCount) {
                brackets++;
                sb.append('(');
            }
        }
    }
    for (int i = 0; i < brackets; i++) {
        sb.append(')');
    }
    queryGenerator.setBooleanLiteralRenderingContext(oldBooleanLiteralRenderingContext);
}
Also used : OrderByExpression(com.blazebit.persistence.impl.OrderByExpression) Expression(com.blazebit.persistence.parser.expression.Expression) OrderByExpression(com.blazebit.persistence.impl.OrderByExpression) SimpleQueryGenerator(com.blazebit.persistence.parser.SimpleQueryGenerator)

Aggregations

OrderByExpression (com.blazebit.persistence.impl.OrderByExpression)3 SimpleQueryGenerator (com.blazebit.persistence.parser.SimpleQueryGenerator)2 Expression (com.blazebit.persistence.parser.expression.Expression)2 Keyset (com.blazebit.persistence.Keyset)1 Serializable (java.io.Serializable)1