You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2017/04/26 22:15:27 UTC
[3/4] calcite git commit: Fix OVERLAPS operator
Fix OVERLAPS operator
Refactor StandardConvertletTable, creating methods to help create
calls to common operators.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/c94a080b
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/c94a080b
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/c94a080b
Branch: refs/heads/master
Commit: c94a080b3520a568e5452cc33ca3a443cf2f50ab
Parents: 39c22f0
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Apr 19 14:46:05 2017 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Apr 26 14:21:11 2017 -0700
----------------------------------------------------------------------
.../sql2rel/StandardConvertletTable.java | 215 ++++++++-----------
.../main/java/org/apache/calcite/util/Bug.java | 7 -
.../calcite/sql/test/SqlOperatorBaseTest.java | 134 ++++++++----
3 files changed, 188 insertions(+), 168 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/c94a080b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 5523c81..90f1ffc 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -361,6 +361,51 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
//~ Methods ----------------------------------------------------------------
+ private RexNode or(RexBuilder rexBuilder, RexNode a0, RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.OR, a0, a1);
+ }
+
+ private RexNode ge(RexBuilder rexBuilder, RexNode a0, RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, a0,
+ a1);
+ }
+
+ private RexNode le(RexBuilder rexBuilder, RexNode a0, RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, a0, a1);
+ }
+
+ private RexNode and(RexBuilder rexBuilder, RexNode a0, RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.AND, a0, a1);
+ }
+
+ private static RexNode divideInt(RexBuilder rexBuilder, RexNode a0,
+ RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE_INTEGER, a0, a1);
+ }
+
+ private RexNode plus(RexBuilder rexBuilder, RexNode a0, RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.PLUS, a0, a1);
+ }
+
+ private RexNode minus(RexBuilder rexBuilder, RexNode a0, RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.MINUS, a0, a1);
+ }
+
+ private static RexNode multiply(RexBuilder rexBuilder, RexNode a0,
+ RexNode a1) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, a0, a1);
+ }
+
+ private RexNode case_(RexBuilder rexBuilder, RexNode... args) {
+ return rexBuilder.makeCall(SqlStdOperatorTable.CASE, args);
+ }
+
+ // SqlNode helpers
+
+ private SqlCall plus(SqlParserPos pos, SqlNode a0, SqlNode a1) {
+ return SqlStdOperatorTable.PLUS.createCall(pos, a0, a1);
+ }
+
/**
* Converts a CASE expression.
*/
@@ -545,45 +590,25 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
interval.getIntervalQualifier().getStartUnit().multiplier;
RexNode rexInterval = cx.convertExpression(literal);
- RexNode res;
-
final RexBuilder rexBuilder = cx.getRexBuilder();
RexNode zero = rexBuilder.makeExactLiteral(BigDecimal.valueOf(0));
- RexNode cond =
- rexBuilder.makeCall(
- SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
- rexInterval,
- zero);
+ RexNode cond = ge(rexBuilder, rexInterval, zero);
RexNode pad =
rexBuilder.makeExactLiteral(val.subtract(BigDecimal.ONE));
RexNode cast = rexBuilder.makeReinterpretCast(
rexInterval.getType(), pad, rexBuilder.makeLiteral(false));
- SqlOperator op =
- floor ? SqlStdOperatorTable.MINUS
- : SqlStdOperatorTable.PLUS;
- RexNode sum = rexBuilder.makeCall(op, rexInterval, cast);
-
- RexNode kase =
- floor
- ? rexBuilder.makeCall(SqlStdOperatorTable.CASE,
- cond, rexInterval, sum)
- : rexBuilder.makeCall(SqlStdOperatorTable.CASE,
- cond, sum, rexInterval);
+ RexNode sum = floor
+ ? minus(rexBuilder, rexInterval, cast)
+ : plus(rexBuilder, rexInterval, cast);
+
+ RexNode kase = floor
+ ? case_(rexBuilder, rexInterval, cond, sum)
+ : case_(rexBuilder, sum, cond, rexInterval);
RexNode factor = rexBuilder.makeExactLiteral(val);
- RexNode div =
- rexBuilder.makeCall(
- SqlStdOperatorTable.DIVIDE_INTEGER,
- kase,
- factor);
- RexNode mult =
- rexBuilder.makeCall(
- SqlStdOperatorTable.MULTIPLY,
- div,
- factor);
- res = mult;
- return res;
+ RexNode div = divideInt(rexBuilder, kase, factor);
+ return multiply(rexBuilder, div, factor);
}
// normal floor, ceil function
@@ -667,10 +692,10 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
case DATE:
res = rexBuilder.makeCall(resType, SqlStdOperatorTable.EXTRACT_DATE,
ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), res));
- res = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, res,
- rexBuilder.makeExactLiteral(BigDecimal.ONE));
+ res =
+ minus(rexBuilder, res, rexBuilder.makeExactLiteral(BigDecimal.ONE));
res = divide(rexBuilder, res, unit.multiplier);
- return rexBuilder.makeCall(SqlStdOperatorTable.PLUS, res,
+ return plus(rexBuilder, res,
rexBuilder.makeExactLiteral(BigDecimal.ONE));
}
break;
@@ -731,13 +756,11 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
res = mod(rexBuilder, resType, res, getFactor(unit));
if (unit == TimeUnit.QUARTER) {
- res = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, res,
- rexBuilder.makeExactLiteral(BigDecimal.ONE));
+ res = minus(rexBuilder, res, rexBuilder.makeExactLiteral(BigDecimal.ONE));
}
res = divide(rexBuilder, res, unit.multiplier);
if (unit == TimeUnit.QUARTER) {
- res = rexBuilder.makeCall(SqlStdOperatorTable.PLUS, res,
- rexBuilder.makeExactLiteral(BigDecimal.ONE));
+ res = plus(rexBuilder, res, rexBuilder.makeExactLiteral(BigDecimal.ONE));
}
return res;
}
@@ -787,14 +810,13 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
try {
final BigDecimal reciprocal =
BigDecimal.ONE.divide(val, RoundingMode.UNNECESSARY);
- return rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY, res,
+ return multiply(rexBuilder, res,
rexBuilder.makeExactLiteral(reciprocal));
} catch (ArithmeticException e) {
// ignore - reciprocal is not an integer
}
}
- return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE_INTEGER, res,
- rexBuilder.makeExactLiteral(val));
+ return divideInt(rexBuilder, res, rexBuilder.makeExactLiteral(val));
}
public RexNode convertDatetimeMinus(
@@ -1091,19 +1113,9 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
final RexNode z = list.get(SqlBetweenOperator.UPPER_OPERAND);
final RexBuilder rexBuilder = cx.getRexBuilder();
- RexNode ge1 =
- rexBuilder.makeCall(
- SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, x, y);
- RexNode le1 =
- rexBuilder.makeCall(
- SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
- x,
- z);
- RexNode and1 =
- rexBuilder.makeCall(
- SqlStdOperatorTable.AND,
- ge1,
- le1);
+ RexNode ge1 = ge(rexBuilder, x, y);
+ RexNode le1 = le(rexBuilder, x, z);
+ RexNode and1 = and(rexBuilder, ge1, le1);
RexNode res;
final SqlBetweenOperator.Flag symmetric = op.flag;
@@ -1112,26 +1124,10 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
res = and1;
break;
case SYMMETRIC:
- RexNode ge2 =
- rexBuilder.makeCall(
- SqlStdOperatorTable.GREATER_THAN_OR_EQUAL,
- x,
- z);
- RexNode le2 =
- rexBuilder.makeCall(
- SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
- x,
- y);
- RexNode and2 =
- rexBuilder.makeCall(
- SqlStdOperatorTable.AND,
- ge2,
- le2);
- res =
- rexBuilder.makeCall(
- SqlStdOperatorTable.OR,
- and1,
- and2);
+ RexNode ge2 = ge(rexBuilder, x, z);
+ RexNode le2 = le(rexBuilder, x, y);
+ RexNode and2 = and(rexBuilder, ge2, le2);
+ res = or(rexBuilder, and1, and2);
break;
default:
throw Util.unexpected(symmetric);
@@ -1198,60 +1194,33 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
// intervals overlaps by: ~(t1 < t2 or t3 < t0)
final SqlNode[] operands = ((SqlBasicCall) call).getOperands();
assert operands.length == 4;
- if (operands[1] instanceof SqlIntervalLiteral) {
+ final SqlParserPos pos = call.getParserPosition();
+ final RelDataType t1 = cx.getValidator().getValidatedNodeType(operands[1]);
+ if (SqlTypeUtil.isInterval(t1)) {
// make t1 = t0 + t1 when t1 is an interval.
- SqlOperator op1 = SqlStdOperatorTable.PLUS;
- SqlNode[] second = new SqlNode[2];
- second[0] = operands[0];
- second[1] = operands[1];
- operands[1] =
- op1.createCall(
- call.getParserPosition(),
- second);
+ operands[1] = plus(pos, operands[0], operands[1]);
}
- if (operands[3] instanceof SqlIntervalLiteral) {
+ final RelDataType t3 = cx.getValidator().getValidatedNodeType(operands[3]);
+ if (SqlTypeUtil.isInterval(t3)) {
// make t3 = t2 + t3 when t3 is an interval.
- SqlOperator op1 = SqlStdOperatorTable.PLUS;
- SqlNode[] four = new SqlNode[2];
- four[0] = operands[2];
- four[1] = operands[3];
- operands[3] =
- op1.createCall(
- call.getParserPosition(),
- four);
+ operands[3] = plus(pos, operands[2], operands[3]);
}
- // This captures t1 >= t2
- SqlOperator op1 = SqlStdOperatorTable.GREATER_THAN_OR_EQUAL;
- SqlNode[] left = new SqlNode[2];
- left[0] = operands[1];
- left[1] = operands[2];
- SqlCall call1 =
- op1.createCall(
- call.getParserPosition(),
- left);
-
- // This captures t3 >= t0
- SqlOperator op2 = SqlStdOperatorTable.GREATER_THAN_OR_EQUAL;
- SqlNode[] right = new SqlNode[2];
- right[0] = operands[3];
- right[1] = operands[0];
- SqlCall call2 =
- op2.createCall(
- call.getParserPosition(),
- right);
-
- // This captures t1 >= t2 and t3 >= t0
- SqlOperator and = SqlStdOperatorTable.AND;
- SqlNode[] overlaps = new SqlNode[2];
- overlaps[0] = call1;
- overlaps[1] = call2;
- SqlCall call3 =
- and.createCall(
- call.getParserPosition(),
- overlaps);
-
- return cx.convertExpression(call3);
+ final RexNode r0 = cx.convertExpression(operands[0]);
+ final RexNode r1 = cx.convertExpression(operands[1]);
+ final RexNode r2 = cx.convertExpression(operands[2]);
+ final RexNode r3 = cx.convertExpression(operands[3]);
+
+ // Sort end points into start and end, such that (s0 <= e0) and (s1 <= e1).
+ final RexBuilder rexBuilder = cx.getRexBuilder();
+ final RexNode s0 = case_(rexBuilder, le(rexBuilder, r0, r1), r0, r1);
+ final RexNode e0 = case_(rexBuilder, le(rexBuilder, r0, r1), r1, r0);
+ final RexNode s1 = case_(rexBuilder, le(rexBuilder, r2, r3), r2, r3);
+ final RexNode e1 = case_(rexBuilder, le(rexBuilder, r2, r3), r3, r2);
+ // (e0 >= s1) AND (e1 >= s0)
+ return and(rexBuilder,
+ ge(rexBuilder, e0, s1),
+ ge(rexBuilder, e1, s0));
}
/**
@@ -1484,7 +1453,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
final TimeUnit unit = unitLiteral.symbolValue(TimeUnit.class);
return rexBuilder.makeCall(SqlStdOperatorTable.DATETIME_PLUS,
cx.convertExpression(call.operand(2)),
- rexBuilder.makeCall(SqlStdOperatorTable.MULTIPLY,
+ multiply(rexBuilder,
rexBuilder.makeIntervalLiteral(unit.multiplier,
new SqlIntervalQualifier(unit, null,
unitLiteral.getParserPosition())),
http://git-wip-us.apache.org/repos/asf/calcite/blob/c94a080b/core/src/main/java/org/apache/calcite/util/Bug.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Bug.java b/core/src/main/java/org/apache/calcite/util/Bug.java
index 1adc2fe..e5d7096 100644
--- a/core/src/main/java/org/apache/calcite/util/Bug.java
+++ b/core/src/main/java/org/apache/calcite/util/Bug.java
@@ -108,13 +108,6 @@ public abstract class Bug {
public static final boolean FRG78_FIXED = false;
/**
- * Whether <a href="http://issues.eigenbase.org/browse/FRG-187">issue
- * FRG-187: FarragoAutoVmOperatorTest.testOverlapsOperator fails</a> is
- * fixed.
- */
- public static final boolean FRG187_FIXED = false;
-
- /**
* Whether <a href="http://issues.eigenbase.org/browse/FRG-189">issue
* FRG-189: FarragoAutoVmOperatorTest.testSelect fails</a> is fixed.
*/
http://git-wip-us.apache.org/repos/asf/calcite/blob/c94a080b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 2ba92ac..ff3c0e2 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -2313,46 +2313,80 @@ public abstract class SqlOperatorBaseTest {
@Test public void testOverlapsOperator() {
tester.setFor(SqlStdOperatorTable.OVERLAPS, VM_EXPAND);
- if (Bug.FRG187_FIXED) {
- tester.checkBoolean(
- "(date '1-2-3', date '1-2-3') overlaps (date '1-2-3', interval '1' year)",
- Boolean.TRUE);
- tester.checkBoolean(
- "(date '1-2-3', date '1-2-3') overlaps (date '4-5-6', interval '1' year)",
- Boolean.FALSE);
- tester.checkBoolean(
- "(date '1-2-3', date '4-5-6') overlaps (date '2-2-3', date '3-4-5')",
- Boolean.TRUE);
- tester.checkNull(
- "(cast(null as date), date '1-2-3') overlaps (date '1-2-3', interval '1' year)");
- tester.checkNull(
- "(date '1-2-3', date '1-2-3') overlaps (date '1-2-3', cast(null as date))");
+ tester.checkBoolean(
+ "(date '1-2-3', date '1-2-3') overlaps (date '1-2-3', interval '1' year)",
+ Boolean.TRUE);
+ tester.checkBoolean(
+ "(date '1-2-3', date '1-2-3') overlaps (date '4-5-6', interval '1' year)",
+ Boolean.FALSE);
+ tester.checkBoolean(
+ "(date '1-2-3', date '4-5-6') overlaps (date '2-2-3', date '3-4-5')",
+ Boolean.TRUE);
+ tester.checkNull(
+ "(cast(null as date), date '1-2-3') overlaps (date '1-2-3', interval '1' year)");
+ tester.checkNull(
+ "(date '1-2-3', date '1-2-3') overlaps (date '1-2-3', cast(null as date))");
- tester.checkBoolean(
- "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', time '1:2:3')",
- Boolean.TRUE);
- tester.checkBoolean(
- "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', time '1:2:2')",
- Boolean.FALSE);
- tester.checkBoolean(
- "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', interval '2' hour)",
- Boolean.TRUE);
- tester.checkNull(
- "(time '1:2:3', cast(null as time)) overlaps (time '23:59:59', time '1:2:3')");
- tester.checkNull(
- "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', cast(null as interval hour))");
+ tester.checkBoolean(
+ "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', time '1:2:3')",
+ Boolean.TRUE);
+ tester.checkBoolean(
+ "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', time '1:2:2')",
+ Boolean.TRUE);
+ tester.checkBoolean(
+ "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', interval '2' hour)",
+ Boolean.FALSE);
+ tester.checkNull(
+ "(time '1:2:3', cast(null as time)) overlaps (time '23:59:59', time '1:2:3')");
+ tester.checkNull(
+ "(time '1:2:3', interval '1' second) overlaps (time '23:59:59', cast(null as interval hour))");
- tester.checkBoolean(
- "(timestamp '1-2-3 4:5:6', timestamp '1-2-3 4:5:6' ) overlaps (timestamp '1-2-3 4:5:6', interval '1 2:3:4.5' day to second)",
- Boolean.TRUE);
- tester.checkBoolean(
- "(timestamp '1-2-3 4:5:6', timestamp '1-2-3 4:5:6' ) overlaps (timestamp '2-2-3 4:5:6', interval '1 2:3:4.5' day to second)",
- Boolean.FALSE);
- tester.checkNull(
- "(timestamp '1-2-3 4:5:6', cast(null as interval day) ) overlaps (timestamp '1-2-3 4:5:6', interval '1 2:3:4.5' day to second)");
- tester.checkNull(
- "(timestamp '1-2-3 4:5:6', timestamp '1-2-3 4:5:6' ) overlaps (cast(null as timestamp), interval '1 2:3:4.5' day to second)");
- }
+ tester.checkBoolean(
+ "(timestamp '1-2-3 4:5:6', timestamp '1-2-3 4:5:6' ) overlaps (timestamp '1-2-3 4:5:6', interval '1 2:3:4.5' day to second)",
+ Boolean.TRUE);
+ tester.checkBoolean(
+ "(timestamp '1-2-3 4:5:6', timestamp '1-2-3 4:5:6' ) overlaps (timestamp '2-2-3 4:5:6', interval '1 2:3:4.5' day to second)",
+ Boolean.FALSE);
+ tester.checkNull(
+ "(timestamp '1-2-3 4:5:6', cast(null as interval day) ) overlaps (timestamp '1-2-3 4:5:6', interval '1 2:3:4.5' day to second)");
+ tester.checkNull(
+ "(timestamp '1-2-3 4:5:6', timestamp '1-2-3 4:5:6' ) overlaps (cast(null as timestamp), interval '1 2:3:4.5' day to second)");
+ }
+
+ @Test public void testOverlapsEtc() {
+ String[] times = {
+ "TIME '01:00:00'",
+ "TIME '02:00:00'",
+ "TIME '03:00:00'",
+ "TIME '04:00:00'",
+ };
+ String[] dates = {
+ "DATE '1970-01-01'",
+ "DATE '1970-02-01'",
+ "DATE '1970-03-01'",
+ "DATE '1970-04-01'",
+ };
+ String[] timestamps = {
+ "TIMESTAMP '1970-01-01 00:00:00'",
+ "TIMESTAMP '1970-02-01 00:00:00'",
+ "TIMESTAMP '1970-03-01 00:00:00'",
+ "TIMESTAMP '1970-04-01 00:00:00'",
+ };
+ checkOverlaps(new OverlapChecker(times));
+ checkOverlaps(new OverlapChecker(dates));
+ checkOverlaps(new OverlapChecker(timestamps));
+ }
+
+ private void checkOverlaps(OverlapChecker c) {
+ c.isFalse("($0,$1) OVERLAPS ($2,$3)");
+ c.isTrue("($0,$1) OVERLAPS ($1,$2)");
+ c.isTrue("($0,$2) OVERLAPS ($1,$3)");
+ c.isTrue("($0,$2) OVERLAPS ($3,$1)");
+ c.isTrue("($2,$0) OVERLAPS ($3,$1)");
+ c.isFalse("($3,$2) OVERLAPS ($1,$0)");
+ c.isTrue("($2,$3) OVERLAPS ($0,$2)");
+ c.isTrue("($2,$3) OVERLAPS ($2,$0)");
+ c.isTrue("($3,$2) OVERLAPS ($2,$0)");
}
@Test public void testLessThanOperator() {
@@ -6743,6 +6777,30 @@ public abstract class SqlOperatorBaseTest {
this.values.add(new ValueType(type, null));
}
}
+
+ /** Runs an OVERLAPS test with a given set of literal values. */
+ class OverlapChecker {
+ final String[] values;
+
+ OverlapChecker(String... values) {
+ this.values = values;
+ }
+
+ public void isTrue(String s) {
+ tester.checkBoolean(sub(s), Boolean.TRUE);
+ }
+
+ public void isFalse(String s) {
+ tester.checkBoolean(sub(s), Boolean.FALSE);
+ }
+
+ private String sub(String s) {
+ return s.replace("$0", values[0])
+ .replace("$1", values[1])
+ .replace("$2", values[2])
+ .replace("$3", values[3]);
+ }
+ }
}
// End SqlOperatorBaseTest.java