diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyRange.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyRange.java index 98d752facb464a..fcd86752241a14 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyRange.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyRange.java @@ -19,6 +19,7 @@ import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher; import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory; +import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext; import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.ComparisonPredicate; import org.apache.doris.nereids.trees.expressions.CompoundPredicate; @@ -31,10 +32,13 @@ import org.apache.doris.nereids.trees.expressions.LessThan; import org.apache.doris.nereids.trees.expressions.LessThanEqual; import org.apache.doris.nereids.trees.expressions.Not; +import org.apache.doris.nereids.trees.expressions.NullSafeEqual; import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral; import org.apache.doris.nereids.trees.expressions.literal.Literal; +import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.util.ExpressionUtils; import com.google.common.collect.BoundType; @@ -81,90 +85,107 @@ public class SimplifyRange implements ExpressionPatternRuleFactory { @Override public List> buildRules() { return ImmutableList.of( - matchesTopType(CompoundPredicate.class).then(SimplifyRange::rewrite) + matchesTopType(CompoundPredicate.class) + .thenApply(ctx -> SimplifyRange.rewrite(ctx.expr, ctx.rewriteContext)) ); } /** rewrite */ - public static Expression rewrite(CompoundPredicate expr) { - ValueDesc valueDesc = expr.accept(new RangeInference(), null); - Expression simplifiedExpr = valueDesc.toExpression(); - return simplifiedExpr == null ? valueDesc.expr : simplifiedExpr; + public static Expression rewrite(CompoundPredicate expr, ExpressionRewriteContext context) { + ValueDesc valueDesc = expr.accept(new RangeInference(), context); + Expression exprForNonNull = valueDesc.toExpressionForNonNull(); + if (exprForNonNull == null) { + // this mean cannot simplify + return valueDesc.exprForNonNull; + } + if (!valueDesc.reference.nullable() || !(exprForNonNull instanceof BooleanLiteral)) { + return exprForNonNull; + } else { + if (exprForNonNull.equals(BooleanLiteral.TRUE)) { + // is same as IF(reference IS NULL, NULL, TRUE) + return new Or(new Not(new IsNull(valueDesc.reference)), new NullLiteral(BooleanType.INSTANCE)); + } else { + // is same as IF(reference IS NULL, NULL, FALSE) + // but this expression is more friendly for constant folding + return new And(new IsNull(valueDesc.reference), new NullLiteral(BooleanType.INSTANCE)); + } + } } - private static class RangeInference extends ExpressionVisitor { + private static class RangeInference extends ExpressionVisitor { @Override - public ValueDesc visit(Expression expr, Void context) { - return new UnknownValue(expr); + public ValueDesc visit(Expression expr, ExpressionRewriteContext context) { + return new UnknownValue(context, expr); } - private ValueDesc buildRange(ComparisonPredicate predicate) { + private ValueDesc buildRange(ExpressionRewriteContext context, ComparisonPredicate predicate) { Expression right = predicate.child(1); if (right.isNullLiteral()) { // it's safe to return empty value if >, >=, <, <= and = with null - if ((predicate instanceof GreaterThan || predicate instanceof GreaterThanEqual - || predicate instanceof LessThan || predicate instanceof LessThanEqual - || predicate instanceof EqualTo)) { - return new EmptyValue(predicate.child(0), predicate); + if (predicate instanceof NullSafeEqual) { + return new UnknownValue(context, predicate); } else { - return new UnknownValue(predicate); + return new EmptyValue(context, predicate.child(0), predicate); } } // only handle `NumericType` and `DateLikeType` if (right.isLiteral() && (right.getDataType().isNumericType() || right.getDataType().isDateLikeType())) { - return ValueDesc.range(predicate); + return ValueDesc.range(context, predicate); } - return new UnknownValue(predicate); + return new UnknownValue(context, predicate); } @Override - public ValueDesc visitGreaterThan(GreaterThan greaterThan, Void context) { - return buildRange(greaterThan); + public ValueDesc visitGreaterThan(GreaterThan greaterThan, ExpressionRewriteContext context) { + return buildRange(context, greaterThan); } @Override - public ValueDesc visitGreaterThanEqual(GreaterThanEqual greaterThanEqual, Void context) { - return buildRange(greaterThanEqual); + public ValueDesc visitGreaterThanEqual(GreaterThanEqual greaterThanEqual, ExpressionRewriteContext context) { + return buildRange(context, greaterThanEqual); } @Override - public ValueDesc visitLessThan(LessThan lessThan, Void context) { - return buildRange(lessThan); + public ValueDesc visitLessThan(LessThan lessThan, ExpressionRewriteContext context) { + return buildRange(context, lessThan); } @Override - public ValueDesc visitLessThanEqual(LessThanEqual lessThanEqual, Void context) { - return buildRange(lessThanEqual); + public ValueDesc visitLessThanEqual(LessThanEqual lessThanEqual, ExpressionRewriteContext context) { + return buildRange(context, lessThanEqual); } @Override - public ValueDesc visitEqualTo(EqualTo equalTo, Void context) { - return buildRange(equalTo); + public ValueDesc visitEqualTo(EqualTo equalTo, ExpressionRewriteContext context) { + return buildRange(context, equalTo); } @Override - public ValueDesc visitInPredicate(InPredicate inPredicate, Void context) { + public ValueDesc visitInPredicate(InPredicate inPredicate, ExpressionRewriteContext context) { // only handle `NumericType` and `DateLikeType` if (ExpressionUtils.isAllLiteral(inPredicate.getOptions()) && (ExpressionUtils.matchNumericType(inPredicate.getOptions()) || ExpressionUtils.matchDateLikeType(inPredicate.getOptions()))) { - return ValueDesc.discrete(inPredicate); + return ValueDesc.discrete(context, inPredicate); } - return new UnknownValue(inPredicate); + return new UnknownValue(context, inPredicate); } @Override - public ValueDesc visitAnd(And and, Void context) { - return simplify(and, ExpressionUtils.extractConjunction(and), ValueDesc::intersect, ExpressionUtils::and); + public ValueDesc visitAnd(And and, ExpressionRewriteContext context) { + return simplify(context, and, ExpressionUtils.extractConjunction(and), + ValueDesc::intersect, ExpressionUtils::and); } @Override - public ValueDesc visitOr(Or or, Void context) { - return simplify(or, ExpressionUtils.extractDisjunction(or), ValueDesc::union, ExpressionUtils::or); + public ValueDesc visitOr(Or or, ExpressionRewriteContext context) { + return simplify(context, or, ExpressionUtils.extractDisjunction(or), + ValueDesc::union, ExpressionUtils::or); } - private ValueDesc simplify(Expression originExpr, List predicates, + private ValueDesc simplify(ExpressionRewriteContext context, + Expression originExpr, List predicates, BinaryOperator op, BinaryOperator exprOp) { Multimap groupByReference @@ -193,52 +214,58 @@ private ValueDesc simplify(Expression originExpr, List predicates, } // use UnknownValue to wrap different references - return new UnknownValue(valuePerRefs, originExpr, exprOp); + return new UnknownValue(context, valuePerRefs, originExpr, exprOp); } } private abstract static class ValueDesc { - Expression expr; + ExpressionRewriteContext context; + Expression exprForNonNull; Expression reference; - public ValueDesc(Expression reference, Expression expr) { - this.expr = expr; + public ValueDesc(ExpressionRewriteContext context, Expression reference, Expression exprForNonNull) { + this.context = context; + this.exprForNonNull = exprForNonNull; this.reference = reference; } public abstract ValueDesc union(ValueDesc other); - public static ValueDesc union(RangeValue range, DiscreteValue discrete, boolean reverseOrder) { + public static ValueDesc union(ExpressionRewriteContext context, + RangeValue range, DiscreteValue discrete, boolean reverseOrder) { long count = discrete.values.stream().filter(x -> range.range.test(x)).count(); if (count == discrete.values.size()) { return range; } - Expression originExpr = ExpressionUtils.or(range.expr, discrete.expr); + Expression exprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.or(range.exprForNonNull, discrete.exprForNonNull), context); List sourceValues = reverseOrder ? ImmutableList.of(discrete, range) : ImmutableList.of(range, discrete); - return new UnknownValue(sourceValues, originExpr, ExpressionUtils::or); + return new UnknownValue(context, sourceValues, exprForNonNull, ExpressionUtils::or); } public abstract ValueDesc intersect(ValueDesc other); - public static ValueDesc intersect(RangeValue range, DiscreteValue discrete) { - DiscreteValue result = new DiscreteValue(discrete.reference, discrete.expr); + public static ValueDesc intersect(ExpressionRewriteContext context, RangeValue range, DiscreteValue discrete) { + DiscreteValue result = new DiscreteValue(context, discrete.reference, discrete.exprForNonNull); discrete.values.stream().filter(x -> range.range.contains(x)).forEach(result.values::add); if (!result.values.isEmpty()) { return result; } - return new EmptyValue(range.reference, ExpressionUtils.and(range.expr, discrete.expr)); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.and(range.exprForNonNull, discrete.exprForNonNull), context); + return new EmptyValue(context, range.reference, originExprForNonNull); } - public abstract Expression toExpression(); + public abstract Expression toExpressionForNonNull(); - public static ValueDesc range(ComparisonPredicate predicate) { + public static ValueDesc range(ExpressionRewriteContext context, ComparisonPredicate predicate) { Literal value = (Literal) predicate.right(); if (predicate instanceof EqualTo) { - return new DiscreteValue(predicate.left(), predicate, value); + return new DiscreteValue(context, predicate.left(), predicate, value); } - RangeValue rangeValue = new RangeValue(predicate.left(), predicate); + RangeValue rangeValue = new RangeValue(context, predicate.left(), predicate); if (predicate instanceof GreaterThanEqual) { rangeValue.range = Range.atLeast(value); } else if (predicate instanceof GreaterThan) { @@ -252,17 +279,17 @@ public static ValueDesc range(ComparisonPredicate predicate) { return rangeValue; } - public static ValueDesc discrete(InPredicate in) { + public static ValueDesc discrete(ExpressionRewriteContext context, InPredicate in) { // Set literals = (Set) Utils.fastToImmutableSet(in.getOptions()); Set literals = in.getOptions().stream().map(Literal.class::cast).collect(Collectors.toSet()); - return new DiscreteValue(in.getCompareExpr(), in, literals); + return new DiscreteValue(context, in.getCompareExpr(), in, literals); } } private static class EmptyValue extends ValueDesc { - public EmptyValue(Expression reference, Expression expr) { - super(reference, expr); + public EmptyValue(ExpressionRewriteContext context, Expression reference, Expression exprForNonNull) { + super(context, reference, exprForNonNull); } @Override @@ -276,7 +303,7 @@ public ValueDesc intersect(ValueDesc other) { } @Override - public Expression toExpression() { + public Expression toExpressionForNonNull() { return BooleanLiteral.FALSE; } } @@ -289,8 +316,8 @@ public Expression toExpression() { private static class RangeValue extends ValueDesc { Range range; - public RangeValue(Expression reference, Expression expr) { - super(reference, expr); + public RangeValue(ExpressionRewriteContext context, Expression reference, Expression exprForNonNull) { + super(context, reference, exprForNonNull); } @Override @@ -300,19 +327,23 @@ public ValueDesc union(ValueDesc other) { } try { if (other instanceof RangeValue) { + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.or(exprForNonNull, other.exprForNonNull), context); RangeValue o = (RangeValue) other; if (range.isConnected(o.range)) { - RangeValue rangeValue = new RangeValue(reference, ExpressionUtils.or(expr, other.expr)); + RangeValue rangeValue = new RangeValue(context, reference, originExprForNonNull); rangeValue.range = range.span(o.range); return rangeValue; } - Expression originExpr = ExpressionUtils.or(expr, other.expr); - return new UnknownValue(ImmutableList.of(this, other), originExpr, ExpressionUtils::or); + return new UnknownValue(context, ImmutableList.of(this, other), + originExprForNonNull, ExpressionUtils::or); } - return union(this, (DiscreteValue) other, false); + return union(context, this, (DiscreteValue) other, false); } catch (Exception e) { - Expression originExpr = ExpressionUtils.or(expr, other.expr); - return new UnknownValue(ImmutableList.of(this, other), originExpr, ExpressionUtils::or); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.or(exprForNonNull, other.exprForNonNull), context); + return new UnknownValue(context, ImmutableList.of(this, other), + originExprForNonNull, ExpressionUtils::or); } } @@ -323,23 +354,27 @@ public ValueDesc intersect(ValueDesc other) { } try { if (other instanceof RangeValue) { + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.and(exprForNonNull, other.exprForNonNull), context); RangeValue o = (RangeValue) other; if (range.isConnected(o.range)) { - RangeValue rangeValue = new RangeValue(reference, ExpressionUtils.and(expr, other.expr)); + RangeValue rangeValue = new RangeValue(context, reference, originExprForNonNull); rangeValue.range = range.intersection(o.range); return rangeValue; } - return new EmptyValue(reference, ExpressionUtils.and(expr, other.expr)); + return new EmptyValue(context, reference, originExprForNonNull); } - return intersect(this, (DiscreteValue) other); + return intersect(context, this, (DiscreteValue) other); } catch (Exception e) { - Expression originExpr = ExpressionUtils.and(expr, other.expr); - return new UnknownValue(ImmutableList.of(this, other), originExpr, ExpressionUtils::and); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.and(exprForNonNull, other.exprForNonNull), context); + return new UnknownValue(context, ImmutableList.of(this, other), + originExprForNonNull, ExpressionUtils::and); } } @Override - public Expression toExpression() { + public Expression toExpressionForNonNull() { List result = Lists.newArrayList(); if (range.hasLowerBound()) { if (range.lowerBoundType() == BoundType.CLOSED) { @@ -357,9 +392,6 @@ public Expression toExpression() { } if (!result.isEmpty()) { return ExpressionUtils.and(result); - } else if (reference.nullable()) { - // when reference is nullable, we should filter null slot. - return new Not(new IsNull(reference)); } else { return BooleanLiteral.TRUE; } @@ -379,12 +411,14 @@ public String toString() { private static class DiscreteValue extends ValueDesc { Set values; - public DiscreteValue(Expression reference, Expression expr, Literal... values) { - this(reference, expr, Arrays.asList(values)); + public DiscreteValue(ExpressionRewriteContext context, + Expression reference, Expression exprForNonNull, Literal... values) { + this(context, reference, exprForNonNull, Arrays.asList(values)); } - public DiscreteValue(Expression reference, Expression expr, Collection values) { - super(reference, expr); + public DiscreteValue(ExpressionRewriteContext context, + Expression reference, Expression exprForNonNull, Collection values) { + super(context, reference, exprForNonNull); this.values = Sets.newTreeSet(values); } @@ -395,15 +429,19 @@ public ValueDesc union(ValueDesc other) { } try { if (other instanceof DiscreteValue) { - DiscreteValue discreteValue = new DiscreteValue(reference, ExpressionUtils.or(expr, other.expr)); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.or(exprForNonNull, other.exprForNonNull), context); + DiscreteValue discreteValue = new DiscreteValue(context, reference, originExprForNonNull); discreteValue.values.addAll(((DiscreteValue) other).values); discreteValue.values.addAll(this.values); return discreteValue; } - return union((RangeValue) other, this, true); + return union(context, (RangeValue) other, this, true); } catch (Exception e) { - Expression originExpr = ExpressionUtils.or(expr, other.expr); - return new UnknownValue(ImmutableList.of(this, other), originExpr, ExpressionUtils::or); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.or(exprForNonNull, other.exprForNonNull), context); + return new UnknownValue(context, ImmutableList.of(this, other), + originExprForNonNull, ExpressionUtils::or); } } @@ -414,24 +452,28 @@ public ValueDesc intersect(ValueDesc other) { } try { if (other instanceof DiscreteValue) { - DiscreteValue discreteValue = new DiscreteValue(reference, ExpressionUtils.and(expr, other.expr)); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.and(exprForNonNull, other.exprForNonNull), context); + DiscreteValue discreteValue = new DiscreteValue(context, reference, originExprForNonNull); discreteValue.values.addAll(((DiscreteValue) other).values); discreteValue.values.retainAll(this.values); if (discreteValue.values.isEmpty()) { - return new EmptyValue(reference, ExpressionUtils.and(expr, other.expr)); + return new EmptyValue(context, reference, originExprForNonNull); } else { return discreteValue; } } - return intersect((RangeValue) other, this); + return intersect(context, (RangeValue) other, this); } catch (Exception e) { - Expression originExpr = ExpressionUtils.and(expr, other.expr); - return new UnknownValue(ImmutableList.of(this, other), originExpr, ExpressionUtils::and); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.and(exprForNonNull, other.exprForNonNull), context); + return new UnknownValue(context, ImmutableList.of(this, other), + originExprForNonNull, ExpressionUtils::and); } } @Override - public Expression toExpression() { + public Expression toExpressionForNonNull() { // NOTICE: it's related with `InPredicateToEqualToRule` // They are same processes, so must change synchronously. if (values.size() == 1) { @@ -459,42 +501,43 @@ private static class UnknownValue extends ValueDesc { private final List sourceValues; private final BinaryOperator mergeExprOp; - private UnknownValue(Expression expr) { - super(expr, expr); + private UnknownValue(ExpressionRewriteContext context, Expression expr) { + super(context, expr, expr); sourceValues = ImmutableList.of(); mergeExprOp = null; } - public UnknownValue(List sourceValues, Expression originExpr, - BinaryOperator mergeExprOp) { - super(sourceValues.get(0).reference, originExpr); + public UnknownValue(ExpressionRewriteContext context, + List sourceValues, Expression exprForNonNull, BinaryOperator mergeExprOp) { + super(context, sourceValues.get(0).reference, exprForNonNull); this.sourceValues = ImmutableList.copyOf(sourceValues); this.mergeExprOp = mergeExprOp; } @Override public ValueDesc union(ValueDesc other) { - Expression originExpr = ExpressionUtils.or(expr, other.expr); - return new UnknownValue(ImmutableList.of(this, other), originExpr, ExpressionUtils::or); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.or(exprForNonNull, other.exprForNonNull), context); + return new UnknownValue(context, ImmutableList.of(this, other), originExprForNonNull, ExpressionUtils::or); } @Override public ValueDesc intersect(ValueDesc other) { - Expression originExpr = ExpressionUtils.and(expr, other.expr); - return new UnknownValue(ImmutableList.of(this, other), originExpr, ExpressionUtils::and); + Expression originExprForNonNull = FoldConstantRuleOnFE.evaluate( + ExpressionUtils.and(exprForNonNull, other.exprForNonNull), context); + return new UnknownValue(context, ImmutableList.of(this, other), originExprForNonNull, ExpressionUtils::and); } @Override - public Expression toExpression() { + public Expression toExpressionForNonNull() { if (sourceValues.isEmpty()) { - return expr; + return exprForNonNull; } - - Expression result = sourceValues.get(0).toExpression(); + Expression result = sourceValues.get(0).toExpressionForNonNull(); for (int i = 1; i < sourceValues.size(); i++) { - result = mergeExprOp.apply(result, sourceValues.get(i).toExpression()); + result = mergeExprOp.apply(result, sourceValues.get(i).toExpressionForNonNull()); } - return result; + return FoldConstantRuleOnFE.evaluate(result, context); } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java index e9430c8168241c..a3fb60b56099cc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java @@ -118,6 +118,21 @@ public TPipelineFragmentParams plan(TUniqueId loadId) throws UserException { // the caller should get table read lock when call this method // create the plan. the plan's query id and load id are same, using the parameter 'loadId' public TPipelineFragmentParams plan(TUniqueId loadId, int fragmentInstanceIdIndex) throws UserException { + + // 1. new load scan + // 2. taskInfo -> load scan + // 3. new sink + // 4. taskInfo -> sink + // 5. scan.init finalize + // 5. sink init finalize complete + + // 1. new nereids scan + // 2. task info -> scan + // 3. new sink + // 4. task sink + // 5. sink + + if (destTable.getKeysType() != KeysType.UNIQUE_KEYS && taskInfo.getMergeType() != LoadTask.MergeType.APPEND) { throw new AnalysisException("load by MERGE or DELETE is only supported in unique tables."); @@ -317,6 +332,8 @@ public TPipelineFragmentParams plan(TUniqueId loadId, int fragmentInstanceIdInde olapTableSink.setPartialUpdateInputColumns(isPartialUpdate, partialUpdateInputColumns); olapTableSink.complete(analyzer); + + // for stream load, we only need one fragment, ScanNode -> DataSink. // OlapTableSink can dispatch data to corresponding node. PlanFragment fragment = new PlanFragment(new PlanFragmentId(0), scanNode, DataPartition.UNPARTITIONED); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java index 30155b3bf77c00..1cc6a3d373f92a 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java @@ -30,7 +30,7 @@ import org.apache.doris.nereids.types.BigIntType; import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; -import org.apache.doris.nereids.types.DoubleType; +import org.apache.doris.nereids.types.DecimalV3Type; import org.apache.doris.nereids.types.IntegerType; import org.apache.doris.nereids.types.StringType; import org.apache.doris.nereids.types.TinyIntType; @@ -66,31 +66,36 @@ public void testSimplify() { assertRewrite("TA > 3 or TA > null", "TA > 3"); assertRewrite("TA > 3 or TA < null", "TA > 3"); assertRewrite("TA > 3 or TA = null", "TA > 3"); - assertRewrite("TA > 3 or TA <> null", "TA > 3 or TA <> null"); + assertRewrite("TA > 3 or TA <> null", "TA > 3 or null"); assertRewrite("TA > 3 or TA <=> null", "TA > 3 or TA <=> null"); - assertRewrite("TA > 3 and TA > null", "false"); - assertRewrite("TA > 3 and TA < null", "false"); - assertRewrite("TA > 3 and TA = null", "false"); - assertRewrite("TA > 3 and TA <> null", "TA > 3 and TA <> null"); + assertRewriteNotNull("TA > 3 and TA > null", "false"); + assertRewriteNotNull("TA > 3 and TA < null", "false"); + assertRewriteNotNull("TA > 3 and TA = null", "false"); + assertRewrite("TA > 3 and TA > null", "TA is null and null"); + assertRewrite("TA > 3 and TA < null", "TA is null and null"); + assertRewrite("TA > 3 and TA = null", "TA is null and null"); + assertRewrite("TA > 3 and TA <> null", "TA > 3 and null"); assertRewrite("TA > 3 and TA <=> null", "TA > 3 and TA <=> null"); assertRewrite("(TA >= 1 and TA <=3 ) or (TA > 5 and TA < 7)", "(TA >= 1 and TA <=3 ) or (TA > 5 and TA < 7)"); - assertRewrite("(TA > 3 and TA < 1) or (TA > 7 and TA < 5)", "FALSE"); - assertRewrite("TA > 3 and TA < 1", "FALSE"); + assertRewriteNotNull("(TA > 3 and TA < 1) or (TA > 7 and TA < 5)", "FALSE"); + assertRewrite("(TA > 3 and TA < 1) or (TA > 7 and TA < 5)", "TA is null and null"); + assertRewriteNotNull("TA > 3 and TA < 1", "FALSE"); + assertRewrite("TA > 3 and TA < 1", "TA is null and null"); assertRewrite("TA >= 3 and TA < 3", "TA >= 3 and TA < 3"); - assertRewrite("TA = 1 and TA > 10", "FALSE"); + assertRewriteNotNull("TA = 1 and TA > 10", "FALSE"); + assertRewrite("TA = 1 and TA > 10", "TA is null and null"); assertRewrite("TA > 5 or TA < 1", "TA > 5 or TA < 1"); assertRewrite("TA > 5 or TA > 1 or TA > 10", "TA > 1"); - assertRewrite("TA > 5 or TA > 1 or TA < 10", "TA IS NOT NULL"); + assertRewrite("TA > 5 or TA > 1 or TA < 10", "TA is not null or null"); assertRewriteNotNull("TA > 5 or TA > 1 or TA < 10", "TRUE"); assertRewrite("TA > 5 and TA > 1 and TA > 10", "TA > 10"); assertRewrite("TA > 5 and TA > 1 and TA < 10", "TA > 5 and TA < 10"); assertRewrite("TA > 1 or TA < 1", "TA > 1 or TA < 1"); - assertRewrite("TA > 1 or TA < 10", "TA IS NOT NULL"); + assertRewrite("TA > 1 or TA < 10", "TA is not null or null"); assertRewriteNotNull("TA > 1 or TA < 10", "TRUE"); assertRewrite("TA > 5 and TA < 10", "TA > 5 and TA < 10"); assertRewrite("TA > 5 and TA > 10", "TA > 10"); - assertRewrite("TA > 5 + 1 and TA > 10", "TA > 5 + 1 and TA > 10"); - assertRewrite("TA > 5 + 1 and TA > 10", "TA > 5 + 1 and TA > 10"); + assertRewrite("TA > 5 + 1 and TA > 10", "cast(TA as smallint) > 6 and TA > 10"); assertRewrite("(TA > 1 and TA > 10) or TA > 20", "TA > 10"); assertRewrite("(TA > 1 or TA > 10) and TA > 20", "TA > 20"); assertRewrite("(TA + TB > 1 or TA + TB > 10) and TA + TB > 20", "TA + TB > 20"); @@ -100,44 +105,52 @@ public void testSimplify() { assertRewrite("((TB > 30 and TA > 40) and TA > 20) and (TB > 10 and TB > 20)", "TB > 30 and TA > 40"); assertRewrite("(TA > 10 and TB > 10) or (TB > 10 and TB > 20)", "TA > 10 and TB > 10 or TB > 20"); assertRewrite("((TA > 10 or TA > 5) and TB > 10) or (TB > 10 and (TB > 20 or TB < 10))", "(TA > 5 and TB > 10) or (TB > 10 and (TB > 20 or TB < 10))"); - assertRewrite("TA in (1,2,3) and TA > 10", "FALSE"); + assertRewriteNotNull("TA in (1,2,3) and TA > 10", "FALSE"); + assertRewrite("TA in (1,2,3) and TA > 10", "TA is null and null"); assertRewrite("TA in (1,2,3) and TA >= 1", "TA in (1,2,3)"); assertRewrite("TA in (1,2,3) and TA > 1", "TA IN (2, 3)"); assertRewrite("TA in (1,2,3) or TA >= 1", "TA >= 1"); assertRewrite("TA in (1)", "TA in (1)"); assertRewrite("TA in (1,2,3) and TA < 10", "TA in (1,2,3)"); - assertRewrite("TA in (1,2,3) and TA < 1", "FALSE"); + assertRewriteNotNull("TA in (1,2,3) and TA < 1", "FALSE"); + assertRewrite("TA in (1,2,3) and TA < 1", "TA is null and null"); assertRewrite("TA in (1,2,3) or TA < 1", "TA in (1,2,3) or TA < 1"); assertRewrite("TA in (1,2,3) or TA in (2,3,4)", "TA in (1,2,3,4)"); assertRewrite("TA in (1,2,3) or TA in (4,5,6)", "TA in (1,2,3,4,5,6)"); - assertRewrite("TA in (1,2,3) and TA in (4,5,6)", "FALSE"); + assertRewrite("TA in (1,2,3) and TA in (4,5,6)", "TA is null and null"); + assertRewriteNotNull("TA in (1,2,3) and TA in (4,5,6)", "FALSE"); assertRewrite("TA in (1,2,3) and TA in (3,4,5)", "TA = 3"); assertRewrite("TA + TB in (1,2,3) and TA + TB in (3,4,5)", "TA + TB = 3"); assertRewrite("TA in (1,2,3) and DA > 1.5", "TA in (1,2,3) and DA > 1.5"); - assertRewrite("TA = 1 and TA = 3", "FALSE"); - assertRewrite("TA in (1) and TA in (3)", "FALSE"); + assertRewriteNotNull("TA = 1 and TA = 3", "FALSE"); + assertRewrite("TA = 1 and TA = 3", "TA is null and null"); + assertRewriteNotNull("TA in (1) and TA in (3)", "FALSE"); + assertRewrite("TA in (1) and TA in (3)", "TA is null and null"); assertRewrite("TA in (1) and TA in (1)", "TA = 1"); - assertRewrite("(TA > 3 and TA < 1) and TB < 5", "FALSE"); + assertRewriteNotNull("(TA > 3 and TA < 1) and TB < 5", "FALSE"); + assertRewrite("(TA > 3 and TA < 1) and TB < 5", "TA is null and null"); assertRewrite("(TA > 3 and TA < 1) or TB < 5", "TB < 5"); assertRewrite("((IA = 1 AND SC ='1') OR SC = '1212') AND IA =1", "((IA = 1 AND SC ='1') OR SC = '1212') AND IA =1"); assertRewrite("TA + TC", "TA + TC"); assertRewrite("(TA + TC >= 1 and TA + TC <=3 ) or (TA + TC > 5 and TA + TC < 7)", "(TA + TC >= 1 and TA + TC <=3 ) or (TA + TC > 5 and TA + TC < 7)"); - assertRewrite("(TA + TC > 3 and TA + TC < 1) or (TA + TC > 7 and TA + TC < 5)", "FALSE"); - assertRewrite("TA + TC > 3 and TA + TC < 1", "FALSE"); + assertRewriteNotNull("(TA + TC > 3 and TA + TC < 1) or (TA + TC > 7 and TA + TC < 5)", "FALSE"); + assertRewrite("(TA + TC > 3 and TA + TC < 1) or (TA + TC > 7 and TA + TC < 5)", "(TA + TC) is null and null"); + assertRewriteNotNull("TA + TC > 3 and TA + TC < 1", "FALSE"); + assertRewrite("TA + TC > 3 and TA + TC < 1", "(TA + TC) is null and null"); assertRewrite("TA + TC >= 3 and TA + TC < 3", "TA + TC >= 3 and TA + TC < 3"); - assertRewrite("TA + TC = 1 and TA + TC > 10", "FALSE"); + assertRewriteNotNull("TA + TC = 1 and TA + TC > 10", "FALSE"); + assertRewrite("TA + TC = 1 and TA + TC > 10", "(TA + TC) is null and null"); assertRewrite("TA + TC > 5 or TA + TC < 1", "TA + TC > 5 or TA + TC < 1"); assertRewrite("TA + TC > 5 or TA + TC > 1 or TA + TC > 10", "TA + TC > 1"); - assertRewrite("TA + TC > 5 or TA + TC > 1 or TA + TC < 10", "(not (TA + TC) IS NULL)"); + assertRewrite("TA + TC > 5 or TA + TC > 1 or TA + TC < 10", "(TA + TC) is not null or null"); assertRewrite("TA + TC > 5 and TA + TC > 1 and TA + TC > 10", "TA + TC > 10"); assertRewrite("TA + TC > 5 and TA + TC > 1 and TA + TC < 10", "TA + TC > 5 and TA + TC < 10"); assertRewrite("TA + TC > 1 or TA + TC < 1", "TA + TC > 1 or TA + TC < 1"); - assertRewrite("TA + TC > 1 or TA + TC < 10", "(not (TA + TC) IS NULL)"); + assertRewrite("TA + TC > 1 or TA + TC < 10", "(TA + TC) is not null or null"); assertRewrite("TA + TC > 5 and TA + TC < 10", "TA + TC > 5 and TA + TC < 10"); assertRewrite("TA + TC > 5 and TA + TC > 10", "TA + TC > 10"); - assertRewrite("TA + TC > 5 + 1 and TA + TC > 10", "TA + TC > 5 + 1 and TA + TC > 10"); - assertRewrite("TA + TC > 5 + 1 and TA + TC > 10", "TA + TC > 5 + 1 and TA + TC > 10"); + assertRewrite("TA + TC > 5 + 1 and TA + TC > 10", "TA + TC > 10"); assertRewrite("(TA + TC > 1 and TA + TC > 10) or TA + TC > 20", "TA + TC > 10"); assertRewrite("(TA + TC > 1 or TA + TC > 10) and TA + TC > 20", "TA + TC > 20"); assertRewrite("(TA + TC + TB > 1 or TA + TC + TB > 10) and TA + TC + TB > 20", "TA + TC + TB > 20"); @@ -147,24 +160,30 @@ public void testSimplify() { assertRewrite("((TB > 30 and TA + TC > 40) and TA + TC > 20) and (TB > 10 and TB > 20)", "TB > 30 and TA + TC > 40"); assertRewrite("(TA + TC > 10 and TB > 10) or (TB > 10 and TB > 20)", "TA + TC > 10 and TB > 10 or TB > 20"); assertRewrite("((TA + TC > 10 or TA + TC > 5) and TB > 10) or (TB > 10 and (TB > 20 or TB < 10))", "(TA + TC > 5 and TB > 10) or (TB > 10 and (TB > 20 or TB < 10))"); - assertRewrite("TA + TC in (1,2,3) and TA + TC > 10", "FALSE"); + assertRewriteNotNull("TA + TC in (1,2,3) and TA + TC > 10", "FALSE"); + assertRewrite("TA + TC in (1,2,3) and TA + TC > 10", "(TA + TC) is null and null"); assertRewrite("TA + TC in (1,2,3) and TA + TC >= 1", "TA + TC in (1,2,3)"); assertRewrite("TA + TC in (1,2,3) and TA + TC > 1", "(TA + TC) IN (2, 3)"); assertRewrite("TA + TC in (1,2,3) or TA + TC >= 1", "TA + TC >= 1"); assertRewrite("TA + TC in (1)", "TA + TC in (1)"); assertRewrite("TA + TC in (1,2,3) and TA + TC < 10", "TA + TC in (1,2,3)"); - assertRewrite("TA + TC in (1,2,3) and TA + TC < 1", "FALSE"); + assertRewriteNotNull("TA + TC in (1,2,3) and TA + TC < 1", "FALSE"); + assertRewrite("TA + TC in (1,2,3) and TA + TC < 1", "(TA + TC) is null and null"); assertRewrite("TA + TC in (1,2,3) or TA + TC < 1", "TA + TC in (1,2,3) or TA + TC < 1"); assertRewrite("TA + TC in (1,2,3) or TA + TC in (2,3,4)", "TA + TC in (1,2,3,4)"); assertRewrite("TA + TC in (1,2,3) or TA + TC in (4,5,6)", "TA + TC in (1,2,3,4,5,6)"); - assertRewrite("TA + TC in (1,2,3) and TA + TC in (4,5,6)", "FALSE"); + assertRewriteNotNull("TA + TC in (1,2,3) and TA + TC in (4,5,6)", "FALSE"); + assertRewrite("TA + TC in (1,2,3) and TA + TC in (4,5,6)", "(TA + TC) is null and null"); assertRewrite("TA + TC in (1,2,3) and TA + TC in (3,4,5)", "TA + TC = 3"); assertRewrite("TA + TC + TB in (1,2,3) and TA + TC + TB in (3,4,5)", "TA + TC + TB = 3"); assertRewrite("TA + TC in (1,2,3) and DA > 1.5", "TA + TC in (1,2,3) and DA > 1.5"); - assertRewrite("TA + TC = 1 and TA + TC = 3", "FALSE"); - assertRewrite("TA + TC in (1) and TA + TC in (3)", "FALSE"); + assertRewriteNotNull("TA + TC = 1 and TA + TC = 3", "FALSE"); + assertRewrite("TA + TC = 1 and TA + TC = 3", "(TA + TC) is null and null"); + assertRewriteNotNull("TA + TC in (1) and TA + TC in (3)", "FALSE"); + assertRewrite("TA + TC in (1) and TA + TC in (3)", "(TA + TC) is null and null"); assertRewrite("TA + TC in (1) and TA + TC in (1)", "TA + TC = 1"); - assertRewrite("(TA + TC > 3 and TA + TC < 1) and TB < 5", "FALSE"); + assertRewriteNotNull("(TA + TC > 3 and TA + TC < 1) and TB < 5", "FALSE"); + assertRewrite("(TA + TC > 3 and TA + TC < 1) and TB < 5", "(TA + TC) is null and null"); assertRewrite("(TA + TC > 3 and TA + TC < 1) or TB < 5", "TB < 5"); assertRewrite("(TA + TC > 3 OR TA < 1) AND TB = 2) AND IA =1", "(TA + TC > 3 OR TA < 1) AND TB = 2) AND IA =1"); @@ -180,18 +199,23 @@ public void testSimplifyDate() { assertRewrite( "(TA >= date '2024-01-01' and TA <= date '2024-01-03') or (TA > date '2024-01-05' and TA < date '2024-01-07')", "(TA >= date '2024-01-01' and TA <= date '2024-01-03') or (TA > date '2024-01-05' and TA < date '2024-01-07')"); + assertRewriteNotNull( + "(TA > date '2024-01-03' and TA < date '2024-01-01') or (TA > date '2024-01-07'and TA < date '2024-01-05')", + "false"); assertRewrite( "(TA > date '2024-01-03' and TA < date '2024-01-01') or (TA > date '2024-01-07'and TA < date '2024-01-05')", - "FALSE"); - assertRewrite("TA > date '2024-01-03' and TA < date '2024-01-01'", "FALSE"); + "cast(TA as date) is null and null"); + assertRewriteNotNull("TA > date '2024-01-03' and TA < date '2024-01-01'", "FALSE"); + assertRewrite("TA > date '2024-01-03' and TA < date '2024-01-01'", "cast(TA as date) is null and null"); assertRewrite("TA >= date '2024-01-01' and TA < date '2024-01-01'", "TA >= date '2024-01-01' and TA < date '2024-01-01'"); - assertRewrite("TA = date '2024-01-01' and TA > date '2024-01-10'", "FALSE"); + assertRewriteNotNull("TA = date '2024-01-01' and TA > date '2024-01-10'", "FALSE"); + assertRewrite("TA = date '2024-01-01' and TA > date '2024-01-10'", "cast(TA as date) is null and null"); assertRewrite("TA > date '2024-01-05' or TA < date '2024-01-01'", "TA > date '2024-01-05' or TA < date '2024-01-01'"); assertRewrite("TA > date '2024-01-05' or TA > date '2024-01-01' or TA > date '2024-01-10'", "TA > date '2024-01-01'"); - assertRewrite("TA > date '2024-01-05' or TA > date '2024-01-01' or TA < date '2024-01-10'", "cast(TA as date) IS NOT NULL"); + assertRewrite("TA > date '2024-01-05' or TA > date '2024-01-01' or TA < date '2024-01-10'", "cast(TA as date) is not null or null"); assertRewriteNotNull("TA > date '2024-01-05' or TA > date '2024-01-01' or TA < date '2024-01-10'", "TRUE"); assertRewrite("TA > date '2024-01-05' and TA > date '2024-01-01' and TA > date '2024-01-10'", "TA > date '2024-01-10'"); @@ -199,7 +223,7 @@ public void testSimplifyDate() { "TA > date '2024-01-05' and TA < date '2024-01-10'"); assertRewrite("TA > date '2024-01-05' or TA < date '2024-01-05'", "TA > date '2024-01-05' or TA < date '2024-01-05'"); - assertRewrite("TA > date '2024-01-01' or TA < date '2024-01-10'", "cast(TA as date) IS NOT NULL"); + assertRewrite("TA > date '2024-01-01' or TA < date '2024-01-10'", "cast(TA as date) is not null or null"); assertRewriteNotNull("TA > date '2024-01-01' or TA < date '2024-01-10'", "TRUE"); assertRewrite("TA > date '2024-01-05' and TA < date '2024-01-10'", "TA > date '2024-01-05' and TA < date '2024-01-10'"); @@ -212,8 +236,8 @@ public void testSimplifyDate() { assertRewrite( "(TA > date '2024-01-10' or TA > date '2024-01-20') and (TB > date '2024-01-10' and TB < date '2024-01-20')", "TA > date '2024-01-10' and (TB > date '2024-01-10' and TB < date '2024-01-20') "); - assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA > date '2024-01-10'", - "FALSE"); + assertRewriteNotNull("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA > date '2024-01-10'", "FALSE"); + assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA > date '2024-01-10'", "cast(TA as date) is null and null"); assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA >= date '2024-01-01'", "TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03')"); assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA > date '2024-01-01'", @@ -223,18 +247,25 @@ public void testSimplifyDate() { assertRewrite("TA in (date '2024-01-01')", "TA in (date '2024-01-01')"); assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA < date '2024-01-10'", "TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03')"); - assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA < date '2024-01-01'", + assertRewriteNotNull("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA < date '2024-01-01'", "FALSE"); + assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') and TA < date '2024-01-01'", + "cast(TA as date) is null and null"); assertRewrite("TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') or TA < date '2024-01-01'", "TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') or TA < date '2024-01-01'"); assertRewrite("TA in (date '2024-01-01',date '2024-01-02') or TA in (date '2024-01-02', date '2024-01-03')", "TA in (date '2024-01-01',date '2024-01-02',date '2024-01-03')"); - assertRewrite("TA in (date '2024-01-01',date '2024-01-02') and TA in (date '2024-01-03', date '2024-01-04')", + assertRewriteNotNull("TA in (date '2024-01-01',date '2024-01-02') and TA in (date '2024-01-03', date '2024-01-04')", "FALSE"); - assertRewrite("TA = date '2024-01-03' and TA = date '2024-01-01'", "FALSE"); - assertRewrite("TA in (date '2024-01-01') and TA in (date '2024-01-03')", "FALSE"); + assertRewrite("TA in (date '2024-01-01',date '2024-01-02') and TA in (date '2024-01-03', date '2024-01-04')", + "cast(TA as date) is null and null"); + assertRewriteNotNull("TA = date '2024-01-03' and TA = date '2024-01-01'", "FALSE"); + assertRewrite("TA = date '2024-01-03' and TA = date '2024-01-01'", "cast(TA as date) is null and null"); + assertRewriteNotNull("TA in (date '2024-01-01') and TA in (date '2024-01-03')", "FALSE"); + assertRewrite("TA in (date '2024-01-01') and TA in (date '2024-01-03')", "cast(TA as date) is null and null"); assertRewrite("TA in (date '2024-01-03') and TA in (date '2024-01-03')", "TA = date '2024-01-03'"); - assertRewrite("(TA > date '2024-01-03' and TA < date '2024-01-01') and TB < date '2024-01-05'", "FALSE"); + assertRewriteNotNull("(TA > date '2024-01-03' and TA < date '2024-01-01') and TB < date '2024-01-05'", "FALSE"); + assertRewrite("(TA > date '2024-01-03' and TA < date '2024-01-01') and TB < date '2024-01-05'", "cast(TA as date) is null and null"); assertRewrite("(TA > date '2024-01-03' and TA < date '2024-01-01') or TB < date '2024-01-05'", "TB < date '2024-01-05'"); } @@ -248,18 +279,23 @@ public void testSimplifyDateTime() { assertRewrite( "(TA >= timestamp '2024-01-01 00:00:00' and TA <= timestamp '2024-01-03 00:00:00') or (TA > timestamp '2024-01-05 00:00:00' and TA < timestamp '2024-01-07 00:00:00')", "(TA >= timestamp '2024-01-01 00:00:00' and TA <= timestamp '2024-01-03 00:00:00') or (TA > timestamp '2024-01-05 00:00:00' and TA < timestamp '2024-01-07 00:00:00')"); - assertRewrite( + assertRewriteNotNull( "(TA > timestamp '2024-01-03 00:00:10' and TA < timestamp '2024-01-01 00:00:10') or (TA > timestamp '2024-01-07 00:00:10'and TA < timestamp '2024-01-05 00:00:10')", "FALSE"); - assertRewrite("TA > timestamp '2024-01-03 00:00:10' and TA < timestamp '2024-01-01 01:00:00'", "FALSE"); + assertRewrite( + "(TA > timestamp '2024-01-03 00:00:10' and TA < timestamp '2024-01-01 00:00:10') or (TA > timestamp '2024-01-07 00:00:10'and TA < timestamp '2024-01-05 00:00:10')", + "cast(TA as datetime) is null and null"); + assertRewriteNotNull("TA > timestamp '2024-01-03 00:00:10' and TA < timestamp '2024-01-01 01:00:00'", "FALSE"); + assertRewrite("TA > timestamp '2024-01-03 00:00:10' and TA < timestamp '2024-01-01 01:00:00'", "cast(TA as datetime) is null and null"); assertRewrite("TA >= timestamp '2024-01-01 00:00:10' and TA < timestamp '2024-01-01 00:00:10'", "TA >= timestamp '2024-01-01 00:00:10' and TA < timestamp '2024-01-01 00:00:10'"); - assertRewrite("TA = timestamp '2024-01-01 10:00:10' and TA > timestamp '2024-01-10 00:00:10'", "FALSE"); + assertRewriteNotNull("TA = timestamp '2024-01-01 10:00:10' and TA > timestamp '2024-01-10 00:00:10'", "FALSE"); + assertRewrite("TA = timestamp '2024-01-01 10:00:10' and TA > timestamp '2024-01-10 00:00:10'", "cast(TA as datetime) is null and null"); assertRewrite("TA > timestamp '2024-01-05 00:00:10' or TA < timestamp '2024-01-01 00:00:10'", "TA > timestamp '2024-01-05 00:00:10' or TA < timestamp '2024-01-01 00:00:10'"); assertRewrite("TA > timestamp '2024-01-05 00:00:10' or TA > timestamp '2024-01-01 00:00:10' or TA > timestamp '2024-01-10 00:00:10'", "TA > timestamp '2024-01-01 00:00:10'"); - assertRewrite("TA > timestamp '2024-01-05 00:00:10' or TA > timestamp '2024-01-01 00:00:10' or TA < timestamp '2024-01-10 00:00:10'", "cast(TA as datetime) IS NOT NULL"); + assertRewrite("TA > timestamp '2024-01-05 00:00:10' or TA > timestamp '2024-01-01 00:00:10' or TA < timestamp '2024-01-10 00:00:10'", "cast(TA as datetime) is not null or null"); assertRewriteNotNull("TA > timestamp '2024-01-05 00:00:10' or TA > timestamp '2024-01-01 00:00:10' or TA < timestamp '2024-01-10 00:00:10'", "TRUE"); assertRewrite("TA > timestamp '2024-01-05 00:00:10' and TA > timestamp '2024-01-01 00:00:10' and TA > timestamp '2024-01-10 00:00:15'", "TA > timestamp '2024-01-10 00:00:15'"); @@ -267,7 +303,7 @@ public void testSimplifyDateTime() { "TA > timestamp '2024-01-05 00:00:10' and TA < timestamp '2024-01-10 00:00:10'"); assertRewrite("TA > timestamp '2024-01-05 00:00:10' or TA < timestamp '2024-01-05 00:00:10'", "TA > timestamp '2024-01-05 00:00:10' or TA < timestamp '2024-01-05 00:00:10'"); - assertRewrite("TA > timestamp '2024-01-01 00:02:10' or TA < timestamp '2024-01-10 00:02:10'", "cast(TA as datetime) IS NOT NULL"); + assertRewrite("TA > timestamp '2024-01-01 00:02:10' or TA < timestamp '2024-01-10 00:02:10'", "cast(TA as datetime) is not null or null"); assertRewriteNotNull("TA > timestamp '2024-01-01 00:00:00' or TA < timestamp '2024-01-10 00:00:00'", "TRUE"); assertRewrite("TA > timestamp '2024-01-05 01:00:00' and TA < timestamp '2024-01-10 01:00:00'", "TA > timestamp '2024-01-05 01:00:00' and TA < timestamp '2024-01-10 01:00:00'"); @@ -280,8 +316,10 @@ public void testSimplifyDateTime() { assertRewrite( "(TA > timestamp '2024-01-10 01:00:00' or TA > timestamp '2024-01-20 01:00:00') and (TB > timestamp '2024-01-10 01:00:00' and TB < timestamp '2024-01-20 01:00:00')", "TA > timestamp '2024-01-10 01:00:00' and (TB > timestamp '2024-01-10 01:00:00' and TB < timestamp '2024-01-20 01:00:00') "); - assertRewrite("TA in (timestamp '2024-01-01 01:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 03:00:00') and TA > timestamp '2024-01-10 01:00:00'", + assertRewriteNotNull("TA in (timestamp '2024-01-01 01:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 03:00:00') and TA > timestamp '2024-01-10 01:00:00'", "FALSE"); + assertRewrite("TA in (timestamp '2024-01-01 01:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 03:00:00') and TA > timestamp '2024-01-10 01:00:00'", + "cast(TA as datetime) is null and null"); assertRewrite("TA in (timestamp '2024-01-01 01:00:00',timestamp '2024-01-02 01:50:00',timestamp '2024-01-03 02:00:00') and TA >= timestamp '2024-01-01'", "TA in (timestamp '2024-01-01 01:00:00',timestamp '2024-01-02 01:50:00',timestamp '2024-01-03 02:00:00')"); assertRewrite("TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') and TA > timestamp '2024-01-01 02:10:00'", @@ -291,20 +329,27 @@ public void testSimplifyDateTime() { assertRewrite("TA in (timestamp '2024-01-01 02:00:00')", "TA in (timestamp '2024-01-01 02:00:00')"); assertRewrite("TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') and TA < timestamp '2024-01-10 02:00:00'", "TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00')"); - assertRewrite("TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') and TA < timestamp '2024-01-01 02:00:00'", + assertRewriteNotNull("TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') and TA < timestamp '2024-01-01 02:00:00'", "FALSE"); + assertRewrite("TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') and TA < timestamp '2024-01-01 02:00:00'", + "cast(TA as datetime) is null and null"); assertRewrite("TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') and TA < timestamp '2024-01-01 02:00:01'", "TA = timestamp '2024-01-01 02:00:00'"); assertRewrite("TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') or TA < timestamp '2024-01-01 01:00:00'", "TA in (timestamp '2024-01-01 02:00:00',timestamp '2024-01-02 02:00:00',timestamp '2024-01-03 02:00:00') or TA < timestamp '2024-01-01 01:00:00'"); assertRewrite("TA in (timestamp '2024-01-01 00:00:00',timestamp '2024-01-02 00:00:00') or TA in (timestamp '2024-01-02 00:00:00', timestamp '2024-01-03 00:00:00')", "TA in (timestamp '2024-01-01 00:00:00',timestamp '2024-01-02 00:00:00',timestamp '2024-01-03 00:00:00')"); - assertRewrite("TA in (timestamp '2024-01-01 00:50:00',timestamp '2024-01-02 00:50:00') and TA in (timestamp '2024-01-03 00:50:00', timestamp '2024-01-04 00:50:00')", + assertRewriteNotNull("TA in (timestamp '2024-01-01 00:50:00',timestamp '2024-01-02 00:50:00') and TA in (timestamp '2024-01-03 00:50:00', timestamp '2024-01-04 00:50:00')", "FALSE"); - assertRewrite("TA = timestamp '2024-01-03 00:50:00' and TA = timestamp '2024-01-01 00:50:00'", "FALSE"); - assertRewrite("TA in (timestamp '2024-01-01 00:50:00') and TA in (timestamp '2024-01-03 00:50:00')", "FALSE"); + assertRewrite("TA in (timestamp '2024-01-01 00:50:00',timestamp '2024-01-02 00:50:00') and TA in (timestamp '2024-01-03 00:50:00', timestamp '2024-01-04 00:50:00')", + "cast(TA as datetime) is null and null"); + assertRewriteNotNull("TA = timestamp '2024-01-03 00:50:00' and TA = timestamp '2024-01-01 00:50:00'", "FALSE"); + assertRewrite("TA = timestamp '2024-01-03 00:50:00' and TA = timestamp '2024-01-01 00:50:00'", "cast(TA as datetime) is null and null"); + assertRewriteNotNull("TA in (timestamp '2024-01-01 00:50:00') and TA in (timestamp '2024-01-03 00:50:00')", "FALSE"); + assertRewrite("TA in (timestamp '2024-01-01 00:50:00') and TA in (timestamp '2024-01-03 00:50:00')", "cast(TA as datetime) is null and null"); assertRewrite("TA in (timestamp '2024-01-03 00:50:00') and TA in (timestamp '2024-01-03 00:50:00')", "TA = timestamp '2024-01-03 00:50:00'"); - assertRewrite("(TA > timestamp '2024-01-03 00:50:00' and TA < timestamp '2024-01-01 00:50:00') and TB < timestamp '2024-01-05 00:50:00'", "FALSE"); + assertRewriteNotNull("(TA > timestamp '2024-01-03 00:50:00' and TA < timestamp '2024-01-01 00:50:00') and TB < timestamp '2024-01-05 00:50:00'", "FALSE"); + assertRewrite("(TA > timestamp '2024-01-03 00:50:00' and TA < timestamp '2024-01-01 00:50:00') and TB < timestamp '2024-01-05 00:50:00'", "cast(TA as datetime) is null and null"); assertRewrite("(TA > timestamp '2024-01-03 00:50:00' and TA < timestamp '2024-01-01 00:50:00') or TB < timestamp '2024-01-05 00:50:00'", "TB < timestamp '2024-01-05 00:50:00'"); } @@ -374,7 +419,7 @@ private DataType getType(char t) { case 'I': return IntegerType.INSTANCE; case 'D': - return DoubleType.INSTANCE; + return DecimalV3Type.createDecimalV3Type(2, 1); case 'S': return StringType.INSTANCE; case 'B':