use of org.apache.calcite.rex.RexExecutor in project calcite by apache.
the class RelOptUtil method containsNullableFields.
/**
* Determines whether any of the fields in a given relational expression may
* contain null values, taking into account constraints on the field types and
* also deduced predicates.
*
* <p>The method is cautious: It may sometimes return {@code true} when the
* actual answer is {@code false}. In particular, it does this when there
* is no executor, or the executor is not a sub-class of
* {@link RexExecutorImpl}.
*/
private static boolean containsNullableFields(RelNode r) {
final RexBuilder rexBuilder = r.getCluster().getRexBuilder();
final RelDataType rowType = r.getRowType();
final List<RexNode> list = new ArrayList<>();
final RelMetadataQuery mq = r.getCluster().getMetadataQuery();
for (RelDataTypeField field : rowType.getFieldList()) {
if (field.getType().isNullable()) {
list.add(rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, rexBuilder.makeInputRef(field.getType(), field.getIndex())));
}
}
if (list.isEmpty()) {
// All columns are declared NOT NULL.
return false;
}
final RelOptPredicateList predicates = mq.getPulledUpPredicates(r);
if (predicates.pulledUpPredicates.isEmpty()) {
// declared NULL are really NOT NULL.
return true;
}
final RexExecutor executor = r.getCluster().getPlanner().getExecutor();
if (!(executor instanceof RexExecutorImpl)) {
// Cannot proceed without an executor.
return true;
}
final RexImplicationChecker checker = new RexImplicationChecker(rexBuilder, (RexExecutorImpl) executor, rowType);
final RexNode first = RexUtil.composeConjunction(rexBuilder, predicates.pulledUpPredicates, false);
final RexNode second = RexUtil.composeConjunction(rexBuilder, list, false);
// It does, so we have no nullable columns.
return !checker.implies(first, second);
}
use of org.apache.calcite.rex.RexExecutor in project calcite by apache.
the class ReduceExpressionsRule method reduceExpressions.
/**
* Reduces a list of expressions.
*
* <p>The {@code matchNullability} flag comes into play when reducing a
* expression whose type is nullable. Suppose we are reducing an expression
* {@code CASE WHEN 'a' = 'a' THEN 1 ELSE NULL END}. Before reduction the
* type is {@code INTEGER} (nullable), but after reduction the literal 1 has
* type {@code INTEGER NOT NULL}.
*
* <p>In some situations it is more important to preserve types; in this
* case you should use {@code matchNullability = true} (which used to be
* the default behavior of this method), and it will cast the literal to
* {@code INTEGER} (nullable).
*
* <p>In other situations, you would rather propagate the new stronger type,
* because it may allow further optimizations later; pass
* {@code matchNullability = false} and no cast will be added, but you may
* need to adjust types elsewhere in the expression tree.
*
* @param rel Relational expression
* @param expList List of expressions, modified in place
* @param predicates Constraints known to hold on input expressions
* @param unknownAsFalse Whether UNKNOWN will be treated as FALSE
* @param matchNullability Whether Calcite should add a CAST to a literal
* resulting from simplification and expression if the
* expression had nullable type and the literal is
* NOT NULL
*
* @return whether reduction found something to change, and succeeded
*/
protected static boolean reduceExpressions(RelNode rel, List<RexNode> expList, RelOptPredicateList predicates, boolean unknownAsFalse, boolean matchNullability) {
final RelOptCluster cluster = rel.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
final RexExecutor executor = Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
final RexSimplify simplify = new RexSimplify(rexBuilder, predicates, unknownAsFalse, executor);
// Simplify predicates in place
boolean reduced = reduceExpressionsInternal(rel, simplify, expList, predicates);
final ExprSimplifier simplifier = new ExprSimplifier(simplify, matchNullability);
boolean simplified = false;
for (int i = 0; i < expList.size(); i++) {
RexNode expr2 = simplifier.apply(expList.get(i));
if (!expr2.toString().equals(expList.get(i).toString())) {
expList.remove(i);
expList.add(i, expr2);
simplified = true;
}
}
return reduced || simplified;
}
use of org.apache.calcite.rex.RexExecutor in project calcite by apache.
the class ReduceExpressionsRule method reduceExpressionsInternal.
protected static boolean reduceExpressionsInternal(RelNode rel, RexSimplify simplify, List<RexNode> expList, RelOptPredicateList predicates) {
boolean changed = false;
// Replace predicates on CASE to CASE on predicates.
changed |= new CaseShuttle().mutate(expList);
// Find reducible expressions.
final List<RexNode> constExps = Lists.newArrayList();
List<Boolean> addCasts = Lists.newArrayList();
final List<RexNode> removableCasts = Lists.newArrayList();
findReducibleExps(rel.getCluster().getTypeFactory(), expList, predicates.constantMap, constExps, addCasts, removableCasts);
if (constExps.isEmpty() && removableCasts.isEmpty()) {
return changed;
}
// able to locate the original cast expression.
if (!removableCasts.isEmpty()) {
final List<RexNode> reducedExprs = Lists.newArrayList();
for (RexNode exp : removableCasts) {
RexCall call = (RexCall) exp;
reducedExprs.add(call.getOperands().get(0));
}
RexReplacer replacer = new RexReplacer(simplify, removableCasts, reducedExprs, Collections.nCopies(removableCasts.size(), false));
replacer.mutate(expList);
}
if (constExps.isEmpty()) {
return true;
}
final List<RexNode> constExps2 = Lists.newArrayList(constExps);
if (!predicates.constantMap.isEmpty()) {
// noinspection unchecked
final List<Map.Entry<RexNode, RexNode>> pairs = Lists.newArrayList(predicates.constantMap.entrySet());
RexReplacer replacer = new RexReplacer(simplify, Pair.left(pairs), Pair.right(pairs), Collections.nCopies(pairs.size(), false));
replacer.mutate(constExps2);
}
// Compute the values they reduce to.
RexExecutor executor = rel.getCluster().getPlanner().getExecutor();
if (executor == null) {
// rootRel.getCluster().getPlanner().setExecutor(executor);
return changed;
}
final List<RexNode> reducedValues = Lists.newArrayList();
executor.reduce(simplify.rexBuilder, constExps2, reducedValues);
// is equivalent to the original one.
if (RexUtil.strings(constExps).equals(RexUtil.strings(reducedValues))) {
return changed;
}
// handled as special cases.
if (rel instanceof Project) {
addCasts = Collections.nCopies(reducedValues.size(), true);
}
RexReplacer replacer = new RexReplacer(simplify, constExps, reducedValues, addCasts);
replacer.mutate(expList);
return true;
}
Aggregations