Skip to content

Commit

Permalink
SQL: Wrap ZonedDateTime parameters inside scripts (#39911)
Browse files Browse the repository at this point in the history
Painless allows ZonedDateTime objects to be passed natively to scripts
which creates problematic translate queries as the ZonedDateTime is
passed as a string instead.
Wrap this with a dedicated method to perform the conversion.

Fix #39877
  • Loading branch information
costin committed Mar 11, 2019
1 parent 28a14e3 commit 4957cad
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 2 deletions.
Expand Up @@ -348,7 +348,7 @@ public static Integer weekOfYear(Object dateTime, String tzId) {
public static ZonedDateTime asDateTime(Object dateTime) {
return (ZonedDateTime) asDateTime(dateTime, false);
}

private static Object asDateTime(Object dateTime, boolean lenient) {
if (dateTime == null) {
return null;
Expand All @@ -363,7 +363,10 @@ private static Object asDateTime(Object dateTime, boolean lenient) {
if (dateTime instanceof Number) {
return DateUtils.asDateTime(((Number) dateTime).longValue());
}


if (dateTime instanceof String) {
return DateUtils.asDateTime(dateTime.toString());
}
throw new SqlIllegalArgumentException("Invalid date encountered [{}]", dateTime);
}
return dateTime;
Expand Down
Expand Up @@ -17,6 +17,9 @@
import org.elasticsearch.xpack.sql.expression.literal.IntervalDayTime;
import org.elasticsearch.xpack.sql.expression.literal.IntervalYearMonth;
import org.elasticsearch.xpack.sql.type.DataType;
import org.elasticsearch.xpack.sql.util.DateUtils;

import java.time.ZonedDateTime;

import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;

Expand Down Expand Up @@ -52,7 +55,18 @@ default ScriptTemplate asScript(Expression exp) {

default ScriptTemplate scriptWithFoldable(Expression foldable) {
Object fold = foldable.fold();

//
// Custom type handling
//

// wrap intervals with dedicated methods for serialization
if (fold instanceof ZonedDateTime) {
ZonedDateTime zdt = (ZonedDateTime) fold;
return new ScriptTemplate(processScript("{sql}.asDateTime({})"),
paramsBuilder().variable(DateUtils.toString(zdt)).build(), dataType());
}

if (fold instanceof IntervalYearMonth) {
IntervalYearMonth iym = (IntervalYearMonth) fold;
return new ScriptTemplate(processScript("{sql}.intervalYearMonth({},{})"),
Expand Down
Expand Up @@ -59,6 +59,7 @@

import static org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation.E;
import static org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation.PI;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.startsWith;

Expand Down Expand Up @@ -728,4 +729,17 @@ public void testNoCountDoesNotTrackHits() throws Exception {
EsQueryExec eqe = (EsQueryExec) p;
assertFalse("Should NOT be tracking hits", eqe.queryContainer().shouldTrackHits());
}

public void testZonedDateTimeInScripts() throws Exception {
PhysicalPlan p = optimizeAndPlan(
"SELECT date FROM test WHERE date + INTERVAL 1 YEAR > CAST('2019-03-11T12:34:56.000Z' AS DATETIME)");
assertEquals(EsQueryExec.class, p.getClass());
EsQueryExec eqe = (EsQueryExec) p;
assertThat(eqe.queryContainer().toString().replaceAll("\\s+", ""), containsString(
"\"script\":{\"script\":{\"source\":\"InternalSqlScriptUtils.nullSafeFilter("
+ "InternalSqlScriptUtils.gt(InternalSqlScriptUtils.add(InternalSqlScriptUtils.docValue(doc,params.v0),"
+ "InternalSqlScriptUtils.intervalYearMonth(params.v1,params.v2)),InternalSqlScriptUtils.asDateTime(params.v3)))\","
+ "\"lang\":\"painless\","
+ "\"params\":{\"v0\":\"date\",\"v1\":\"P1Y\",\"v2\":\"INTERVAL_YEAR\",\"v3\":\"2019-03-11T12:34:56.000Z\"}},"));
}
}

0 comments on commit 4957cad

Please sign in to comment.