In TimeUnit add WEEK, QUARTER, MICROSECOND values, and change type of multiplier
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/cf5d07bd Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/cf5d07bd Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/cf5d07bd Branch: refs/heads/master Commit: cf5d07bde81a7c6a82bdab34ec798d0bf01ac01c Parents: eead3d2 Author: Julian Hyde <[email protected]> Authored: Mon Mar 7 15:46:31 2016 -0800 Committer: Julian Hyde <[email protected]> Committed: Mon Mar 7 21:25:01 2016 -0800 ---------------------------------------------------------------------- .../apache/calcite/avatica/util/TimeUnit.java | 38 +++++++++++++------- .../calcite/avatica/util/TimeUnitRange.java | 8 ++++- .../java/org/apache/calcite/rex/RexBuilder.java | 11 +++--- .../sql2rel/StandardConvertletTable.java | 33 ++++++++--------- 4 files changed, 52 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java index b249232..574aa45 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnit.java @@ -20,28 +20,42 @@ import java.math.BigDecimal; /** * Enumeration of time units used to construct an interval. + * + * <p>Only {@link #YEAR}, {@link #YEAR}, {@link #MONTH}, {@link #DAY}, + * {@link #HOUR}, {@link #MINUTE}, {@link #SECOND} can be the unit of a SQL + * interval. + * + * <p>The others ({@link #QUARTER}, {@link #WEEK}, {@link #MILLISECOND} and + * {@link #MICROSECOND}) are convenient to use it internally, when converting to + * and from UNIX timestamps. And also may be arguments to the + * {@code TIMESTAMPADD} and {@code TIMESTAMPDIFF} functions. */ public enum TimeUnit { - YEAR(true, ' ', 12 /* months */, null), - MONTH(true, '-', 1 /* months */, BigDecimal.valueOf(12)), - DAY(false, '-', DateTimeUtils.MILLIS_PER_DAY, null), - HOUR(false, ' ', DateTimeUtils.MILLIS_PER_HOUR, BigDecimal.valueOf(24)), - MINUTE(false, ':', DateTimeUtils.MILLIS_PER_MINUTE, BigDecimal.valueOf(60)), - SECOND(false, ':', DateTimeUtils.MILLIS_PER_SECOND, BigDecimal.valueOf(60)), + YEAR(true, ' ', BigDecimal.valueOf(12) /* months */, null), + MONTH(true, '-', BigDecimal.ONE /* months */, BigDecimal.valueOf(12)), + DAY(false, '-', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_DAY), null), + HOUR(false, ' ', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_HOUR), + BigDecimal.valueOf(24)), + MINUTE(false, ':', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_MINUTE), + BigDecimal.valueOf(60)), + SECOND(false, ':', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_SECOND), + BigDecimal.valueOf(60)), - /** Unlike the other units, MILLISECOND may not be the unit of a SQL interval. - * Still, it is convenient to use it internally, when converting to and from - * UNIX timestamps. */ - MILLISECOND(false, '.', 1, BigDecimal.valueOf(1)); + QUARTER(true, '*', BigDecimal.valueOf(3) /* months */, BigDecimal.valueOf(4)), + WEEK(false, '*', BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_DAY * 7), + BigDecimal.valueOf(53)), + MILLISECOND(false, '.', BigDecimal.ONE, BigDecimal.valueOf(1000)), + MICROSECOND(false, '.', BigDecimal.ONE.scaleByPowerOfTen(-3), + BigDecimal.valueOf(1000000)); public final boolean yearMonth; public final char separator; - public final long multiplier; + public final BigDecimal multiplier; private final BigDecimal limit; private static final TimeUnit[] CACHED_VALUES = values(); - TimeUnit(boolean yearMonth, char separator, long multiplier, + TimeUnit(boolean yearMonth, char separator, BigDecimal multiplier, BigDecimal limit) { this.yearMonth = yearMonth; this.separator = separator; http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java index 4d9b322..ddfe9f7 100644 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/util/TimeUnitRange.java @@ -36,7 +36,13 @@ public enum TimeUnitRange { HOUR_TO_SECOND(TimeUnit.HOUR, TimeUnit.SECOND), MINUTE(TimeUnit.MINUTE, null), MINUTE_TO_SECOND(TimeUnit.MINUTE, TimeUnit.SECOND), - SECOND(TimeUnit.SECOND, null); + SECOND(TimeUnit.SECOND, null), + + // non-standard time units cannot participate in ranges + QUARTER(TimeUnit.QUARTER, null), + WEEK(TimeUnit.WEEK, null), + MILLISECOND(TimeUnit.MILLISECOND, null), + MICROSECOND(TimeUnit.MICROSECOND, null); public final TimeUnit startUnit; public final TimeUnit endUnit; http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/core/src/main/java/org/apache/calcite/rex/RexBuilder.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java index dd147a5..b0cc27e 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java +++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java @@ -525,7 +525,7 @@ public class RexBuilder { case INTERVAL_DAY_TIME: assert value instanceof BigDecimal; BigDecimal value2 = (BigDecimal) value; - final long multiplier = + final BigDecimal multiplier = literal.getType().getIntervalQualifier().getStartUnit() .multiplier; typeName = type.getSqlTypeName(); @@ -534,8 +534,7 @@ public class RexBuilder { case INTEGER: typeName = SqlTypeName.BIGINT; } - value = value2.divide(BigDecimal.valueOf(multiplier), 0, - BigDecimal.ROUND_HALF_DOWN); + value = value2.divide(multiplier, 0, BigDecimal.ROUND_HALF_DOWN); } final RexLiteral literal2 = makeLiteral(value, type, typeName); @@ -595,8 +594,7 @@ public class RexBuilder { .getFractionalSecondPrecision(typeFactory.getTypeSystem()), 3); } - BigDecimal multiplier = BigDecimal.valueOf(endUnit.multiplier) - .divide(BigDecimal.TEN.pow(scale)); + BigDecimal multiplier = endUnit.multiplier.scaleByPowerOfTen(-scale); RexNode value = decodeIntervalOrDecimal(exp); if (multiplier.longValue() != 1) { value = makeCall( @@ -627,8 +625,7 @@ public class RexBuilder { .getFractionalSecondPrecision(typeFactory.getTypeSystem()), 3); } - BigDecimal multiplier = BigDecimal.valueOf(endUnit.multiplier) - .divide(BigDecimal.TEN.pow(scale)); + BigDecimal multiplier = endUnit.multiplier.scaleByPowerOfTen(-scale); RelDataType decimalType = getTypeFactory().createSqlType(SqlTypeName.DECIMAL, scale + intervalType.getPrecision(), http://git-wip-us.apache.org/repos/asf/calcite/blob/cf5d07bd/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 99452bf..5d1957f 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java @@ -16,7 +16,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; @@ -465,8 +464,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { RexLiteral castedInterval = cx.getRexBuilder().makeIntervalLiteral( sourceValue.multiply( - BigDecimal.valueOf( - intervalQualifier.getStartUnit().multiplier), + intervalQualifier.getStartUnit().multiplier, MathContext.UNLIMITED), intervalQualifier); return castToValidatedType(cx, call, castedInterval); @@ -515,7 +513,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { final SqlIntervalLiteral literal = call.operand(0); SqlIntervalLiteral.IntervalValue interval = (SqlIntervalLiteral.IntervalValue) literal.getValue(); - long val = + BigDecimal val = interval.getIntervalQualifier().getStartUnit().multiplier; RexNode rexInterval = cx.convertExpression(literal); @@ -530,7 +528,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { zero); RexNode pad = - rexBuilder.makeExactLiteral(BigDecimal.valueOf(val - 1)); + rexBuilder.makeExactLiteral(val.subtract(BigDecimal.ONE)); RexNode cast = rexBuilder.makeReinterpretCast( rexInterval.getType(), pad, rexBuilder.makeLiteral(false)); SqlOperator op = @@ -545,8 +543,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { : rexBuilder.makeCall(SqlStdOperatorTable.CASE, cond, sum, rexInterval); - RexNode factor = - rexBuilder.makeExactLiteral(BigDecimal.valueOf(val)); + RexNode factor = rexBuilder.makeExactLiteral(val); RexNode div = rexBuilder.makeCall( SqlStdOperatorTable.DIVIDE_INTEGER, @@ -596,7 +593,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { case INTERVAL_DAY_TIME: break; case TIMESTAMP: - res = divide(rexBuilder, res, DateTimeUtils.MILLIS_PER_DAY); + res = divide(rexBuilder, res, TimeUnit.DAY.multiplier); // fall through case DATE: return rexBuilder.makeCall(resType, SqlStdOperatorTable.EXTRACT_DATE, @@ -636,16 +633,16 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), x)); res = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, res, rexBuilder.makeExactLiteral(BigDecimal.ONE)); - res = divide(rexBuilder, res, 3); + res = divide(rexBuilder, res, TimeUnit.QUARTER.multiplier); res = rexBuilder.makeCall(SqlStdOperatorTable.PLUS, res, rexBuilder.makeExactLiteral(BigDecimal.ONE)); return res; } - private static long getFactor(TimeUnit unit) { + private static BigDecimal getFactor(TimeUnit unit) { switch (unit) { case DAY: - return 1; + return BigDecimal.ONE; case HOUR: return TimeUnit.DAY.multiplier; case MINUTE: @@ -653,7 +650,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { case SECOND: return TimeUnit.MINUTE.multiplier; case YEAR: - return 1; + return BigDecimal.ONE; case MONTH: return TimeUnit.YEAR.multiplier; default: @@ -662,20 +659,20 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { } private RexNode mod(RexBuilder rexBuilder, RelDataType resType, RexNode res, - long val) { - if (val == 1L) { + BigDecimal val) { + if (val.equals(BigDecimal.ONE)) { return res; } return rexBuilder.makeCall(SqlStdOperatorTable.MOD, res, - rexBuilder.makeExactLiteral(BigDecimal.valueOf(val), resType)); + rexBuilder.makeExactLiteral(val, resType)); } - private RexNode divide(RexBuilder rexBuilder, RexNode res, long val) { - if (val == 1L) { + private RexNode divide(RexBuilder rexBuilder, RexNode res, BigDecimal val) { + if (val.equals(BigDecimal.ONE)) { return res; } return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE_INTEGER, res, - rexBuilder.makeExactLiteral(BigDecimal.valueOf(val))); + rexBuilder.makeExactLiteral(val)); } public RexNode convertDatetimeMinus(
