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");
}
}
}
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);
}
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);
}
Aggregations