From 029d02d9048d8eab5e4712533f6a9edcb8e332d1 Mon Sep 17 00:00:00 2001 From: Roman Kulyk Date: Fri, 1 Sep 2017 19:21:04 +0300 Subject: [PATCH] Drill-specific changes: added a general class for Date/Time/Timestamp literals (TimestampString, DateString, TimeString) to avoid class cast exceptions. In case of "date + interval" situation, for example: where o.o_orderdate >= date '1996-10-01' and o.o_orderdate < date '1996-10-01' + interval '3' month Drill will cast DATE to TIMESTAMP and we can face with ClassCastException like "ClassCastException: org.apache.calcite.util.DateString cannot be cast to org.apache.calcite.util.TimestampString" when Calcite will compare DATE ('1996-10-01') with TIMESTAMP ('1996-10-01' + interval '3'). To avoid this situation added a general class for Date/Time/Timestamp literals to make them comparable to each other. Also added comparing NlsString with Date/Time/Timestamp strings to avoid ClassCastExceptoin in queries like: WHERE birth_date BETWEEN '1920-01-01' AND cast('1931-01-01' AS DATE) In this case, '1920-01-01' is NlsString and we got ClassCastExceptoin when we tried to compare it with Date '1931-01-01'. (cherry picked from commit afd4fc6) (cherry picked from commit 6e793d4) --- .../apache/calcite/util/AbstractDateTime.java | 38 +++++++++++++++++++ .../org/apache/calcite/util/DateString.java | 11 +----- .../org/apache/calcite/util/NlsString.java | 9 +++-- .../org/apache/calcite/util/TimeString.java | 11 +----- .../apache/calcite/util/TimestampString.java | 12 ++---- 5 files changed, 51 insertions(+), 30 deletions(-) create mode 100644 core/src/main/java/org/apache/calcite/util/AbstractDateTime.java diff --git a/core/src/main/java/org/apache/calcite/util/AbstractDateTime.java b/core/src/main/java/org/apache/calcite/util/AbstractDateTime.java new file mode 100644 index 000000000..27e5e4f38 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/util/AbstractDateTime.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.util; + +/** + * General class for Date/Time/Timestamp literals (TimestampString, DateString, TimeString) + * to make them comparable to each other + */ +public abstract class AbstractDateTime implements Comparable { + protected final String v; + + public AbstractDateTime(String v) { + this.v = v; + } + + @Override public int compareTo(Object o) { + if (o instanceof NlsString) { + return v.compareTo(((NlsString) o).getValue()); + } + return v.compareTo(((AbstractDateTime) o).v); + } +} + +// End AbstractDateTime.java diff --git a/core/src/main/java/org/apache/calcite/util/DateString.java b/core/src/main/java/org/apache/calcite/util/DateString.java index 3a704ff86..6af83f104 100644 --- a/core/src/main/java/org/apache/calcite/util/DateString.java +++ b/core/src/main/java/org/apache/calcite/util/DateString.java @@ -22,22 +22,19 @@ import java.util.Calendar; import java.util.regex.Pattern; -import javax.annotation.Nonnull; /** * Date literal. * *

