Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions core/src/main/java/org/apache/calcite/rex/RexCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.calcite.sql.type.SqlTypeUtil;
import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Sarg;

import com.google.common.collect.ImmutableList;

Expand Down Expand Up @@ -196,6 +197,10 @@ private boolean digestWithType() {
case IS_TRUE:
case CAST:
return operands.get(0).isAlwaysTrue();
case SEARCH:
final Sarg sarg = ((RexLiteral) operands.get(1)).getValueAs(Sarg.class);
return sarg.isAll()
&& (sarg.containsNull || !operands.get(0).getType().isNullable());
default:
return false;
}
Expand All @@ -213,6 +218,10 @@ private boolean digestWithType() {
case IS_TRUE:
case CAST:
return operands.get(0).isAlwaysFalse();
case SEARCH:
final Sarg sarg = ((RexLiteral) operands.get(1)).getValueAs(Sarg.class);
return sarg.isNone()
&& (!sarg.containsNull || !operands.get(0).getType().isNullable());
default:
return false;
}
Expand Down
19 changes: 18 additions & 1 deletion core/src/main/java/org/apache/calcite/rex/RexSimplify.java
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,18 @@ private RexNode simplifyNot(RexCall call, RexUnknownAs unknownAs) {
case NOT:
// NOT NOT x ==> x
return simplify(((RexCall) a).getOperands().get(0), unknownAs);
case SEARCH:
// NOT SEARCH(x, Sarg[(-inf, 10) OR NULL) ==> SEARCH(x, Sarg[[10, +inf)])
final RexCall call2 = (RexCall) a;
final RexNode ref = call2.operands.get(0);
final RexLiteral literal = (RexLiteral) call2.operands.get(1);
final Sarg sarg = literal.getValueAs(Sarg.class);
return simplifySearch(
call2.clone(call2.type,
ImmutableList.of(ref,
rexBuilder.makeLiteral(sarg.negate(), literal.getType(),
literal.getTypeName()))),
unknownAs.negate());
case LITERAL:
if (a.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
&& !RexLiteral.isNullLiteral(a)) {
Expand Down Expand Up @@ -2651,7 +2663,7 @@ private boolean accept1(RexNode e, SqlKind kind,
map.computeIfAbsent(e, e2 ->
addFluent(newTerms, new RexSargBuilder(e2, rexBuilder, negate)));
if (negate) {
kind = kind.negateNullSafe();
kind = kind.negateNullSafe2();
}
final Comparable value = literal.getValueAs(Comparable.class);
switch (kind) {
Expand Down Expand Up @@ -2687,6 +2699,7 @@ private boolean accept1(RexNode e, SqlKind kind,
} else {
++b.notNullTermCount;
}
b.addAll();
return true;
case SEARCH:
final Sarg sarg = literal.getValueAs(Sarg.class);
Expand Down Expand Up @@ -2790,6 +2803,10 @@ <C extends Comparable<C>> Sarg<C> build(boolean negate) {
throw new UnsupportedOperationException();
}

void addAll() {
rangeSet.add(Range.all());
}

void addRange(Range<Comparable> range, RelDataType type) {
types.add(type);
rangeSet.add(range);
Expand Down
84 changes: 61 additions & 23 deletions core/src/main/java/org/apache/calcite/rex/RexUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -565,32 +565,36 @@ public static RexFinder find(final RexInputRef ref) {
};
}

/** Expands calls to {@link SqlStdOperatorTable#SEARCH} in an expression. */
public static RexNode expandSearch(RexBuilder rexBuilder,
@Nullable RexProgram program, RexNode node) {
final RexShuttle shuttle = new RexShuttle() {
@Override public RexNode visitCall(RexCall call) {
switch (call.getKind()) {
case SEARCH:
return visitSearch(rexBuilder, program, call);
default:
return super.visitCall(call);
}
}
};
return node.accept(shuttle);
return node.accept(searchShuttle(rexBuilder, program, -1));
}

/** Creates a shuttle that expands calls to
* {@link SqlStdOperatorTable#SEARCH}.
*
* <p>If {@code maxComplexity} is non-negative, a {@link Sarg} whose
* complexity is greater than {@code maxComplexity} is retained (not
* expanded); this gives a means to simplify simple expressions such as
* {@code x IS NULL} or {@code x > 10} while keeping more complex expressions
* such as {@code x IN (3, 5, 7) OR x IS NULL} as a Sarg. */
public static RexShuttle searchShuttle(RexBuilder rexBuilder,
RexProgram program, int maxComplexity) {
return new SearchExpandingShuttle(program, rexBuilder, maxComplexity);
}

@SuppressWarnings("BetaApi")
private static <C extends Comparable<C>> RexNode
visitSearch(RexBuilder rexBuilder,
@Nullable RexProgram program, RexCall call) {
final RexNode ref = call.operands.get(0);
final RexLiteral literal =
(RexLiteral) deref(program, call.operands.get(1));
@SuppressWarnings("unchecked")
final Sarg<C> sarg = literal.getValueAs(Sarg.class);
private static <C extends Comparable<C>> RexNode sargRef(
RexBuilder rexBuilder, RexNode ref, Sarg<C> sarg, RelDataType type) {
if (sarg.isAll()) {
if (sarg.containsNull) {
return rexBuilder.makeLiteral(true);
} else {
return rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, ref);
}
}
final List<RexNode> orList = new ArrayList<>();

if (sarg.containsNull) {
orList.add(rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, ref));
}
Expand All @@ -600,19 +604,19 @@ public static RexNode expandSearch(RexBuilder rexBuilder,
orList.add(
rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, ref,
rexBuilder.makeLiteral(range.lowerEndpoint(),
literal.getType(), true, true))));
type, true, true))));
} else if (sarg.isComplementedPoints()) {
// Generate 'ref <> value1 AND ... AND ref <> valueN'
final List<RexNode> list = sarg.rangeSet.complement().asRanges().stream()
.map(range ->
rexBuilder.makeCall(SqlStdOperatorTable.NOT_EQUALS, ref,
rexBuilder.makeLiteral(range.lowerEndpoint(),
literal.getType(), true, true)))
type, true, true)))
.collect(Util.toImmutableList());
orList.add(composeConjunction(rexBuilder, list));
} else {
final RangeSets.Consumer<C> consumer =
new RangeToRex<>(ref, orList, rexBuilder, literal.getType());
new RangeToRex<>(ref, orList, rexBuilder, type);
RangeSets.forEach(sarg.rangeSet, consumer);
}
return composeDisjunction(rexBuilder, orList);
Expand Down Expand Up @@ -2987,4 +2991,38 @@ private RexNode op(SqlOperator op, C value) {
op(SqlStdOperatorTable.LESS_THAN, upper));
}
}

