Repository: calcite Updated Branches: refs/heads/master 5511253b5 -> ac9c8c7af
[CALCITE-1302] Create SqlTypeName values for each interval range, e.g. YEAR_MONTH As a result, we don't need to use SqlIntervalQualifier as often. Also, the JDBC client gets more information from the type. Change the CalciteAssert.checkResultCount API. Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/ac9c8c7a Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/ac9c8c7a Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/ac9c8c7a Branch: refs/heads/master Commit: ac9c8c7af020a0532e3e7e31b4216f69d9f0b39f Parents: 5511253 Author: Julian Hyde <[email protected]> Authored: Mon Jun 27 23:57:41 2016 -0700 Committer: Julian Hyde <[email protected]> Committed: Fri Jul 1 11:11:10 2016 -0700 ---------------------------------------------------------------------- .../calcite/adapter/enumerable/RexImpTable.java | 36 +++- .../adapter/enumerable/RexToLixTranslator.java | 42 ++++- .../calcite/jdbc/JavaTypeFactoryImpl.java | 13 +- .../calcite/prepare/CalcitePrepareImpl.java | 21 ++- .../apache/calcite/rel/metadata/RelMdSize.java | 30 +++- .../calcite/rel/type/RelDataTypeSystemImpl.java | 52 +++++- .../java/org/apache/calcite/rex/RexBuilder.java | 67 ++++++-- .../java/org/apache/calcite/rex/RexLiteral.java | 39 ++++- .../calcite/sql/SqlIntervalQualifier.java | 46 +++++- .../java/org/apache/calcite/sql/SqlLiteral.java | 44 +++-- .../calcite/sql/type/IntervalSqlType.java | 27 +-- .../sql/type/MatchReturnTypeInference.java | 8 +- .../sql/type/SqlTypeAssignmentRules.java | 111 +++++-------- .../sql/type/SqlTypeExplicitPrecedenceList.java | 39 ++++- .../calcite/sql/type/SqlTypeFactoryImpl.java | 4 +- .../apache/calcite/sql/type/SqlTypeFamily.java | 8 +- .../apache/calcite/sql/type/SqlTypeName.java | 164 ++++++++++++++++++- .../apache/calcite/sql/type/SqlTypeUtil.java | 3 +- .../calcite/sql/validate/SqlValidatorImpl.java | 13 +- .../sql2rel/SqlNodeToRexConverterImpl.java | 13 +- .../sql2rel/StandardConvertletTable.java | 73 ++++++++- .../main/java/org/apache/calcite/util/Util.java | 3 +- .../calcite/jdbc/CalciteRemoteDriverTest.java | 2 +- .../calcite/sql/test/SqlOperatorBaseTest.java | 24 +++ .../org/apache/calcite/test/CalciteAssert.java | 12 +- .../apache/calcite/test/SqlValidatorTest.java | 31 +--- 26 files changed, 710 insertions(+), 215 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 2ac0dc9..22f2249 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 @@ -45,7 +45,6 @@ import org.apache.calcite.schema.ImplementableFunction; import org.apache.calcite.schema.impl.AggregateFunctionImpl; import org.apache.calcite.sql.SqlAggFunction; import org.apache.calcite.sql.SqlBinaryOperator; -import org.apache.calcite.sql.SqlIntervalQualifier; import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.fun.SqlTrimFunction; @@ -1962,7 +1961,16 @@ public class RexImpTable { switch (operand0.getType().getSqlTypeName()) { case DATE: switch (typeName1) { - case INTERVAL_DAY_TIME: + 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: trop1 = Expressions.convert_( Expressions.divide(trop1, @@ -1974,16 +1982,26 @@ public class RexImpTable { trop1 = Expressions.convert_(trop1, int.class); break; } - final SqlIntervalQualifier interval = call.getType().getIntervalQualifier(); switch (typeName1) { + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: switch (call.getKind()) { case MINUS: trop1 = Expressions.negate(trop1); } return Expressions.call(BuiltInMethod.ADD_MONTHS.method, trop0, trop1); - case INTERVAL_DAY_TIME: + 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: switch (call.getKind()) { case MINUS: return Expressions.subtract(trop0, trop1); @@ -1994,17 +2012,19 @@ public class RexImpTable { default: switch (call.getKind()) { case MINUS: - Class targetType = interval.isYearMonth() ? int.class : long.class; - if (interval.isYearMonth()) { + switch (call.getType().getSqlTypeName()) { + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: return Expressions.call(BuiltInMethod.SUBTRACT_MONTHS.method, trop0, trop1); } TimeUnit fromUnit = typeName1 == SqlTypeName.DATE ? TimeUnit.DAY : TimeUnit.MILLISECOND; - TimeUnit toUnit = interval.isYearMonth() ? TimeUnit.MONTH : TimeUnit.MILLISECOND; + TimeUnit toUnit = TimeUnit.MILLISECOND; return multiplyDivide( Expressions.convert_(Expressions.subtract(trop0, trop1), - targetType), + (Class) long.class), fromUnit.multiplier, toUnit.multiplier); default: return Expressions.add(trop0, trop1); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java index 2a93c0a..333e183 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java @@ -323,7 +323,9 @@ public class RexToLixTranslator { BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method, operand)); break; + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: convert = RexImpTable.optimize2( operand, Expressions.call( @@ -331,7 +333,16 @@ public class RexToLixTranslator { operand, Expressions.constant(interval.timeUnitRange))); break; - case INTERVAL_DAY_TIME: + 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: convert = RexImpTable.optimize2( operand, Expressions.call( @@ -413,12 +424,22 @@ public class RexToLixTranslator { (long) Math.pow(10, 3 - targetScale))); } break; - case INTERVAL_DAY_TIME: + 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: switch (sourceType.getSqlTypeName().getFamily()) { case NUMERIC: - final SqlIntervalQualifier interval = targetType.getIntervalQualifier(); - final BigDecimal multiplier = interval.getUnit().multiplier; + final BigDecimal multiplier = targetType.getSqlTypeName().getEndUnit().multiplier; final BigDecimal divider = BigDecimal.ONE; convert = RexImpTable.multiplyDivide(convert, multiplier, divider); } @@ -614,11 +635,22 @@ public class RexToLixTranslator { value2 = ((Calendar) value).getTimeInMillis(); javaClass = long.class; break; - case INTERVAL_DAY_TIME: + 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: value2 = ((BigDecimal) value).longValue(); javaClass = long.class; break; + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: value2 = ((BigDecimal) value).intValue(); javaClass = int.class; break; http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java index 45e935f..a1f6e3f 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java @@ -176,11 +176,22 @@ public class JavaTypeFactoryImpl case DATE: case TIME: case INTEGER: + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: return type.isNullable() ? Integer.class : int.class; case TIMESTAMP: case BIGINT: - case INTERVAL_DAY_TIME: + 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: return type.isNullable() ? Long.class : long.class; case SMALLINT: return type.isNullable() ? Short.class : short.class; http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java index 60a76bb..bfc1ce2 100644 --- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java @@ -912,18 +912,27 @@ public class CalcitePrepareImpl implements CalcitePrepare { private static String getTypeName(RelDataType type) { final SqlTypeName sqlTypeName = type.getSqlTypeName(); switch (sqlTypeName) { - case INTERVAL_YEAR_MONTH: - case INTERVAL_DAY_TIME: - // e.g. "INTERVAL_MONTH" or "INTERVAL_YEAR_MONTH" - return "INTERVAL_" - + type.getIntervalQualifier().toString().replace(' ', '_'); case ARRAY: case MULTISET: case MAP: case ROW: return type.toString(); // e.g. "INTEGER ARRAY" + case INTERVAL_YEAR_MONTH: + return "INTERVAL_YEAR_TO_MONTH"; + case INTERVAL_DAY_HOUR: + return "INTERVAL_DAY_TO_HOUR"; + case INTERVAL_DAY_MINUTE: + return "INTERVAL_DAY_TO_MINUTE"; + case INTERVAL_DAY_SECOND: + return "INTERVAL_DAY_TO_SECOND"; + case INTERVAL_HOUR_MINUTE: + return "INTERVAL_HOUR_TO_MINUTE"; + case INTERVAL_HOUR_SECOND: + return "INTERVAL_HOUR_TO_SECOND"; + case INTERVAL_MINUTE_SECOND: + return "INTERVAL_MINUTE_TO_SECOND"; default: - return sqlTypeName.getName(); // e.g. "DECIMAL" + return sqlTypeName.getName(); // e.g. "DECIMAL", "INTERVAL_YEAR_MONTH" } } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java index 0fd808e..744d241 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java @@ -280,13 +280,24 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> { case DECIMAL: case DATE: case TIME: + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: return 4d; case BIGINT: case DOUBLE: case FLOAT: // sic case TIMESTAMP: - case INTERVAL_DAY_TIME: - case INTERVAL_YEAR_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: return 8d; case BINARY: return (double) type.getPrecision(); @@ -327,12 +338,23 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> { case REAL: case DATE: case TIME: + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: return 4d; case BIGINT: case DOUBLE: case TIMESTAMP: - case INTERVAL_DAY_TIME: - case INTERVAL_YEAR_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: return 8d; case BINARY: case VARBINARY: http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java index c34c2e6..677173f 100644 --- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java @@ -37,8 +37,19 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem { switch (typeName) { case DECIMAL: return getMaxNumericScale(); - case INTERVAL_DAY_TIME: + 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: return SqlTypeName.MAX_INTERVAL_FRACTIONAL_SECOND_PRECISION; default: return -1; @@ -55,8 +66,19 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem { return 1; case DECIMAL: return getMaxNumericPrecision(); - case INTERVAL_DAY_TIME: + 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: return SqlTypeName.DEFAULT_INTERVAL_START_PRECISION; case BOOLEAN: return 1; @@ -99,8 +121,19 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem { case TIME: case TIMESTAMP: return SqlTypeName.MAX_DATETIME_PRECISION; - case INTERVAL_DAY_TIME: + 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: return SqlTypeName.MAX_INTERVAL_START_PRECISION; default: return getDefaultPrecision(typeName); @@ -125,9 +158,20 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem { return isPrefix ? "x'" : "'"; case TIMESTAMP: return isPrefix ? "TIMESTAMP '" : "'"; - case INTERVAL_DAY_TIME: + 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: return isPrefix ? "INTERVAL '" : "' DAY"; + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: return isPrefix ? "INTERVAL '" : "' YEAR TO MONTH"; case TIME: return isPrefix ? "TIME '" : "'"; http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 825fdb9..a062ba5 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java +++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java @@ -38,7 +38,6 @@ import org.apache.calcite.sql.SqlUtil; import org.apache.calcite.sql.fun.SqlCountAggFunction; import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.type.ArraySqlType; -import org.apache.calcite.sql.type.IntervalSqlType; import org.apache.calcite.sql.type.MapSqlType; import org.apache.calcite.sql.type.MultisetSqlType; import org.apache.calcite.sql.type.SqlTypeFamily; @@ -73,7 +72,8 @@ public class RexBuilder { */ public static final SqlSpecialOperator GET_OPERATOR = new SqlSpecialOperator("_get", SqlKind.OTHER_FUNCTION); - public static final Function<RelDataTypeField, RexInputRef> TO_INPUT_REF = + + private static final Function<RelDataTypeField, RexInputRef> TO_INPUT_REF = new Function<RelDataTypeField, RexInputRef>() { public RexInputRef apply(RelDataTypeField input) { return new RexInputRef(input.getIndex(), input.getType()); @@ -509,7 +509,16 @@ public class RexBuilder { calendar.getTimeInMillis(), DateTimeUtils.powerX(10, 3 - scale))); break; - case INTERVAL_DAY_TIME: + 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: assert value instanceof BigDecimal; typeName = type.getSqlTypeName(); switch (typeName) { @@ -522,9 +531,9 @@ public class RexBuilder { case DECIMAL: BigDecimal value2 = (BigDecimal) value; final BigDecimal multiplier = - baseUnit(literal.getType().getIntervalQualifier().getUnit()).multiplier; + baseUnit(literal.getTypeName()).multiplier; final BigDecimal divider = - literal.getType().getIntervalQualifier().getUnit().multiplier; + literal.getTypeName().getEndUnit().multiplier; value = value2.multiply(multiplier) .divide(divider, 0, BigDecimal.ROUND_HALF_DOWN); } @@ -560,8 +569,8 @@ public class RexBuilder { /** Returns the lowest granularity unit for the given unit. * YEAR and MONTH intervals are stored as months; * HOUR, MINUTE, SECOND intervals are stored as milliseconds. */ - protected static TimeUnit baseUnit(TimeUnit unit) { - if (unit.yearMonth) { + protected static TimeUnit baseUnit(SqlTypeName unit) { + if (unit.isYearMonth()) { return TimeUnit.MONTH; } else { return TimeUnit.MILLISECOND; @@ -624,9 +633,8 @@ public class RexBuilder { } private RexNode makeCastIntervalToExact(RelDataType toType, RexNode exp) { - final IntervalSqlType intervalType = (IntervalSqlType) exp.getType(); - final TimeUnit endUnit = intervalType.getIntervalQualifier().getUnit(); - final TimeUnit baseUnit = baseUnit(endUnit); + final TimeUnit endUnit = exp.getType().getSqlTypeName().getEndUnit(); + final TimeUnit baseUnit = baseUnit(exp.getType().getSqlTypeName()); final BigDecimal multiplier = baseUnit.multiplier; final int scale = 0; BigDecimal divider = endUnit.multiplier.scaleByPowerOfTen(-scale); @@ -636,14 +644,14 @@ public class RexBuilder { RelDataType decimalType = getTypeFactory().createSqlType( SqlTypeName.DECIMAL, - scale + intervalType.getPrecision(), + scale + exp.getType().getPrecision(), scale); value = encodeIntervalOrDecimal(value, decimalType, false); } return ensureType(toType, value, false); } - private RexNode multiplyDivide(RexNode e, BigDecimal multiplier, + public RexNode multiplyDivide(RexNode e, BigDecimal multiplier, BigDecimal divider) { assert multiplier.signum() > 0; assert divider.signum() > 0; @@ -1063,7 +1071,8 @@ public class RexBuilder { } /** - * Creates an interval literal. + * Creates a literal representing an interval type, for example + * {@code YEAR TO MONTH} or {@code DOW}. */ public RexLiteral makeIntervalLiteral( SqlIntervalQualifier intervalQualifier) { @@ -1072,7 +1081,8 @@ public class RexBuilder { } /** - * Creates an interval literal. + * Creates a literal representing an interval value, for example + * {@code INTERVAL '3-7' YEAR TO MONTH}. */ public RexLiteral makeIntervalLiteral( BigDecimal v, @@ -1080,8 +1090,7 @@ public class RexBuilder { return makeLiteral( v, typeFactory.createSqlIntervalType(intervalQualifier), - intervalQualifier.isYearMonth() ? SqlTypeName.INTERVAL_YEAR_MONTH - : SqlTypeName.INTERVAL_DAY_TIME); + intervalQualifier.typeName()); } /** @@ -1257,8 +1266,19 @@ public class RexBuilder { return makeDateLiteral((Calendar) value); case TIMESTAMP: return makeTimestampLiteral((Calendar) value, type.getPrecision()); + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: - case INTERVAL_DAY_TIME: + 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: return makeIntervalLiteral((BigDecimal) value, type.getIntervalQualifier()); case MAP: @@ -1330,8 +1350,19 @@ public class RexBuilder { case INTEGER: case BIGINT: case DECIMAL: + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: - case INTERVAL_DAY_TIME: + 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: if (o instanceof BigDecimal) { return o; } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java index 8af8a06..c9ffc1b 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java +++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java @@ -215,8 +215,19 @@ public class RexLiteral extends RexNode { case TIME: case TIMESTAMP: return value instanceof Calendar; - case INTERVAL_DAY_TIME: + 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: // The value of a DAY-TIME interval (whatever the start and end units, // even say HOUR TO MINUTE) is in milliseconds (perhaps fractional // milliseconds). The value of a YEAR-MONTH interval is in months. @@ -386,8 +397,19 @@ public class RexLiteral extends RexNode { case TIMESTAMP: printDatetime(pw, new ZonelessTimestamp(), value); break; - case INTERVAL_DAY_TIME: + 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: if (value instanceof BigDecimal) { pw.print(value.toString()); } else { @@ -469,13 +491,24 @@ public class RexLiteral extends RexNode { return new RexLiteral(new ByteString(bytes), type, typeName); case NULL: return new RexLiteral(null, type, typeName); - case INTERVAL_DAY_TIME: + 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: long millis = SqlParserUtil.intervalToMillis( literal, type.getIntervalQualifier()); return new RexLiteral(BigDecimal.valueOf(millis), type, typeName); + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: long months = SqlParserUtil.intervalToMonths( literal, http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java index 5255047..9be154c 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java @@ -107,6 +107,9 @@ public class SqlIntervalQualifier extends SqlNode { int fractionalSecondPrecision, SqlParserPos pos) { super(pos); + if (endUnit == startUnit) { + endUnit = null; + } this.timeUnitRange = TimeUnitRange.of(Preconditions.checkNotNull(startUnit), endUnit); this.startPrecision = startPrecision; @@ -128,9 +131,46 @@ public class SqlIntervalQualifier extends SqlNode { //~ Methods ---------------------------------------------------------------- public SqlTypeName typeName() { - return isYearMonth() - ? SqlTypeName.INTERVAL_YEAR_MONTH - : SqlTypeName.INTERVAL_DAY_TIME; + switch (timeUnitRange) { + case YEAR: + case CENTURY: + case DECADE: + case MILLENNIUM: + return SqlTypeName.INTERVAL_YEAR; + case YEAR_TO_MONTH: + return SqlTypeName.INTERVAL_YEAR_MONTH; + case MONTH: + case QUARTER: + return SqlTypeName.INTERVAL_MONTH; + case DOW: + case DOY: + case DAY: + case WEEK: + return SqlTypeName.INTERVAL_DAY; + case DAY_TO_HOUR: + return SqlTypeName.INTERVAL_DAY_HOUR; + case DAY_TO_MINUTE: + return SqlTypeName.INTERVAL_DAY_MINUTE; + case DAY_TO_SECOND: + return SqlTypeName.INTERVAL_DAY_SECOND; + case HOUR: + return SqlTypeName.INTERVAL_HOUR; + case HOUR_TO_MINUTE: + return SqlTypeName.INTERVAL_HOUR_MINUTE; + case HOUR_TO_SECOND: + return SqlTypeName.INTERVAL_HOUR_SECOND; + case MINUTE: + return SqlTypeName.INTERVAL_MINUTE; + case MINUTE_TO_SECOND: + return SqlTypeName.INTERVAL_MINUTE_SECOND; + case SECOND: + case MILLISECOND: + case EPOCH: + case MICROSECOND: + return SqlTypeName.INTERVAL_SECOND; + default: + throw new AssertionError(timeUnitRange); + } } public void validate( http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java index 347ea1a..95b1bc3 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java @@ -129,7 +129,8 @@ import static org.apache.calcite.util.Static.RESOURCE; * <td>An {@link Enum}</td> * </tr> * <tr> - * <td>{@link SqlTypeName#INTERVAL_DAY_TIME}</td> + * <td>{@link SqlTypeName#INTERVAL_YEAR} + * .. {@link SqlTypeName#INTERVAL_SECOND}</td> * <td>Interval, for example <code>INTERVAL '1:34' HOUR</code>.</td> * <td>{@link SqlIntervalLiteral.IntervalValue}.</td> * </tr> @@ -197,8 +198,19 @@ public class SqlLiteral extends SqlNode { case TIME: case TIMESTAMP: return value instanceof Calendar; - case INTERVAL_DAY_TIME: + 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: return value instanceof SqlIntervalLiteral.IntervalValue; case BINARY: return value instanceof BitString; @@ -281,10 +293,10 @@ public class SqlLiteral extends SqlNode { * <li>If the node is a {@link SqlIntervalQualifier}, * returns its {@link TimeUnitRange}. * - * <li>If the node is INTERVAL_DAY_TIME in {@link SqlTypeFamily}, + * <li>If the node is INTERVAL_DAY_TIME_ in {@link SqlTypeFamily}, * returns its sign multiplied by its millisecond equivalent value * - * <li>If the node is INTERVAL_YEAR_MONTH in {@link SqlTypeFamily}, + * <li>If the node is INTERVAL_YEAR_MONTH_ in {@link SqlTypeFamily}, * returns its sign multiplied by its months equivalent value * * <li>Otherwise the behavior is not specified. @@ -632,8 +644,19 @@ public class SqlLiteral extends SqlNode { collation); return type; + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: - case INTERVAL_DAY_TIME: + 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: SqlIntervalLiteral.IntervalValue intervalValue = (SqlIntervalLiteral.IntervalValue) value; return typeFactory.createSqlIntervalType( @@ -684,15 +707,8 @@ public class SqlLiteral extends SqlNode { String intervalStr, SqlIntervalQualifier intervalQualifier, SqlParserPos pos) { - SqlTypeName typeName = - intervalQualifier.isYearMonth() ? SqlTypeName.INTERVAL_YEAR_MONTH - : SqlTypeName.INTERVAL_DAY_TIME; - return new SqlIntervalLiteral( - sign, - intervalStr, - intervalQualifier, - typeName, - pos); + return new SqlIntervalLiteral(sign, intervalStr, intervalQualifier, + intervalQualifier.typeName(), pos); } public static SqlNumericLiteral createNegative( http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java b/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java index 6111c7b..d4b2284 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java +++ b/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java @@ -46,11 +46,7 @@ public class IntervalSqlType extends AbstractSqlType { public IntervalSqlType(RelDataTypeSystem typeSystem, SqlIntervalQualifier intervalQualifier, boolean isNullable) { - super(intervalQualifier.isYearMonth() - ? SqlTypeName.INTERVAL_YEAR_MONTH - : SqlTypeName.INTERVAL_DAY_TIME, - isNullable, - null); + super(intervalQualifier.typeName(), isNullable, null); this.typeSystem = Preconditions.checkNotNull(typeSystem); this.intervalQualifier = Preconditions.checkNotNull(intervalQualifier); computeDigest(); @@ -85,24 +81,17 @@ public class IntervalSqlType extends AbstractSqlType { public IntervalSqlType combine( RelDataTypeFactoryImpl typeFactory, IntervalSqlType that) { - assert this.intervalQualifier.isYearMonth() - == that.intervalQualifier.isYearMonth(); + assert this.typeName.isYearMonth() == that.typeName.isYearMonth(); boolean nullable = isNullable || that.isNullable; - TimeUnit thisStart = - this.intervalQualifier.getStartUnit(); - TimeUnit thisEnd = - this.intervalQualifier.getEndUnit(); - TimeUnit thatStart = - that.intervalQualifier.getStartUnit(); - TimeUnit thatEnd = - that.intervalQualifier.getEndUnit(); - - assert null != thisStart; - assert null != thatStart; + TimeUnit thisStart = Preconditions.checkNotNull(typeName.getStartUnit()); + TimeUnit thisEnd = typeName.getEndUnit(); + final TimeUnit thatStart = + Preconditions.checkNotNull(that.typeName.getStartUnit()); + final TimeUnit thatEnd = that.typeName.getEndUnit(); int secondPrec = this.intervalQualifier.getStartPrecisionPreservingDefault(); - int fracPrec = + final int fracPrec = SqlIntervalQualifier.combineFractionalSecondPrecisionPreservingDefault( typeSystem, this.intervalQualifier, http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java b/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java index 5c60187..2eadcd8 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java +++ b/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java @@ -19,6 +19,7 @@ package org.apache.calcite.sql.type; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.SqlOperatorBinding; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.List; @@ -49,12 +50,11 @@ public class MatchReturnTypeInference implements SqlReturnTypeInference { * Returns the first type matching any type in typeNames at or after * position start (zero based). */ - public MatchReturnTypeInference(int start, List<SqlTypeName> typeNames) { - assert start >= 0; - assert null != typeNames; - assert typeNames.size() > 0; + public MatchReturnTypeInference(int start, Iterable<SqlTypeName> typeNames) { + Preconditions.checkArgument(start >= 0); this.start = start; this.typeNames = ImmutableList.copyOf(typeNames); + Preconditions.checkArgument(!this.typeNames.isEmpty()); } //~ Methods ---------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java index 8ed26b8..efe2bb7 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java @@ -18,6 +18,7 @@ package org.apache.calcite.sql.type; import org.apache.calcite.util.Util; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -40,45 +41,39 @@ public class SqlTypeAssignmentRules { //~ Constructors ----------------------------------------------------------- private SqlTypeAssignmentRules() { - rules = new HashMap<SqlTypeName, Set<SqlTypeName>>(); + rules = new HashMap<>(); Set<SqlTypeName> rule; // IntervalYearMonth is assignable from... - rule = new HashSet<SqlTypeName>(); - rule.add(SqlTypeName.INTERVAL_YEAR_MONTH); - rules.put(SqlTypeName.INTERVAL_YEAR_MONTH, rule); - - // IntervalDayTime is assignable from... - rule = new HashSet<SqlTypeName>(); - rule.add(SqlTypeName.INTERVAL_DAY_TIME); - rules.put(SqlTypeName.INTERVAL_DAY_TIME, rule); + for (SqlTypeName interval : SqlTypeName.YEAR_INTERVAL_TYPES) { + rules.put(interval, SqlTypeName.YEAR_INTERVAL_TYPES); + } + for (SqlTypeName interval : SqlTypeName.DAY_INTERVAL_TYPES) { + rules.put(interval, SqlTypeName.DAY_INTERVAL_TYPES); + } // Multiset is assignable from... - rule = new HashSet<SqlTypeName>(); - rule.add(SqlTypeName.MULTISET); - rules.put(SqlTypeName.MULTISET, rule); + rules.put(SqlTypeName.MULTISET, EnumSet.of(SqlTypeName.MULTISET)); // Tinyint is assignable from... - rule = new HashSet<SqlTypeName>(); - rule.add(SqlTypeName.TINYINT); - rules.put(SqlTypeName.TINYINT, rule); + rules.put(SqlTypeName.TINYINT, EnumSet.of(SqlTypeName.TINYINT)); // Smallint is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rules.put(SqlTypeName.SMALLINT, rule); // Int is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); rules.put(SqlTypeName.INTEGER, rule); // BigInt is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); @@ -86,7 +81,7 @@ public class SqlTypeAssignmentRules { rules.put(SqlTypeName.BIGINT, rule); // Float is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); @@ -96,7 +91,7 @@ public class SqlTypeAssignmentRules { rules.put(SqlTypeName.FLOAT, rule); // Real is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); @@ -107,7 +102,7 @@ public class SqlTypeAssignmentRules { rules.put(SqlTypeName.REAL, rule); // Double is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); @@ -119,7 +114,7 @@ public class SqlTypeAssignmentRules { rules.put(SqlTypeName.DOUBLE, rule); // Decimal is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); @@ -130,52 +125,46 @@ public class SqlTypeAssignmentRules { rules.put(SqlTypeName.DECIMAL, rule); // VarBinary is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.VARBINARY); rule.add(SqlTypeName.BINARY); rules.put(SqlTypeName.VARBINARY, rule); // Char is assignable from... - rule = new HashSet<SqlTypeName>(); - rule.add(SqlTypeName.CHAR); - rules.put(SqlTypeName.CHAR, rule); + rules.put(SqlTypeName.CHAR, EnumSet.of(SqlTypeName.CHAR)); // VarChar is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.CHAR); rule.add(SqlTypeName.VARCHAR); rules.put(SqlTypeName.VARCHAR, rule); // Boolean is assignable from... - rule = new HashSet<SqlTypeName>(); - rule.add(SqlTypeName.BOOLEAN); - rules.put(SqlTypeName.BOOLEAN, rule); + rules.put(SqlTypeName.BOOLEAN, EnumSet.of(SqlTypeName.BOOLEAN)); // Binary is assignable from... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.BINARY); rule.add(SqlTypeName.VARBINARY); rules.put(SqlTypeName.BINARY, rule); // Date is assignable from ... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.DATE); rule.add(SqlTypeName.TIMESTAMP); rules.put(SqlTypeName.DATE, rule); // Time is assignable from ... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TIME); rule.add(SqlTypeName.TIMESTAMP); rules.put(SqlTypeName.TIME, rule); // Timestamp is assignable from ... - rule = new HashSet<SqlTypeName>(); - rule.add(SqlTypeName.TIMESTAMP); - rules.put(SqlTypeName.TIMESTAMP, rule); + rules.put(SqlTypeName.TIMESTAMP, EnumSet.of(SqlTypeName.TIMESTAMP)); // Any is assignable from ... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); @@ -193,7 +182,7 @@ public class SqlTypeAssignmentRules { // Make numbers symmetrical and // make varchar/char castable to/from numbers - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TINYINT); rule.add(SqlTypeName.SMALLINT); rule.add(SqlTypeName.INTEGER); @@ -240,27 +229,19 @@ public class SqlTypeAssignmentRules { // Exact Numerics are castable from intervals for (SqlTypeName exactType : SqlTypeName.EXACT_TYPES) { rule = coerceRules.get(exactType); - rule.add(SqlTypeName.INTERVAL_DAY_TIME); - rule.add(SqlTypeName.INTERVAL_YEAR_MONTH); + rule.addAll(SqlTypeName.INTERVAL_TYPES); } // intervals are castable from Exact Numeric - rule = coerceRules.get(SqlTypeName.INTERVAL_DAY_TIME); - rule.add(SqlTypeName.TINYINT); - rule.add(SqlTypeName.SMALLINT); - rule.add(SqlTypeName.INTEGER); - rule.add(SqlTypeName.BIGINT); - rule.add(SqlTypeName.DECIMAL); - rule.add(SqlTypeName.VARCHAR); - - // intervals castable from Exact Numeric - rule = coerceRules.get(SqlTypeName.INTERVAL_YEAR_MONTH); - rule.add(SqlTypeName.TINYINT); - rule.add(SqlTypeName.SMALLINT); - rule.add(SqlTypeName.INTEGER); - rule.add(SqlTypeName.BIGINT); - rule.add(SqlTypeName.DECIMAL); - rule.add(SqlTypeName.VARCHAR); + for (SqlTypeName typeName : SqlTypeName.INTERVAL_TYPES) { + rule = coerceRules.get(typeName); + rule.add(SqlTypeName.TINYINT); + rule.add(SqlTypeName.SMALLINT); + rule.add(SqlTypeName.INTEGER); + rule.add(SqlTypeName.BIGINT); + rule.add(SqlTypeName.DECIMAL); + rule.add(SqlTypeName.VARCHAR); + } // varchar is castable from Boolean, Date, time, timestamp, numbers and // intervals @@ -269,8 +250,7 @@ public class SqlTypeAssignmentRules { rule.add(SqlTypeName.DATE); rule.add(SqlTypeName.TIME); rule.add(SqlTypeName.TIMESTAMP); - rule.add(SqlTypeName.INTERVAL_DAY_TIME); - rule.add(SqlTypeName.INTERVAL_YEAR_MONTH); + rule.addAll(SqlTypeName.INTERVAL_TYPES); // char is castable from Boolean, Date, time and timestamp and numbers rule = coerceRules.get(SqlTypeName.CHAR); @@ -278,8 +258,7 @@ public class SqlTypeAssignmentRules { rule.add(SqlTypeName.DATE); rule.add(SqlTypeName.TIME); rule.add(SqlTypeName.TIMESTAMP); - rule.add(SqlTypeName.INTERVAL_DAY_TIME); - rule.add(SqlTypeName.INTERVAL_YEAR_MONTH); + rule.addAll(SqlTypeName.INTERVAL_TYPES); // Boolean is castable from char and varchar rule = coerceRules.get(SqlTypeName.BOOLEAN); @@ -289,7 +268,7 @@ public class SqlTypeAssignmentRules { // Date, time, and timestamp are castable from // char and varchar // Date is castable from ... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.DATE); rule.add(SqlTypeName.TIMESTAMP); rule.add(SqlTypeName.CHAR); @@ -297,7 +276,7 @@ public class SqlTypeAssignmentRules { coerceRules.put(SqlTypeName.DATE, rule); // Time is castable from ... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TIME); rule.add(SqlTypeName.TIMESTAMP); rule.add(SqlTypeName.CHAR); @@ -305,7 +284,7 @@ public class SqlTypeAssignmentRules { coerceRules.put(SqlTypeName.TIME, rule); // Timestamp is castable from ... - rule = new HashSet<SqlTypeName>(); + rule = new HashSet<>(); rule.add(SqlTypeName.TIMESTAMP); rule.add(SqlTypeName.DATE); rule.add(SqlTypeName.TIME); @@ -333,9 +312,9 @@ public class SqlTypeAssignmentRules { Map<SqlTypeName, Set<SqlTypeName>> ruleset = coerce ? coerceRules : rules; - if (to.equals(SqlTypeName.NULL)) { + if (to == SqlTypeName.NULL) { return false; - } else if (from.equals(SqlTypeName.NULL)) { + } else if (from == SqlTypeName.NULL) { return true; } @@ -352,7 +331,7 @@ public class SqlTypeAssignmentRules { @SuppressWarnings("unchecked") private static <K, V> Map<K, V> copy(Map<K, V> map) { - Map<K, V> copy = new HashMap<K, V>(); + Map<K, V> copy = new HashMap<>(); for (Map.Entry<K, V> e : map.entrySet()) { if (e.getValue() instanceof Set) { copy.put(e.getKey(), (V) copy((Set) e.getValue())); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java index 4fe315b..1fc7c9b 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java @@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -86,10 +87,32 @@ public class SqlTypeExplicitPrecedenceList .put(SqlTypeName.DATE, list(SqlTypeName.DATE)) .put(SqlTypeName.TIME, list(SqlTypeName.TIME)) .put(SqlTypeName.TIMESTAMP, list(SqlTypeName.TIMESTAMP)) + .put(SqlTypeName.INTERVAL_YEAR, + list(SqlTypeName.YEAR_INTERVAL_TYPES)) .put(SqlTypeName.INTERVAL_YEAR_MONTH, - list(SqlTypeName.INTERVAL_YEAR_MONTH)) - .put(SqlTypeName.INTERVAL_DAY_TIME, - list(SqlTypeName.INTERVAL_DAY_TIME)) + list(SqlTypeName.YEAR_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_MONTH, + list(SqlTypeName.YEAR_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_DAY, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_DAY_HOUR, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_DAY_MINUTE, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_DAY_SECOND, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_HOUR, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_HOUR_MINUTE, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_HOUR_SECOND, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_MINUTE, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_MINUTE_SECOND, + list(SqlTypeName.DAY_INTERVAL_TYPES)) + .put(SqlTypeName.INTERVAL_SECOND, + list(SqlTypeName.DAY_INTERVAL_TYPES)) .build(); //~ Instance fields -------------------------------------------------------- @@ -98,14 +121,18 @@ public class SqlTypeExplicitPrecedenceList //~ Constructors ----------------------------------------------------------- - public SqlTypeExplicitPrecedenceList(List<SqlTypeName> typeNames) { + public SqlTypeExplicitPrecedenceList(Iterable<SqlTypeName> typeNames) { this.typeNames = ImmutableNullableList.copyOf(typeNames); } //~ Methods ---------------------------------------------------------------- - private static SqlTypeExplicitPrecedenceList list(SqlTypeName... array) { - return new SqlTypeExplicitPrecedenceList(ImmutableList.copyOf(array)); + private static SqlTypeExplicitPrecedenceList list(SqlTypeName... typeNames) { + return list(Arrays.asList(typeNames)); + } + + private static SqlTypeExplicitPrecedenceList list(Iterable<SqlTypeName> typeNames) { + return new SqlTypeExplicitPrecedenceList(typeNames); } private static SqlTypeExplicitPrecedenceList numeric(SqlTypeName typeName) { http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java index 57378cc..92c3313 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java @@ -208,9 +208,7 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl { assert typeName != null; assert typeName != SqlTypeName.MULTISET : "use createMultisetType() instead"; - assert typeName != SqlTypeName.INTERVAL_DAY_TIME - : "use createSqlIntervalType() instead"; - assert typeName != SqlTypeName.INTERVAL_YEAR_MONTH + assert !SqlTypeName.INTERVAL_TYPES.contains(typeName) : "use createSqlIntervalType() instead"; } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java index ce3fd6e..4543b00 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java @@ -23,7 +23,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.sql.Types; -import java.util.List; +import java.util.Collection; import java.util.Map; /** @@ -118,7 +118,7 @@ public enum SqlTypeFamily implements RelDataTypeFamily { /** * @return collection of {@link SqlTypeName}s included in this family */ - public List<SqlTypeName> getTypeNames() { + public Collection<SqlTypeName> getTypeNames() { switch (this) { case CHARACTER: return SqlTypeName.CHAR_TYPES; @@ -135,9 +135,9 @@ public enum SqlTypeFamily implements RelDataTypeFamily { case BOOLEAN: return SqlTypeName.BOOLEAN_TYPES; case INTERVAL_YEAR_MONTH: - return ImmutableList.of(SqlTypeName.INTERVAL_YEAR_MONTH); + return SqlTypeName.YEAR_INTERVAL_TYPES; case INTERVAL_DAY_TIME: - return ImmutableList.of(SqlTypeName.INTERVAL_DAY_TIME); + return SqlTypeName.DAY_INTERVAL_TYPES; case STRING: return SqlTypeName.STRING_TYPES; case APPROXIMATE_NUMERIC: http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java index b43850c..f55f9b9 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java @@ -17,12 +17,15 @@ package org.apache.calcite.sql.type; import org.apache.calcite.avatica.util.DateTimeUtils; +import org.apache.calcite.avatica.util.TimeUnit; import org.apache.calcite.sql.SqlLiteral; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.Util; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; import java.math.BigDecimal; import java.sql.Types; @@ -30,6 +33,7 @@ import java.util.Arrays; import java.util.Calendar; import java.util.List; import java.util.Map; +import java.util.Set; /** * Enumeration of the type names which can be used to construct a SQL type. @@ -59,9 +63,31 @@ public enum SqlTypeName { SqlTypeFamily.TIME), TIMESTAMP(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.TIMESTAMP, SqlTypeFamily.TIMESTAMP), + INTERVAL_YEAR(PrecScale.NO_NO, false, Types.OTHER, + SqlTypeFamily.INTERVAL_YEAR_MONTH), INTERVAL_YEAR_MONTH(PrecScale.NO_NO, false, Types.OTHER, SqlTypeFamily.INTERVAL_YEAR_MONTH), - INTERVAL_DAY_TIME(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + INTERVAL_MONTH(PrecScale.NO_NO, false, Types.OTHER, + SqlTypeFamily.INTERVAL_YEAR_MONTH), + INTERVAL_DAY(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_DAY_HOUR(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_DAY_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_DAY_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_HOUR(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_HOUR_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_HOUR_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_MINUTE_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, + false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), + INTERVAL_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES, false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME), CHAR(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.CHAR, SqlTypeFamily.CHARACTER), @@ -114,7 +140,11 @@ public enum SqlTypeName { ImmutableList.of( BOOLEAN, INTEGER, VARCHAR, DATE, TIME, TIMESTAMP, NULL, DECIMAL, ANY, CHAR, BINARY, VARBINARY, TINYINT, SMALLINT, BIGINT, REAL, - DOUBLE, SYMBOL, INTERVAL_YEAR_MONTH, INTERVAL_DAY_TIME, + DOUBLE, SYMBOL, INTERVAL_YEAR, INTERVAL_YEAR_MONTH, INTERVAL_MONTH, + INTERVAL_DAY, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, + INTERVAL_DAY_SECOND, INTERVAL_HOUR, INTERVAL_HOUR_MINUTE, + INTERVAL_HOUR_SECOND, INTERVAL_MINUTE, INTERVAL_MINUTE_SECOND, + INTERVAL_SECOND, FLOAT, MULTISET, DISTINCT, STRUCTURED, ROW, CURSOR, COLUMN_LIST); public static final List<SqlTypeName> BOOLEAN_TYPES = @@ -147,8 +177,26 @@ public enum SqlTypeName { public static final List<SqlTypeName> DATETIME_TYPES = ImmutableList.of(DATE, TIME, TIMESTAMP); - public static final List<SqlTypeName> INTERVAL_TYPES = - ImmutableList.of(INTERVAL_DAY_TIME, INTERVAL_YEAR_MONTH); + public static final Set<SqlTypeName> YEAR_INTERVAL_TYPES = + Sets.immutableEnumSet(SqlTypeName.INTERVAL_YEAR, + SqlTypeName.INTERVAL_YEAR_MONTH, + SqlTypeName.INTERVAL_MONTH); + + public static final Set<SqlTypeName> DAY_INTERVAL_TYPES = + Sets.immutableEnumSet(SqlTypeName.INTERVAL_DAY, + SqlTypeName.INTERVAL_DAY_HOUR, + SqlTypeName.INTERVAL_DAY_MINUTE, + SqlTypeName.INTERVAL_DAY_SECOND, + SqlTypeName.INTERVAL_HOUR, + SqlTypeName.INTERVAL_HOUR_MINUTE, + SqlTypeName.INTERVAL_HOUR_SECOND, + SqlTypeName.INTERVAL_MINUTE, + SqlTypeName.INTERVAL_MINUTE_SECOND, + SqlTypeName.INTERVAL_SECOND); + + public static final Set<SqlTypeName> INTERVAL_TYPES = + Sets.immutableEnumSet( + Iterables.concat(YEAR_INTERVAL_TYPES, DAY_INTERVAL_TYPES)); private static final Map<Integer, SqlTypeName> JDBC_TYPE_TO_NAME = ImmutableMap.<Integer, SqlTypeName>builder() @@ -206,7 +254,7 @@ public enum SqlTypeName { private final int jdbcOrdinal; private final SqlTypeFamily family; - private SqlTypeName(int signatures, boolean special, int jdbcType, + SqlTypeName(int signatures, boolean special, int jdbcType, SqlTypeFamily family) { this.signatures = signatures; this.special = special; @@ -307,8 +355,19 @@ public enum SqlTypeName { switch (this) { case DECIMAL: return 0; - case INTERVAL_DAY_TIME: + 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: return DEFAULT_INTERVAL_FRACTIONAL_SECOND_PRECISION; default: return -1; @@ -680,8 +739,19 @@ public enum SqlTypeName { case TIME: case TIMESTAMP: return 1; - case INTERVAL_DAY_TIME: + 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: return MIN_INTERVAL_START_PRECISION; default: return -1; @@ -698,14 +768,92 @@ public enum SqlTypeName { public int getMinScale() { switch (this) { // TODO: Minimum numeric scale for decimal - case INTERVAL_DAY_TIME: + 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: return MIN_INTERVAL_FRACTIONAL_SECOND_PRECISION; default: return -1; } } + /** Returns {@code HOUR} for {@code HOUR TO SECOND} and + * {@code HOUR}, {@code SECOND} for {@code SECOND}. */ + public TimeUnit getStartUnit() { + switch (this) { + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + return TimeUnit.YEAR; + case INTERVAL_MONTH: + return TimeUnit.MONTH; + case INTERVAL_DAY: + case INTERVAL_DAY_HOUR: + case INTERVAL_DAY_MINUTE: + case INTERVAL_DAY_SECOND: + return TimeUnit.DAY; + case INTERVAL_HOUR: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_HOUR_SECOND: + return TimeUnit.HOUR; + case INTERVAL_MINUTE: + case INTERVAL_MINUTE_SECOND: + return TimeUnit.MINUTE; + case INTERVAL_SECOND: + return TimeUnit.SECOND; + default: + throw new AssertionError(this); + } + } + + /** Returns {@code SECOND} for both {@code HOUR TO SECOND} and + * {@code SECOND}. */ + public TimeUnit getEndUnit() { + switch (this) { + case INTERVAL_YEAR: + return TimeUnit.YEAR; + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: + return TimeUnit.MONTH; + case INTERVAL_DAY: + return TimeUnit.DAY; + case INTERVAL_DAY_HOUR: + case INTERVAL_HOUR: + return TimeUnit.HOUR; + case INTERVAL_DAY_MINUTE: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_MINUTE: + return TimeUnit.MINUTE; + case INTERVAL_DAY_SECOND: + case INTERVAL_HOUR_SECOND: + case INTERVAL_MINUTE_SECOND: + case INTERVAL_SECOND: + return TimeUnit.SECOND; + default: + throw new AssertionError(this); + } + } + + public boolean isYearMonth() { + switch (this) { + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: + return true; + default: + return false; + } + } + /** Limit. */ public enum Limit { ZERO, UNDERFLOW, OVERFLOW http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java index 203392a..ee7b41a 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java @@ -42,6 +42,7 @@ import com.google.common.collect.Lists; import java.nio.charset.Charset; import java.util.AbstractList; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import static org.apache.calcite.util.Static.RESOURCE; @@ -267,7 +268,7 @@ public abstract class SqlTypeUtil { * @see #isOfSameTypeName(SqlTypeName, RelDataType) */ public static boolean isOfSameTypeName( - List<SqlTypeName> typeNames, + Collection<SqlTypeName> typeNames, RelDataType type) { for (SqlTypeName typeName : typeNames) { if (isOfSameTypeName(typeName, type)) { http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java index 3aacce7..ae4f8e5 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java @@ -2665,8 +2665,19 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { } break; + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: - case INTERVAL_DAY_TIME: + 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: if (literal instanceof SqlIntervalLiteral) { SqlIntervalLiteral.IntervalValue interval = (SqlIntervalLiteral.IntervalValue) http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java index bf7fdd0..a22963f 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java @@ -138,8 +138,19 @@ public class SqlNodeToRexConverterImpl implements SqlNodeToRexConverter { case DATE: return rexBuilder.makeDateLiteral((Calendar) value); + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: - case INTERVAL_DAY_TIME: + 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: SqlIntervalQualifier sqlIntervalQualifier = ((SqlIntervalLiteral.IntervalValue) value).getIntervalQualifier(); l = (long) SqlLiteral.value(literal); http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 c9db0f3..21aaf30 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java @@ -16,6 +16,7 @@ */ 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; @@ -620,8 +621,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { case MONTH: case DAY: switch (sqlTypeName) { + case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: - case INTERVAL_DAY_TIME: + 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: res = divide(rexBuilder, res, TimeUnit.DAY.multiplier); @@ -671,8 +683,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { case TIMESTAMP: // convert to seconds return divide(rexBuilder, res, TimeUnit.SECOND.multiplier); - case INTERVAL_DAY_TIME: + 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); } @@ -681,8 +704,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { case DOY: case WEEK: switch (sqlTypeName) { - case INTERVAL_DAY_TIME: // fall through + 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: // TODO: is this check better to do in validation phase? // Currently there is parameter on TimeUnit to identify these type of units. throw new IllegalArgumentException("Extract " + unit + " from " @@ -1032,8 +1066,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { if (operands.size() == 2) { final SqlTypeName sqlTypeName = operands.get(0).getType().getSqlTypeName(); switch (sqlTypeName) { - case INTERVAL_DAY_TIME: + 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: operands = ImmutableList.of(operands.get(1), operands.get(0)); } } @@ -1469,17 +1514,33 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { // => (t2 - t1) UNIT final RexBuilder rexBuilder = cx.getRexBuilder(); final SqlLiteral unitLiteral = call.operand(0); - final TimeUnit unit = unitLiteral.symbolValue(TimeUnit.class); + TimeUnit unit = unitLiteral.symbolValue(TimeUnit.class); + BigDecimal multiplier = BigDecimal.ONE; + BigDecimal divider = BigDecimal.ONE; + switch (unit) { + case MICROSECOND: + case MILLISECOND: + case WEEK: + multiplier = BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_SECOND); + divider = unit.multiplier; + unit = TimeUnit.SECOND; + break; + case QUARTER: + divider = unit.multiplier; + unit = TimeUnit.MONTH; + break; + } final RelDataType intType = cx.getTypeFactory().createSqlType(SqlTypeName.INTEGER); final SqlIntervalQualifier qualifier = new SqlIntervalQualifier(unit, null, SqlParserPos.ZERO); final RelDataType intervalType = cx.getTypeFactory().createSqlIntervalType(qualifier); - return rexBuilder.makeCast(intType, + RexNode e = rexBuilder.makeCast(intType, rexBuilder.makeCall(intervalType, SqlStdOperatorTable.MINUS_DATE, ImmutableList.of(cx.convertExpression(call.operand(2)), cx.convertExpression(call.operand(1))))); + return rexBuilder.multiplyDivide(e, multiplier, divider); } } } http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/util/Util.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java index f972db8..0eee37b 100644 --- a/core/src/main/java/org/apache/calcite/util/Util.java +++ b/core/src/main/java/org/apache/calcite/util/Util.java @@ -1877,8 +1877,7 @@ public class Util { Class<T> clazz) { final T[] ts = clazz.getEnumConstants(); if (ts == null) { - // not an enum type - return null; + throw new AssertionError("not an enum type"); } ImmutableMap.Builder<String, T> builder = ImmutableMap.builder(); for (T t : ts) { http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java index 18ab7bd..4578822 100644 --- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java +++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java @@ -272,7 +272,7 @@ public class CalciteRemoteDriverTest { @Test public void testRemoteTypeInfo() throws Exception { CalciteAssert.hr().with(REMOTE_CONNECTION_FACTORY) .metaData(GET_TYPEINFO) - .returns(CalciteAssert.checkResultCount(31)); + .returns(CalciteAssert.checkResultCount(is(42))); } @Test public void testRemoteTableTypes() throws Exception { http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 e81ed4c..fe51c64 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 @@ -5068,10 +5068,34 @@ public abstract class SqlOperatorBaseTest { + "timestamp '2016-02-24 12:42:25', " + "timestamp '2016-02-24 12:42:20')", "-5000000", "INTEGER NOT NULL"); + tester.checkScalar("timestampdiff(SQL_TSI_FRAC_SECOND, " + + "timestamp '2016-02-24 12:42:25', " + + "timestamp '2016-02-24 12:42:20')", + "-5000000", "INTEGER NOT NULL"); tester.checkScalar("timestampdiff(YEAR, " + "timestamp '2014-02-24 12:42:25', " + "timestamp '2016-02-24 12:42:25')", "2", "INTEGER NOT NULL"); + tester.checkScalar("timestampdiff(WEEK, " + + "timestamp '2014-02-24 12:42:25', " + + "timestamp '2016-02-24 12:42:25')", + "104", "INTEGER NOT NULL"); + tester.checkScalar("timestampdiff(WEEK, " + + "timestamp '2014-02-19 12:42:25', " + + "timestamp '2016-02-24 12:42:25')", + "105", "INTEGER NOT NULL"); + tester.checkScalar("timestampdiff(MONTH, " + + "timestamp '2014-02-24 12:42:25', " + + "timestamp '2016-02-24 12:42:25')", + "24", "INTEGER NOT NULL"); + tester.checkScalar("timestampdiff(QUARTER, " + + "timestamp '2014-02-24 12:42:25', " + + "timestamp '2016-02-24 12:42:25')", + "8", "INTEGER NOT NULL"); + tester.checkFails("timestampdiff(CENTURY, " + + "timestamp '2014-02-24 12:42:25', " + + "timestamp '2614-02-24 12:42:25')", + "(?s)Encountered \"CENTURY\" at .*", false); } @Test public void testDenseRankFunc() { http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java index 1ba65de..e4f6976 100644 --- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java +++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java @@ -53,7 +53,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException; import net.hydromatic.foodmart.data.hsqldb.FoodmartHsqldb; import net.hydromatic.scott.data.hsqldb.ScottHsqldb; -import org.hamcrest.CoreMatchers; +import org.hamcrest.Matcher; import java.io.File; import java.io.PrintWriter; @@ -86,6 +86,7 @@ import javax.sql.DataSource; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; @@ -287,12 +288,13 @@ public class CalciteAssert { }; } - public static Function<ResultSet, Void> checkResultCount(final int expected) { + public static Function<ResultSet, Void> + checkResultCount(final Matcher<Integer> expected) { return new Function<ResultSet, Void>() { public Void apply(ResultSet resultSet) { try { final int count = CalciteAssert.countRows(resultSet); - assertEquals(expected, count); + assertThat(count, expected); return null; } catch (SQLException e) { throw new RuntimeException(e); @@ -304,7 +306,7 @@ public class CalciteAssert { public static Function<Integer, Void> checkUpdateCount(final int expected) { return new Function<Integer, Void>() { public Void apply(Integer updateCount) { - assertThat(updateCount, CoreMatchers.is(expected)); + assertThat(updateCount, is(expected)); return null; } }; @@ -1194,7 +1196,7 @@ public class CalciteAssert { } public AssertQuery returnsCount(int expectedCount) { - return returns(checkResultCount(expectedCount)); + return returns(checkResultCount(is(expectedCount))); } public final AssertQuery returns(Function<ResultSet, Void> checker) { http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 f95c971..1c44a0b 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -50,6 +50,7 @@ import java.util.List; import java.util.Locale; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -3456,29 +3457,15 @@ public class SqlValidatorTest extends SqlValidatorTestCase { // accurately test bounds) final RelDataTypeSystem typeSystem = getTester().getValidator().getTypeFactory().getTypeSystem(); - assertTrue( - SqlTypeName.INTERVAL_YEAR_MONTH.getMinPrecision() == 1); - assertTrue( - SqlTypeName.INTERVAL_DAY_TIME.getMinPrecision() == 1); final RelDataTypeSystem defTypeSystem = RelDataTypeSystem.DEFAULT; - assertEquals(10, - defTypeSystem.getMaxPrecision(SqlTypeName.INTERVAL_YEAR_MONTH)); - assertEquals(10, - defTypeSystem.getMaxPrecision(SqlTypeName.INTERVAL_DAY_TIME)); - assertEquals(2, - typeSystem.getDefaultPrecision(SqlTypeName.INTERVAL_YEAR_MONTH)); - assertEquals(2, - typeSystem.getDefaultPrecision(SqlTypeName.INTERVAL_DAY_TIME)); - assertTrue( - SqlTypeName.INTERVAL_YEAR_MONTH.getMinScale() == 1); - assertTrue( - SqlTypeName.INTERVAL_DAY_TIME.getMinScale() == 1); - assertEquals(9, typeSystem.getMaxScale(SqlTypeName.INTERVAL_YEAR_MONTH)); - assertEquals(9, typeSystem.getMaxScale(SqlTypeName.INTERVAL_DAY_TIME)); - assertTrue( - SqlTypeName.INTERVAL_YEAR_MONTH.getDefaultScale() == 6); - assertTrue( - SqlTypeName.INTERVAL_DAY_TIME.getDefaultScale() == 6); + for (SqlTypeName typeName : SqlTypeName.INTERVAL_TYPES) { + assertThat(typeName.getMinPrecision(), is(1)); + assertThat(typeSystem.getMaxPrecision(typeName), is(10)); + assertThat(typeSystem.getDefaultPrecision(typeName), is(2)); + assertThat(typeName.getMinScale(), is(1)); + assertThat(typeSystem.getMaxScale(typeName), is(9)); + assertThat(typeName.getDefaultScale(), is(6)); + } // Tests that should pass both parser and validator subTestIntervalYearPositive();