Immutable, internally represented as a string (in ISO format). */ -public class DateString implements Comparable { +public class DateString extends AbstractDateTime { private static final Pattern PATTERN = Pattern.compile("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"); - final String v; - /** Internal constructor, no validation. */ private DateString(String v, @SuppressWarnings("unused") boolean ignore) { - this.v = v; + super(v); } /** Creates a DateString. */ @@ -86,10 +83,6 @@ private static String ymd(int year, int month, int day) { return v.hashCode(); } - @Override public int compareTo(@Nonnull DateString o) { - return v.compareTo(o.v); - } - /** Creates a DateString from a Calendar. */ public static DateString fromCalendarFields(Calendar calendar) { return new DateString(calendar.get(Calendar.YEAR), diff --git a/core/src/main/java/org/apache/calcite/util/NlsString.java b/core/src/main/java/org/apache/calcite/util/NlsString.java index 8c6727455..573ac3865 100644 --- a/core/src/main/java/org/apache/calcite/util/NlsString.java +++ b/core/src/main/java/org/apache/calcite/util/NlsString.java @@ -44,7 +44,7 @@ * A string, optionally with {@link Charset character set} and * {@link SqlCollation}. It is immutable. */ -public class NlsString implements Comparable, Cloneable { +public class NlsString implements Comparable, Cloneable { //~ Instance fields -------------------------------------------------------- private static final LoadingCache, String> @@ -170,10 +170,13 @@ public boolean equals(Object obj) { && Objects.equals(collation, ((NlsString) obj).collation); } - @Override public int compareTo(NlsString other) { + // implement Comparable + public int compareTo(Object other) { // TODO jvs 18-Jan-2006: Actual collation support. This just uses // the default collation. - return getValue().compareTo(other.getValue()); + return other instanceof AbstractDateTime + ? getValue().compareTo(((AbstractDateTime) other).v) + : getValue().compareTo(((NlsString) other).getValue()); } public String getCharsetName() { diff --git a/core/src/main/java/org/apache/calcite/util/TimeString.java b/core/src/main/java/org/apache/calcite/util/TimeString.java index 8527f6770..af83dcb3a 100644 --- a/core/src/main/java/org/apache/calcite/util/TimeString.java +++ b/core/src/main/java/org/apache/calcite/util/TimeString.java @@ -23,7 +23,6 @@ import java.util.Calendar; import java.util.regex.Pattern; -import javax.annotation.Nonnull; /** * Time literal. @@ -31,15 +30,13 @@ *

Immutable, internally represented as a string (in ISO format), * and can support unlimited precision (milliseconds, nanoseconds). */ -public class TimeString implements Comparable { +public class TimeString extends AbstractDateTime { private static final Pattern PATTERN = Pattern.compile("[0-9][0-9]:[0-9][0-9]:[0-9][0-9](\\.[0-9]*[1-9])?"); - final String v; - /** Internal constructor, no validation. */ private TimeString(String v, @SuppressWarnings("unused") boolean ignore) { - this.v = v; + super(v); } /** Creates a TimeString. */ @@ -129,10 +126,6 @@ public TimeString withFraction(String fraction) { return v.hashCode(); } - @Override public int compareTo(@Nonnull TimeString o) { - return v.compareTo(o.v); - } - /** Creates a TimeString from a Calendar. */ public static TimeString fromCalendarFields(Calendar calendar) { return new TimeString( diff --git a/core/src/main/java/org/apache/calcite/util/TimestampString.java b/core/src/main/java/org/apache/calcite/util/TimestampString.java index 604d5a4ac..40dc3c737 100644 --- a/core/src/main/java/org/apache/calcite/util/TimestampString.java +++ b/core/src/main/java/org/apache/calcite/util/TimestampString.java @@ -30,24 +30,22 @@ *

Immutable, internally represented as a string (in ISO format), * and can support unlimited precision (milliseconds, nanoseconds). */ -public class TimestampString implements Comparable { +public class TimestampString extends AbstractDateTime { private static final Pattern PATTERN = Pattern.compile("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" + " " + "[0-9][0-9]:[0-9][0-9]:[0-9][0-9](\\.[0-9]*[1-9])?"); - final String v; - /** Creates a TimeString. */ public TimestampString(String v) { - this.v = v; + super(v); Preconditions.checkArgument(PATTERN.matcher(v).matches(), v); } /** Creates a TimestampString for year, month, day, hour, minute, second, * millisecond values. */ public TimestampString(int year, int month, int day, int h, int m, int s) { - this(DateTimeStringUtils.ymdhms(new StringBuilder(), year, month, day, h, m, s).toString()); + super(DateTimeStringUtils.ymdhms(new StringBuilder(), year, month, day, h, m, s).toString()); } /** Sets the fraction field of a {@code TimestampString} to a given number @@ -109,10 +107,6 @@ public TimestampString withFraction(String fraction) { return v.hashCode(); } - @Override public int compareTo(TimestampString o) { - return v.compareTo(o.v); - } - /** Creates a TimestampString from a Calendar. */ public static TimestampString fromCalendarFields(Calendar calendar) { return new TimestampString(