/** Shuttle that expands calls to
* {@link org.apache.calcite.sql.fun.SqlStdOperatorTable#SEARCH}.
*
* <p>Calls whose complexity is greater than {@link #maxComplexity}
* are retained (not expanded). */
private static class SearchExpandingShuttle extends RexShuttle {
private final RexBuilder rexBuilder;
private final RexProgram program;
private final int maxComplexity;

SearchExpandingShuttle(RexProgram program, RexBuilder rexBuilder,
int maxComplexity) {
this.program = program;
this.rexBuilder = rexBuilder;
this.maxComplexity = maxComplexity;
}

@Override public RexNode visitCall(RexCall call) {
switch (call.getKind()) {
case SEARCH:
final RexNode ref = call.operands.get(0);
final RexLiteral literal =
(RexLiteral) deref(program, call.operands.get(1));
final Sarg sarg = literal.getValueAs(Sarg.class);
if (maxComplexity < 0 || sarg.complexity() < maxComplexity) {
return sargRef(rexBuilder, ref, sarg, literal.getType());
}
// Sarg is complex (therefore useful); fall through
default:
return super.visitCall(call);
}
}
}
}
3 changes: 3 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.calcite.plan.Context;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.sql.fun.SqlBasicAggFunction;
import org.apache.calcite.sql.type.SqlOperandTypeChecker;
import org.apache.calcite.sql.type.SqlOperandTypeInference;
import org.apache.calcite.sql.type.SqlReturnTypeInference;
Expand All @@ -33,6 +34,8 @@
/**
* Abstract base class for the definition of an aggregate function: an operator
* which aggregates sets of values into a result.
*
* @see SqlBasicAggFunction
*/
public abstract class SqlAggFunction extends SqlFunction implements Context {
private final boolean requiresOrder;
Expand Down
16 changes: 15 additions & 1 deletion core/src/main/java/org/apache/calcite/sql/SqlKind.java
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,9 @@ public enum SqlKind {
/** The {@code STRING_AGG} aggregate function. */
STRING_AGG,

/** The {@code COUNTIF} aggregate function. */
COUNTIF,

/** The {@code ARRAY_AGG} aggregate function. */
ARRAY_AGG,

Expand Down Expand Up @@ -1040,7 +1043,7 @@ public enum SqlKind {
AVG, STDDEV_POP, STDDEV_SAMP, VAR_POP, VAR_SAMP, NTILE, COLLECT,
FUSION, SINGLE_VALUE, ROW_NUMBER, RANK, PERCENT_RANK, DENSE_RANK,
CUME_DIST, JSON_ARRAYAGG, JSON_OBJECTAGG, BIT_AND, BIT_OR, BIT_XOR,
LISTAGG, STRING_AGG, ARRAY_AGG, ARRAY_CONCAT_AGG,
LISTAGG, STRING_AGG, ARRAY_AGG, ARRAY_CONCAT_AGG, COUNTIF,
INTERSECTION, ANY_VALUE);

/**
Expand Down Expand Up @@ -1382,6 +1385,17 @@ public SqlKind negateNullSafe() {
}
}

public SqlKind negateNullSafe2() {
switch (this) {
case IS_NOT_NULL:
return IS_NULL;
case IS_NULL:
return IS_NOT_NULL;
default:
return this.negateNullSafe();
}
}

/**
* Returns whether this {@code SqlKind} belongs to a given category.
*
Expand Down
12 changes: 9 additions & 3 deletions core/src/main/java/org/apache/calcite/sql/SqlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static org.apache.calcite.util.Static.RESOURCE;

Expand All @@ -75,9 +77,13 @@
public abstract class SqlUtil {
//~ Methods ----------------------------------------------------------------

static SqlNode andExpressions(
SqlNode node1,
SqlNode node2) {
/** Returns the AND of two expressions.
*
* <p>If {@code node1} is null, returns {@code node2}.
* Flattens if either node is an AND. */
public static @Nonnull SqlNode andExpressions(
@Nullable SqlNode node1,
@Nonnull SqlNode node2) {
if (node1 == null) {
return node2;
}
Expand Down
Loading