[CALCITE-1987] Implement EXTRACT for JDBC (Pavel Gubin) Remove EXTRACT_DATE function (it's all just EXTRACTi now), and revise Druid adapter.
Close apache/calcite#539 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/796a28f9 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/796a28f9 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/796a28f9 Branch: refs/heads/master Commit: 796a28f9a9d49a16971135074f315d536eb929cf Parents: 8441e79 Author: pavelgubin <[email protected]> Authored: Thu Sep 14 14:53:41 2017 +0200 Committer: Julian Hyde <[email protected]> Committed: Mon Oct 2 11:13:43 2017 -0700 ---------------------------------------------------------------------- .../calcite/adapter/enumerable/RexImpTable.java | 163 ++++++++++++++++++- .../calcite/sql/fun/SqlStdOperatorTable.java | 5 - .../sql2rel/StandardConvertletTable.java | 154 +----------------- .../calcite/rel/rules/DateRangeRulesTest.java | 118 ++++++-------- .../java/org/apache/calcite/test/JdbcTest.java | 24 +++ .../apache/calcite/test/SqlValidatorTest.java | 1 - .../org/apache/calcite/test/RelOptRulesTest.xml | 20 +-- .../org/apache/calcite/test/DruidAdapterIT.java | 64 ++++---- .../calcite/test/DruidDateRangeRulesTest.java | 24 +-- 9 files changed, 283 insertions(+), 290 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java index 0b3aa84..3f99182 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java @@ -125,7 +125,7 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE_INTEGER; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ELEMENT; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EQUALS; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXP; -import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXTRACT_DATE; +import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXTRACT; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.FIRST_VALUE; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.FLOOR; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GREATER_THAN; @@ -323,8 +323,8 @@ public class RexImpTable { new DatetimeArithmeticImplementor(), false); defineImplementor(MINUS_DATE, NullPolicy.STRICT, new DatetimeArithmeticImplementor(), false); - defineMethod(EXTRACT_DATE, BuiltInMethod.UNIX_DATE_EXTRACT.method, - NullPolicy.STRICT); + defineImplementor(EXTRACT, NullPolicy.STRICT, + new ExtractImplementor(), false); defineImplementor(FLOOR, NullPolicy.STRICT, new FloorImplementor(BuiltInMethod.FLOOR.method.getName(), BuiltInMethod.UNIX_TIMESTAMP_FLOOR.method, @@ -1889,6 +1889,163 @@ public class RexImpTable { } } + /** Implementor for the {@code EXTRACT(unit FROM datetime)} function. */ + private static class ExtractImplementor implements NotNullImplementor { + public Expression implement(RexToLixTranslator translator, RexCall call, + List<Expression> translatedOperands) { + final TimeUnitRange timeUnitRange = + (TimeUnitRange) ((ConstantExpression) translatedOperands.get(0)).value; + final TimeUnit unit = timeUnitRange.startUnit; + Expression operand = translatedOperands.get(1); + final SqlTypeName sqlTypeName = + call.operands.get(1).getType().getSqlTypeName(); + switch (unit) { + case MILLENNIUM: + case CENTURY: + case YEAR: + case QUARTER: + case MONTH: + case DAY: + case DOW: + case DOY: + case WEEK: + switch (sqlTypeName) { + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: + case INTERVAL_DAY: + case INTERVAL_DAY_HOUR: + case INTERVAL_DAY_MINUTE: + case INTERVAL_DAY_SECOND: + case INTERVAL_HOUR: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_HOUR_SECOND: + case INTERVAL_MINUTE: + case INTERVAL_MINUTE_SECOND: + case INTERVAL_SECOND: + break; + case TIMESTAMP_WITH_LOCAL_TIME_ZONE: + operand = Expressions.call( + BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method, + operand, + Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot())); + // fall through + case TIMESTAMP: + operand = Expressions.divide(operand, + Expressions.constant(TimeUnit.DAY.multiplier.longValue())); + // fall through + case DATE: + return Expressions.call(BuiltInMethod.UNIX_DATE_EXTRACT.method, + translatedOperands.get(0), operand); + default: + throw new AssertionError("unexpected " + sqlTypeName); + } + break; + case DECADE: + switch (sqlTypeName) { + case TIMESTAMP_WITH_LOCAL_TIME_ZONE: + operand = Expressions.call( + BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method, + operand, + Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot())); + // fall through + case TIMESTAMP: + operand = Expressions.divide(operand, + Expressions.constant(TimeUnit.DAY.multiplier.longValue())); + // fall through + case DATE: + operand = Expressions.call( + BuiltInMethod.UNIX_DATE_EXTRACT.method, + Expressions.constant(TimeUnitRange.YEAR), operand); + return Expressions.divide(operand, + Expressions.constant( + unit.multiplier.divideToIntegralValue(TimeUnit.YEAR.multiplier) + .longValue())); + } + break; + case EPOCH: + switch (sqlTypeName) { + case DATE: + // convert to milliseconds + operand = Expressions.multiply(operand, + Expressions.constant(TimeUnit.DAY.multiplier.longValue())); + // fall through + case TIMESTAMP: + // convert to seconds + return Expressions.divide(operand, + Expressions.constant(TimeUnit.SECOND.multiplier.longValue())); + case TIMESTAMP_WITH_LOCAL_TIME_ZONE: + operand = Expressions.call( + BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method, + operand, + Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot())); + return Expressions.divide(operand, + Expressions.constant(TimeUnit.SECOND.multiplier.longValue())); + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: + case INTERVAL_DAY: + case INTERVAL_DAY_HOUR: + case INTERVAL_DAY_MINUTE: + case INTERVAL_DAY_SECOND: + case INTERVAL_HOUR: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_HOUR_SECOND: + case INTERVAL_MINUTE: + case INTERVAL_MINUTE_SECOND: + case INTERVAL_SECOND: + // no convertlet conversion, pass it as extract + throw new AssertionError("unexpected " + sqlTypeName); + } + break; + } + + operand = mod(operand, getFactor(unit)); + if (unit == TimeUnit.QUARTER) { + operand = Expressions.subtract(operand, Expressions.constant(1L)); + } + operand = Expressions.divide(operand, + Expressions.constant(unit.multiplier.longValue())); + if (unit == TimeUnit.QUARTER) { + operand = Expressions.add(operand, Expressions.constant(1L)); + } + return operand; + } + + } + + private static Expression mod(Expression operand, long factor) { + if (factor == 1L) { + return operand; + } else { + return Expressions.modulo(operand, Expressions.constant(factor)); + } + } + + private static long getFactor(TimeUnit unit) { + switch (unit) { + case DAY: + return 1L; + case HOUR: + return TimeUnit.DAY.multiplier.longValue(); + case MINUTE: + return TimeUnit.HOUR.multiplier.longValue(); + case SECOND: + return TimeUnit.MINUTE.multiplier.longValue(); + case MONTH: + return TimeUnit.YEAR.multiplier.longValue(); + case QUARTER: + return TimeUnit.YEAR.multiplier.longValue(); + case YEAR: + case DECADE: + case CENTURY: + case MILLENNIUM: + return 1L; + default: + throw Util.unexpected(unit); + } + } + /** Implementor for the SQL {@code CASE} operator. */ private static class CaseImplementor implements CallImplementor { public Expression implement(RexToLixTranslator translator, RexCall call, http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java index 7b6b771..c8adf5e 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java @@ -1235,11 +1235,6 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable { } }; - /** Internal operator that extracts time periods (year, month, date) from a - * date in internal format (number of days since epoch). */ - public static final SqlSpecialOperator EXTRACT_DATE = - new SqlSpecialOperator("EXTRACT_DATE", SqlKind.EXTRACT); - //------------------------------------------------------------- // FUNCTIONS //------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/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 14bff94..4c45716 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java @@ -18,7 +18,6 @@ package org.apache.calcite.sql2rel; import org.apache.calcite.avatica.util.DateTimeUtils; import org.apache.calcite.avatica.util.TimeUnit; -import org.apache.calcite.avatica.util.TimeUnitRange; import org.apache.calcite.plan.RelOptUtil; import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rel.type.RelDataType; @@ -635,158 +634,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { SqlRexContext cx, SqlExtractFunction op, SqlCall call) { - final RexBuilder rexBuilder = cx.getRexBuilder(); - final List<SqlNode> operands = call.getOperandList(); - final List<RexNode> exprs = convertExpressionList(cx, operands, - SqlOperandTypeChecker.Consistency.NONE); - - // TODO: Will need to use decimal type for seconds with precision - RelDataType resType = - cx.getTypeFactory().createSqlType(SqlTypeName.BIGINT); - resType = - cx.getTypeFactory().createTypeWithNullability( - resType, - exprs.get(1).getType().isNullable()); - RexNode res = rexBuilder.makeReinterpretCast( - resType, exprs.get(1), rexBuilder.makeLiteral(false)); - - final TimeUnit unit = - ((SqlIntervalQualifier) operands.get(0)).getStartUnit(); - final SqlTypeName sqlTypeName = exprs.get(1).getType().getSqlTypeName(); - switch (unit) { - case MILLENNIUM: - case CENTURY: - case YEAR: - case QUARTER: - case MONTH: - case DAY: - case DOW: - case DOY: - case WEEK: - switch (sqlTypeName) { - case INTERVAL_YEAR: - case INTERVAL_YEAR_MONTH: - case INTERVAL_MONTH: - case INTERVAL_DAY: - case INTERVAL_DAY_HOUR: - case INTERVAL_DAY_MINUTE: - case INTERVAL_DAY_SECOND: - case INTERVAL_HOUR: - case INTERVAL_HOUR_MINUTE: - case INTERVAL_HOUR_SECOND: - case INTERVAL_MINUTE: - case INTERVAL_MINUTE_SECOND: - case INTERVAL_SECOND: - break; - case TIMESTAMP_WITH_LOCAL_TIME_ZONE: - RelDataType type = - cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP); - type = cx.getTypeFactory().createTypeWithNullability( - type, - exprs.get(1).getType().isNullable()); - res = rexBuilder.makeCast(type, res); - // fall through - case TIMESTAMP: - res = divide(rexBuilder, res, TimeUnit.DAY.multiplier); - // fall through - case DATE: - return rexBuilder.makeCall(resType, SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(exprs.get(0), res)); - default: - throw new AssertionError("unexpected " + sqlTypeName); - } - break; - case DECADE: - switch (sqlTypeName) { - case TIMESTAMP_WITH_LOCAL_TIME_ZONE: - RelDataType type = - cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP); - type = cx.getTypeFactory().createTypeWithNullability( - type, - exprs.get(1).getType().isNullable()); - res = rexBuilder.makeCast(type, res); - // fall through - case TIMESTAMP: - res = divide(rexBuilder, res, TimeUnit.DAY.multiplier); - // fall through - case DATE: - res = rexBuilder.makeCall(resType, SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), res)); - return divide(rexBuilder, res, unit.multiplier.divide(TimeUnit.YEAR.multiplier)); - } - break; - case EPOCH: - switch (sqlTypeName) { - case DATE: - // convert to milliseconds - res = rexBuilder.makeCall(resType, SqlStdOperatorTable.MULTIPLY, - ImmutableList.of(res, rexBuilder.makeExactLiteral(TimeUnit.DAY.multiplier))); - // fall through - case TIMESTAMP: - // convert to seconds - return divide(rexBuilder, res, TimeUnit.SECOND.multiplier); - case TIMESTAMP_WITH_LOCAL_TIME_ZONE: - RelDataType type = - cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP); - type = cx.getTypeFactory().createTypeWithNullability( - type, - exprs.get(1).getType().isNullable()); - return divide( - rexBuilder, - rexBuilder.makeCast(type, res), - TimeUnit.SECOND.multiplier); - case INTERVAL_YEAR: - case INTERVAL_YEAR_MONTH: - case INTERVAL_MONTH: - case INTERVAL_DAY: - case INTERVAL_DAY_HOUR: - case INTERVAL_DAY_MINUTE: - case INTERVAL_DAY_SECOND: - case INTERVAL_HOUR: - case INTERVAL_HOUR_MINUTE: - case INTERVAL_HOUR_SECOND: - case INTERVAL_MINUTE: - case INTERVAL_MINUTE_SECOND: - case INTERVAL_SECOND: - // no convertlet conversion, pass it as extract - return convertFunction(cx, (SqlFunction) call.getOperator(), call); - } - break; - } - - res = mod(rexBuilder, resType, res, getFactor(unit)); - if (unit == TimeUnit.QUARTER) { - res = minus(rexBuilder, res, rexBuilder.makeExactLiteral(BigDecimal.ONE)); - } - res = divide(rexBuilder, res, unit.multiplier); - if (unit == TimeUnit.QUARTER) { - res = plus(rexBuilder, res, rexBuilder.makeExactLiteral(BigDecimal.ONE)); - } - return res; - } - - private static BigDecimal getFactor(TimeUnit unit) { - switch (unit) { - case DAY: - return BigDecimal.ONE; - case HOUR: - return TimeUnit.DAY.multiplier; - case MINUTE: - return TimeUnit.HOUR.multiplier; - case SECOND: - return TimeUnit.MINUTE.multiplier; - case MONTH: - return TimeUnit.YEAR.multiplier; - case QUARTER: - return TimeUnit.YEAR.multiplier; - case YEAR: - case DECADE: - case CENTURY: - case MILLENNIUM: - return BigDecimal.ONE; - default: - throw Util.unexpected(unit); - } + return convertFunction(cx, (SqlFunction) call.getOperator(), call); } private RexNode mod(RexBuilder rexBuilder, RelDataType resType, RexNode res, http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java index ea7b58b..5fd746d 100644 --- a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java @@ -53,34 +53,34 @@ public class DateRangeRulesTest { assertThat(DateRangeRules.extractTimeUnits(f.literal(1)), is(set())); // extract YEAR from a DATE column - checkDateRange(f, e, is("AND(>=($8, 2014-01-01), <($8, 2015-01-01))")); + checkDateRange(f, e, is("AND(>=($9, 2014-01-01), <($9, 2015-01-01))")); checkDateRange(f, f.eq(f.exYear, f.literal(2014)), - is("AND(>=($8, 2014-01-01), <($8, 2015-01-01))")); + is("AND(>=($9, 2014-01-01), <($9, 2015-01-01))")); checkDateRange(f, f.ge(f.exYear, f.literal(2014)), - is(">=($8, 2014-01-01)")); + is(">=($9, 2014-01-01)")); checkDateRange(f, f.gt(f.exYear, f.literal(2014)), - is(">=($8, 2015-01-01)")); + is(">=($9, 2015-01-01)")); checkDateRange(f, f.lt(f.exYear, f.literal(2014)), - is("<($8, 2014-01-01)")); + is("<($9, 2014-01-01)")); checkDateRange(f, f.le(f.exYear, f.literal(2014)), - is("<($8, 2015-01-01)")); + is("<($9, 2015-01-01)")); checkDateRange(f, f.ne(f.exYear, f.literal(2014)), - is("<>(EXTRACT_DATE(FLAG(YEAR), $8), 2014)")); + is("<>(EXTRACT(FLAG(YEAR), $9), 2014)")); } @Test public void testExtractYearFromTimestampColumn() { final Fixture2 f = new Fixture2(); - checkDateRange(f, f.eq(f.exYearTs, f.literal(2014)), + checkDateRange(f, f.eq(f.exYear, f.literal(2014)), is("AND(>=($9, 2014-01-01), <($9, 2015-01-01))")); - checkDateRange(f, f.ge(f.exYearTs, f.literal(2014)), + checkDateRange(f, f.ge(f.exYear, f.literal(2014)), is(">=($9, 2014-01-01)")); - checkDateRange(f, f.gt(f.exYearTs, f.literal(2014)), + checkDateRange(f, f.gt(f.exYear, f.literal(2014)), is(">=($9, 2015-01-01)")); - checkDateRange(f, f.lt(f.exYearTs, f.literal(2014)), + checkDateRange(f, f.lt(f.exYear, f.literal(2014)), is("<($9, 2014-01-01)")); - checkDateRange(f, f.le(f.exYearTs, f.literal(2014)), + checkDateRange(f, f.le(f.exYear, f.literal(2014)), is("<($9, 2015-01-01)")); - checkDateRange(f, f.ne(f.exYearTs, f.literal(2014)), + checkDateRange(f, f.ne(f.exYear, f.literal(2014)), is("<>(EXTRACT(FLAG(YEAR), $9), 2014)")); } @@ -88,10 +88,10 @@ public class DateRangeRulesTest { final Fixture2 f = new Fixture2(); checkDateRange(f, f.and(f.eq(f.exYear, f.literal(2014)), f.eq(f.exMonth, f.literal(6))), - is("AND(AND(>=($8, 2014-01-01), <($8, 2015-01-01))," - + " AND(>=($8, 2014-06-01), <($8, 2014-07-01)))"), - is("AND(>=($8, 2014-01-01), <($8, 2015-01-01)," - + " >=($8, 2014-06-01), <($8, 2014-07-01))")); + is("AND(AND(>=($9, 2014-01-01), <($9, 2015-01-01))," + + " AND(>=($9, 2014-06-01), <($9, 2014-07-01)))"), + is("AND(>=($9, 2014-01-01), <($9, 2015-01-01)," + + " >=($9, 2014-06-01), <($9, 2014-07-01))")); } /** Test case for @@ -100,16 +100,16 @@ public class DateRangeRulesTest { @Test public void testExtractYearAndMonthFromDateColumn2() { final Fixture2 f = new Fixture2(); final String s1 = "AND(" - + "AND(>=($8, 2000-01-01), <($8, 2001-01-01))," + + "AND(>=($9, 2000-01-01), <($9, 2001-01-01))," + " OR(" - + "AND(>=($8, 2000-02-01), <($8, 2000-03-01)), " - + "AND(>=($8, 2000-03-01), <($8, 2000-04-01)), " - + "AND(>=($8, 2000-05-01), <($8, 2000-06-01))))"; - final String s2 = "AND(>=($8, 2000-01-01), <($8, 2001-01-01)," + + "AND(>=($9, 2000-02-01), <($9, 2000-03-01)), " + + "AND(>=($9, 2000-03-01), <($9, 2000-04-01)), " + + "AND(>=($9, 2000-05-01), <($9, 2000-06-01))))"; + final String s2 = "AND(>=($9, 2000-01-01), <($9, 2001-01-01)," + " OR(" - + "AND(>=($8, 2000-02-01), <($8, 2000-03-01)), " - + "AND(>=($8, 2000-03-01), <($8, 2000-04-01)), " - + "AND(>=($8, 2000-05-01), <($8, 2000-06-01))))"; + + "AND(>=($9, 2000-02-01), <($9, 2000-03-01)), " + + "AND(>=($9, 2000-03-01), <($9, 2000-04-01)), " + + "AND(>=($9, 2000-05-01), <($9, 2000-06-01))))"; final RexNode e = f.and(f.eq(f.exYear, f.literal(2000)), f.or(f.eq(f.exMonth, f.literal(2)), @@ -122,14 +122,14 @@ public class DateRangeRulesTest { final Fixture2 f = new Fixture2(); checkDateRange(f, f.and(f.eq(f.exYear, f.literal(2010)), f.eq(f.exDay, f.literal(31))), - is("AND(AND(>=($8, 2010-01-01), <($8, 2011-01-01))," - + " OR(AND(>=($8, 2010-01-31), <($8, 2010-02-01))," - + " AND(>=($8, 2010-03-31), <($8, 2010-04-01))," - + " AND(>=($8, 2010-05-31), <($8, 2010-06-01))," - + " AND(>=($8, 2010-07-31), <($8, 2010-08-01))," - + " AND(>=($8, 2010-08-31), <($8, 2010-09-01))," - + " AND(>=($8, 2010-10-31), <($8, 2010-11-01))," - + " AND(>=($8, 2010-12-31), <($8, 2011-01-01))))")); + is("AND(AND(>=($9, 2010-01-01), <($9, 2011-01-01))," + + " OR(AND(>=($9, 2010-01-31), <($9, 2010-02-01))," + + " AND(>=($9, 2010-03-31), <($9, 2010-04-01))," + + " AND(>=($9, 2010-05-31), <($9, 2010-06-01))," + + " AND(>=($9, 2010-07-31), <($9, 2010-08-01))," + + " AND(>=($9, 2010-08-31), <($9, 2010-09-01))," + + " AND(>=($9, 2010-10-31), <($9, 2010-11-01))," + + " AND(>=($9, 2010-12-31), <($9, 2011-01-01))))")); } @@ -139,32 +139,32 @@ public class DateRangeRulesTest { // namely 29th February 2012 and 2016. // // Currently there are redundant conditions, e.g. - // "AND(>=($8, 2011-01-01), <($8, 2020-01-01))". We should remove them by + // "AND(>=($9, 2011-01-01), <($9, 2020-01-01))". We should remove them by // folding intervals. checkDateRange(f, f.and(f.gt(f.exYear, f.literal(2010)), f.lt(f.exYear, f.literal(2020)), f.eq(f.exMonth, f.literal(2)), f.eq(f.exDay, f.literal(29))), - is("AND(>=($8, 2011-01-01)," - + " AND(>=($8, 2011-01-01), <($8, 2020-01-01))," - + " OR(AND(>=($8, 2011-02-01), <($8, 2011-03-01))," - + " AND(>=($8, 2012-02-01), <($8, 2012-03-01))," - + " AND(>=($8, 2013-02-01), <($8, 2013-03-01))," - + " AND(>=($8, 2014-02-01), <($8, 2014-03-01))," - + " AND(>=($8, 2015-02-01), <($8, 2015-03-01))," - + " AND(>=($8, 2016-02-01), <($8, 2016-03-01))," - + " AND(>=($8, 2017-02-01), <($8, 2017-03-01))," - + " AND(>=($8, 2018-02-01), <($8, 2018-03-01))," - + " AND(>=($8, 2019-02-01), <($8, 2019-03-01)))," - + " OR(AND(>=($8, 2012-02-29), <($8, 2012-03-01))," - + " AND(>=($8, 2016-02-29), <($8, 2016-03-01))))")); + is("AND(>=($9, 2011-01-01)," + + " AND(>=($9, 2011-01-01), <($9, 2020-01-01))," + + " OR(AND(>=($9, 2011-02-01), <($9, 2011-03-01))," + + " AND(>=($9, 2012-02-01), <($9, 2012-03-01))," + + " AND(>=($9, 2013-02-01), <($9, 2013-03-01))," + + " AND(>=($9, 2014-02-01), <($9, 2014-03-01))," + + " AND(>=($9, 2015-02-01), <($9, 2015-03-01))," + + " AND(>=($9, 2016-02-01), <($9, 2016-03-01))," + + " AND(>=($9, 2017-02-01), <($9, 2017-03-01))," + + " AND(>=($9, 2018-02-01), <($9, 2018-03-01))," + + " AND(>=($9, 2019-02-01), <($9, 2019-03-01)))," + + " OR(AND(>=($9, 2012-02-29), <($9, 2012-03-01))," + + " AND(>=($9, 2016-02-29), <($9, 2016-03-01))))")); } @Test public void testExtractYearMonthDayFromTimestampColumn() { final Fixture2 f = new Fixture2(); checkDateRange(f, - f.and(f.gt(f.exYearTs, f.literal(2010)), - f.lt(f.exYearTs, f.literal(2020)), - f.eq(f.exMonthTs, f.literal(2)), f.eq(f.exDayTs, f.literal(29))), + f.and(f.gt(f.exYear, f.literal(2010)), + f.lt(f.exYear, f.literal(2020)), + f.eq(f.exMonth, f.literal(2)), f.eq(f.exDay, f.literal(29))), is("AND(>=($9, 2011-01-01)," + " AND(>=($9, 2011-01-01), <($9, 2020-01-01))," + " OR(AND(>=($9, 2011-02-01), <($9, 2011-03-01))," @@ -212,26 +212,14 @@ public class DateRangeRulesTest { private final RexNode exYear; private final RexNode exMonth; private final RexNode exDay; - private final RexNode exYearTs; - private final RexNode exMonthTs; - private final RexNode exDayTs; Fixture2() { - exYear = rexBuilder.makeCall(intRelDataType, - SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), dt)); - exMonth = rexBuilder.makeCall(intRelDataType, - SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), dt)); - exDay = rexBuilder.makeCall(intRelDataType, - SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), dt)); - exYearTs = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT, + exYear = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT, ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), ts)); - exMonthTs = rexBuilder.makeCall(intRelDataType, + exMonth = rexBuilder.makeCall(intRelDataType, SqlStdOperatorTable.EXTRACT, ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), ts)); - exDayTs = rexBuilder.makeCall(intRelDataType, + exDay = rexBuilder.makeCall(intRelDataType, SqlStdOperatorTable.EXTRACT, ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), ts)); } http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/test/java/org/apache/calcite/test/JdbcTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java index 2282037..7d722cb 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java @@ -1516,6 +1516,30 @@ public class JdbcTest { }); } + @Test public void testExtractMonthFromTimestamp() { + CalciteAssert.that() + .with(CalciteAssert.Config.JDBC_FOODMART) + .query("select extract(month from \"birth_date\") as c \n" + + "from \"foodmart\".\"employee\" where \"employee_id\"=1") + .returns("C=8\n"); + } + + @Test public void testExtractYearFromTimestamp() { + CalciteAssert.that() + .with(CalciteAssert.Config.JDBC_FOODMART) + .query("select extract(year from \"birth_date\") as c \n" + + "from \"foodmart\".\"employee\" where \"employee_id\"=1") + .returns("C=1961\n"); + } + + @Test public void testExtractFromInterval() { + CalciteAssert.that() + .with(CalciteAssert.Config.JDBC_FOODMART) + .query("select extract(month from interval '2-3' year to month) as c \n" + + "from \"foodmart\".\"employee\" where \"employee_id\"=1") + .returns("C=3\n"); + } + @Test public void testFloorDate() { CalciteAssert.that() .with(CalciteAssert.Config.JDBC_FOODMART) http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java index 95c47fc..570c7a0 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -8575,7 +8575,6 @@ public class SqlValidatorTest extends SqlValidatorTestCase { + "UNION ALL left\n" + "\n" + "$throw -\n" - + "EXTRACT_DATE -\n" + "FILTER left\n" + "Reinterpret -\n" + "TABLE pre\n" http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml ---------------------------------------------------------------------- diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml index f575271..ecf1e46 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -18,11 +18,9 @@ limitations under the License. <Root> <TestCase name="testReduceNot"> <Resource name="sql"> - <![CDATA[select sal -from emp -where case when (sal = 1000) then -(case when sal = 1000 then null else 1 end is null) else -(case when sal = 2000 then null else 1 end is null) end is true]]> + <![CDATA[select * +from (select (case when sal > 1000 then null else false end) as caseCol from emp) +where NOT(caseCol)]]> </Resource> <Resource name="planAfter"> <![CDATA[ @@ -656,7 +654,7 @@ LogicalAggregate(group=[{0}], EXPR$1=[$SUM0($2)], EXPR$2=[SUM($1)]) </TestCase> <TestCase name="testDistinctNonDistinctTwoAggregatesWithGrouping"> <Resource name="sql"> - <![CDATA[SELECT deptno, sum(comm), min(comm), SUM(DISTINCT sal) + <![CDATA[SELECT deptno, SUM(comm), MIN(comm), SUM(DISTINCT sal) FROM emp GROUP BY deptno]]> </Resource> @@ -678,7 +676,7 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($2)], EXPR$2=[MIN($3)], EXPR$3=[SUM($1 </TestCase> <TestCase name="testDistinctWithGrouping"> <Resource name="sql"> - <![CDATA[SELECT sal, sum(comm), min(comm), SUM(DISTINCT sal) + <![CDATA[SELECT sal, SUM(comm), MIN(comm), SUM(DISTINCT sal) FROM emp GROUP BY sal]]> </Resource> @@ -2331,14 +2329,14 @@ where extract(year from birthdate) = 2014and extract(month from birthdate) = 4]] <Resource name="planBefore"> <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9]) - LogicalFilter(condition=[AND(=(EXTRACT_DATE(FLAG(YEAR), Reinterpret($9)), 2014), =(EXTRACT_DATE(FLAG(MONTH), Reinterpret($9)), 4))]) + LogicalFilter(condition=[AND(=(EXTRACT(FLAG(YEAR), $9), 2014), =(EXTRACT(FLAG(MONTH), $9), 4))]) LogicalTableScan(table=[[CATALOG, SALES, EMP_B]]) ]]> </Resource> <Resource name="planAfter"> <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9]) - LogicalFilter(condition=[AND(>=(Reinterpret($9), 2014-01-01), <(Reinterpret($9), 2015-01-01), >=(Reinterpret($9), 2014-04-01), <(Reinterpret($9), 2014-05-01))]) + LogicalFilter(condition=[AND(>=($9, 2014-04-01), <($9, 2014-05-01))]) LogicalTableScan(table=[[CATALOG, SALES, EMP_B]]) ]]> </Resource> @@ -2352,14 +2350,14 @@ where extract(year from birthdate) = 2014]]> <Resource name="planBefore"> <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9]) - LogicalFilter(condition=[=(EXTRACT_DATE(FLAG(YEAR), Reinterpret($9)), 2014)]) + LogicalFilter(condition=[=(EXTRACT(FLAG(YEAR), $9), 2014)]) LogicalTableScan(table=[[CATALOG, SALES, EMP_B]]) ]]> </Resource> <Resource name="planAfter"> <![CDATA[ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9]) - LogicalFilter(condition=[AND(>=(Reinterpret($9), 2014-01-01), <(Reinterpret($9), 2015-01-01))]) + LogicalFilter(condition=[AND(>=($9, 2014-01-01), <($9, 2015-01-01))]) LogicalTableScan(table=[[CATALOG, SALES, EMP_B]]) ]]> </Resource> http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java ---------------------------------------------------------------------- diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java index 1a0d3d3..c167e06 100644 --- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java +++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java @@ -1378,10 +1378,9 @@ public class DruidAdapterIT { + "where extract(year from \"timestamp\") = 1997\n" + "and extract(month from \"timestamp\") in (4, 6)\n"; final String explain = "DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[AND(=" - + "(EXTRACT_DATE(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 1997), OR(=(EXTRACT_DATE" - + "(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 4), =(EXTRACT_DATE(FLAG(MONTH), " - + "/INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 6)))], groups=[{}], aggs=[[COUNT()]])"; + + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], " + + "filter=[AND(=(EXTRACT(FLAG(YEAR), $0), 1997), OR(=(EXTRACT(FLAG(MONTH), $0), 4), " + + "=(EXTRACT(FLAG(MONTH), $0), 6)))], groups=[{}], aggs=[[COUNT()]])"; sql(sql) .explainContains(explain) .returnsUnordered("C=13500"); @@ -1586,10 +1585,9 @@ public class DruidAdapterIT { + "'timeZone':'UTC','locale':'en-US'}}")) .explainContains("PLAN=EnumerableInterpreter\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], filter=[=($1, 1016)" - + "], projects=[[EXTRACT_DATE(FLAG(DAY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), " - + "EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), EXTRACT_DATE(FLAG" - + "(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n") + + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], " + + "filter=[=($1, 1016)], projects=[[EXTRACT(FLAG(DAY), $0), EXTRACT(FLAG(MONTH), $0), " + + "EXTRACT(FLAG(YEAR), $0), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n") .returnsUnordered("day=2; month=1; year=1997; product_id=1016", "day=10; month=1; year=1997; product_id=1016", "day=13; month=1; year=1997; product_id=1016", @@ -1620,10 +1618,9 @@ public class DruidAdapterIT { + "'timeZone':'UTC','locale':'en-US'}}")) .explainContains("PLAN=EnumerableInterpreter\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], filter=[=($1, 1016)" - + "], projects=[[EXTRACT_DATE(FLAG(DAY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), " - + "EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), EXTRACT_DATE(FLAG" - + "(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n") + + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], " + + "filter=[=($1, 1016)], projects=[[EXTRACT(FLAG(DAY), $0), EXTRACT(FLAG(MONTH), $0), " + + "EXTRACT(FLAG(YEAR), $0), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n") .returnsUnordered("EXPR$0=2; EXPR$1=1; EXPR$2=1997; product_id=1016", "EXPR$0=10; EXPR$1=1; EXPR$2=1997; product_id=1016", "EXPR$0=13; EXPR$1=1; EXPR$2=1997; product_id=1016", @@ -1647,8 +1644,8 @@ public class DruidAdapterIT { + "'timeZone':'UTC','locale':'en-US'}}")) .explainContains("PLAN=EnumerableInterpreter\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], filter=[=($1, 1016)], " - + "projects=[[EXTRACT_DATE(FLAG(DAY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1]], " + + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], " + + "filter=[=($1, 1016)], projects=[[EXTRACT(FLAG(DAY), $0), $1]], " + "groups=[{0, 1}], aggs=[[]])\n") .returnsUnordered("EXPR$0=2; dayOfMonth=1016", "EXPR$0=10; dayOfMonth=1016", "EXPR$0=13; dayOfMonth=1016", "EXPR$0=16; dayOfMonth=1016"); @@ -1675,10 +1672,10 @@ public class DruidAdapterIT { sql(sql) .explainContains("PLAN=EnumerableInterpreter\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[AND(>=(CAST" - + "($11):BIGINT, 8), <=(CAST($11):BIGINT, 10), <(CAST($10):BIGINT, 15), =(EXTRACT_DATE" - + "(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 1997))], groups=[{}], " - + "aggs=[[SUM($90)]])") + + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], " + + "filter=[AND(>=(CAST($11):BIGINT, 8), <=(CAST($11):BIGINT, 10), " + + "<(CAST($10):BIGINT, 15), =(EXTRACT(FLAG(YEAR), $0), 1997))], groups=[{}], " + + "aggs=[[SUM($90)]])\n") .queryContains(druidChecker(druidQuery)) .returnsUnordered("EXPR$0=75364.09998679161"); } @@ -1824,10 +1821,10 @@ public class DruidAdapterIT { + "'intervals':['1900-01-09T00:00:00.000/2992-01-10T00:00:00.000']}")) .explainContains("PLAN=EnumerableInterpreter\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[>=(CAST($1)" - + ":BIGINT, 1558)], projects=[[EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), " - + "86400000)), $1, $89]], groups=[{0, 1}], aggs=[[SUM($2)]], sort0=[0], sort1=[2], " - + "sort2=[1], dir0=[ASC], dir1=[ASC], dir2=[ASC])"); + + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], " + + "filter=[>=(CAST($1):BIGINT, 1558)], projects=[[EXTRACT(FLAG(MONTH), $0), $1, $89]], " + + "groups=[{0, 1}], aggs=[[SUM($2)]], sort0=[0], sort1=[2], sort2=[1], " + + "dir0=[ASC], dir1=[ASC], dir2=[ASC])"); } @@ -1870,10 +1867,10 @@ public class DruidAdapterIT { + " by y DESC, m ASC, s DESC, \"product_id\" LIMIT 3"; final String expectedPlan = "PLAN=EnumerableInterpreter\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[>=(CAST($1)" - + ":BIGINT, 1558)], projects=[[EXTRACT_DATE(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000))," - + " EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1, $89]], groups=[{0, 1," - + " 2}], aggs=[[SUM($3)]], sort0=[0], sort1=[1], sort2=[3], sort3=[2], dir0=[DESC], " + + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], " + + "filter=[>=(CAST($1):BIGINT, 1558)], projects=[[EXTRACT(FLAG(YEAR), $0), " + + "EXTRACT(FLAG(MONTH), $0), $1, $89]], groups=[{0, 1, 2}], aggs=[[SUM($3)]], sort0=[0], " + + "sort1=[1], sort2=[3], sort3=[2], dir0=[DESC], " + "dir1=[ASC], dir2=[DESC], dir3=[ASC], fetch=[3])"; final String expectedDruidQuery = "{'queryType':'groupBy','dataSource':'foodmart'," + "'granularity':'all','dimensions':[{'type':'extraction'," @@ -1906,11 +1903,10 @@ public class DruidAdapterIT { + " by s DESC, m DESC, \"product_id\" LIMIT 3"; final String expectedPlan = "PLAN=EnumerableInterpreter\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[>=(CAST($1)" - + ":BIGINT, 1558)], projects=[[EXTRACT_DATE(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000))," - + " EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1, $89]], groups=[{0, 1," - + " 2}], aggs=[[SUM($3)]], sort0=[3], sort1=[1], sort2=[2], dir0=[DESC], dir1=[DESC], " - + "dir2=[ASC], fetch=[3])"; + + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], " + + "filter=[>=(CAST($1):BIGINT, 1558)], projects=[[EXTRACT(FLAG(YEAR), $0), " + + "EXTRACT(FLAG(MONTH), $0), $1, $89]], groups=[{0, 1, 2}], aggs=[[SUM($3)]], " + + "sort0=[3], sort1=[1], sort2=[2], dir0=[DESC], dir1=[DESC], dir2=[ASC], fetch=[3])"; final String expectedDruidQuery = "{'queryType':'groupBy','dataSource':'foodmart'," + "'granularity':'all','dimensions':[{'type':'extraction'," + "'dimension':'__time','outputName':'extract_year'," @@ -2040,10 +2036,10 @@ public class DruidAdapterIT { + "\"product_id\" = 1558 group by extract(CENTURY from \"timestamp\")"; final String plan = "PLAN=EnumerableInterpreter\n" + " BindableAggregate(group=[{0}])\n" - + " BindableProject(EXPR$0=[EXTRACT_DATE(FLAG(CENTURY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000))])\n" + + " BindableProject(EXPR$0=[EXTRACT(FLAG(CENTURY), $0)])\n" + " DruidQuery(table=[[foodmart, foodmart]], " - + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[=($1, 1558)], " - + "projects=[[$0]])"; + + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], " + + "filter=[=($1, 1558)], projects=[[$0]])\n"; sql(sql).explainContains(plan).queryContains(druidChecker("'queryType':'select'")) .returnsUnordered("EXPR$0=20"); } http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java ---------------------------------------------------------------------- diff --git a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java index 0e1948d..f993a53 100644 --- a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java +++ b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java @@ -112,9 +112,9 @@ public class DruidDateRangeRulesTest { // OR(AND(>=($9, 2012-02-29), <($9, 2012-03-01))," // AND(>=($9, 2016-02-29), <($9, 2016-03-01)))) checkDateRange(f, - f.and(f.gt(f.exYearTs, f.literal(2010)), - f.lt(f.exYearTs, f.literal(2020)), - f.eq(f.exMonthTs, f.literal(2)), f.eq(f.exDayTs, f.literal(29))), + f.and(f.gt(f.exYear, f.literal(2010)), + f.lt(f.exYear, f.literal(2020)), + f.eq(f.exMonth, f.literal(2)), f.eq(f.exDay, f.literal(29))), is("[2012-02-29T00:00:00.000/2012-03-01T00:00:00.000, " + "2016-02-29T00:00:00.000/2016-03-01T00:00:00.000]")); } @@ -190,26 +190,14 @@ public class DruidDateRangeRulesTest { private final RexNode exYear; private final RexNode exMonth; private final RexNode exDay; - private final RexNode exYearTs; - private final RexNode exMonthTs; - private final RexNode exDayTs; Fixture2() { - exYear = rexBuilder.makeCall(intRelDataType, - SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), dt)); - exMonth = rexBuilder.makeCall(intRelDataType, - SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), dt)); - exDay = rexBuilder.makeCall(intRelDataType, - SqlStdOperatorTable.EXTRACT_DATE, - ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), dt)); - exYearTs = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT, + exYear = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT, ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), ts)); - exMonthTs = rexBuilder.makeCall(intRelDataType, + exMonth = rexBuilder.makeCall(intRelDataType, SqlStdOperatorTable.EXTRACT, ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), ts)); - exDayTs = rexBuilder.makeCall(intRelDataType, + exDay = rexBuilder.makeCall(intRelDataType, SqlStdOperatorTable.EXTRACT, ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), ts)); }
