SQL: Fix handling of CURRENT_TIMESTAMP and friends in non-UTC timezones. (#4114)

This commit is contained in:
Gian Merlino 2017-03-24 18:45:23 -07:00 committed by GitHub
parent dd6c0ab509
commit 76c4b6446e
3 changed files with 40 additions and 8 deletions

View File

@ -34,6 +34,7 @@ import org.joda.time.DateTimeZone;
import org.joda.time.Days;
import java.nio.charset.Charset;
import java.util.Calendar;
/**
* Utility functions for Calcite.
@ -139,6 +140,22 @@ public class Calcites
return Days.daysBetween(new DateTime(0L, DateTimeZone.UTC), date.withZoneRetainFields(DateTimeZone.UTC)).getDays();
}
/**
* Calcite expects TIMESTAMP and DATE literals to be represented by Calendars that would have the expected
* local time fields if printed as UTC.
*
* @param dateTime joda timestamp
* @param timeZone session time zone
*
* @return Calcite style Calendar, appropriate for literals
*/
public static Calendar jodaToCalciteCalendarLiteral(final DateTime dateTime, final DateTimeZone timeZone)
{
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(Calcites.jodaToCalciteTimestamp(dateTime, timeZone));
return calendar;
}
/**
* The inverse of {@link #jodaToCalciteTimestamp(DateTime, DateTimeZone)}.
*

View File

@ -32,7 +32,6 @@ import org.apache.calcite.sql2rel.SqlRexConvertlet;
import org.apache.calcite.sql2rel.SqlRexConvertletTable;
import org.apache.calcite.sql2rel.StandardConvertletTable;
import java.util.Locale;
import java.util.Map;
public class DruidConvertletTable implements SqlRexConvertletTable
@ -84,17 +83,20 @@ public class DruidConvertletTable implements SqlRexConvertletTable
final SqlOperator operator = call.getOperator();
if (operator == SqlStdOperatorTable.CURRENT_TIMESTAMP || operator == SqlStdOperatorTable.LOCALTIMESTAMP) {
return cx.getRexBuilder().makeTimestampLiteral(
plannerContext.getLocalNow().toCalendar(Locale.getDefault()),
Calcites.jodaToCalciteCalendarLiteral(plannerContext.getLocalNow(), plannerContext.getTimeZone()),
RelDataType.PRECISION_NOT_SPECIFIED
);
} else if (operator == SqlStdOperatorTable.CURRENT_TIME || operator == SqlStdOperatorTable.LOCALTIME) {
return cx.getRexBuilder().makeTimeLiteral(
plannerContext.getLocalNow().toCalendar(Locale.getDefault()),
Calcites.jodaToCalciteCalendarLiteral(plannerContext.getLocalNow(), plannerContext.getTimeZone()),
RelDataType.PRECISION_NOT_SPECIFIED
);
} else if (operator == SqlStdOperatorTable.CURRENT_DATE) {
return cx.getRexBuilder().makeDateLiteral(
plannerContext.getLocalNow().hourOfDay().roundFloorCopy().toCalendar(Locale.getDefault())
Calcites.jodaToCalciteCalendarLiteral(
plannerContext.getLocalNow().hourOfDay().roundFloorCopy(),
plannerContext.getTimeZone()
)
);
} else {
throw new ISE("WTF?! Should not have got here, operator was: %s", operator);

View File

@ -2962,6 +2962,19 @@ public class CalciteQueryTest
);
}
@Test
public void testSelectCurrentTimeAndDateLosAngeles() throws Exception
{
testQuery(
PlannerContext.create(PLANNER_CONFIG_DEFAULT, QUERY_CONTEXT_LOS_ANGELES),
"SELECT CURRENT_TIMESTAMP, CURRENT_DATE, CURRENT_DATE + INTERVAL '1' DAY",
ImmutableList.of(),
ImmutableList.of(
new Object[]{T("2000-01-01T00Z", LOS_ANGELES), D("1999-12-31"), D("2000-01-01")}
)
);
}
@Test
public void testFilterOnCurrentTimestampLosAngeles() throws Exception
{
@ -2972,14 +2985,14 @@ public class CalciteQueryTest
ImmutableList.<Query>of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(QSS(new Interval("2000-01-02T08Z/2002-01-01T08Z")))
.intervals(QSS(new Interval("2000-01-02T00Z/2002-01-01T08Z")))
.granularity(Granularities.ALL)
.aggregators(AGGS(new CountAggregatorFactory("a0")))
.context(TIMESERIES_CONTEXT_LOS_ANGELES)
.build()
),
ImmutableList.of(
new Object[]{4L}
new Object[]{5L}
)
);
}
@ -3016,14 +3029,14 @@ public class CalciteQueryTest
ImmutableList.<Query>of(
Druids.newTimeseriesQueryBuilder()
.dataSource(CalciteTests.DATASOURCE1)
.intervals(QSS(new Interval("2000-01-02T08Z/2002-01-01T08Z")))
.intervals(QSS(new Interval("2000-01-02T00Z/2002-01-01T08Z")))
.granularity(Granularities.ALL)
.aggregators(AGGS(new CountAggregatorFactory("a0")))
.context(TIMESERIES_CONTEXT_LOS_ANGELES)
.build()
),
ImmutableList.of(
new Object[]{4L}
new Object[]{5L}
)
);
}