diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/AbstractFunctionRegistry.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/AbstractFunctionRegistry.java index 7824323c1ae..1464226ab6e 100644 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/AbstractFunctionRegistry.java +++ b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/AbstractFunctionRegistry.java @@ -7,62 +7,56 @@ package org.elasticsearch.xpack.sql.expression.function; import org.elasticsearch.common.Strings; import org.elasticsearch.xpack.sql.SqlIllegalArgumentException; -import org.elasticsearch.xpack.sql.expression.function.aware.DistinctAware; -import org.elasticsearch.xpack.sql.expression.function.aware.TimeZoneAware; +import org.elasticsearch.xpack.sql.expression.Expression; import org.elasticsearch.xpack.sql.parser.ParsingException; -import org.elasticsearch.xpack.sql.tree.Node; -import org.elasticsearch.xpack.sql.tree.NodeUtils; -import org.elasticsearch.xpack.sql.tree.NodeUtils.NodeInfo; -import org.elasticsearch.xpack.sql.util.Check; +import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.util.StringUtils; import org.joda.time.DateTimeZone; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.BiFunction; import java.util.regex.Pattern; import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; abstract class AbstractFunctionRegistry implements FunctionRegistry { + private final Map defs = new LinkedHashMap<>(); + private final Map aliases; - protected final Map defs = new LinkedHashMap<>(); - - { - for (Class f : functions()) { - FunctionDefinition def = def(f, aliases()); - defs.put(def.name(), def); - for (String alias : def.aliases()) { - Check.isTrue(defs.containsKey(alias) == false, "Alias %s already exists", alias); - // alias should be already normalized but to be double sure - defs.put(normalize(alias), def); + protected AbstractFunctionRegistry(List functions) { + this.aliases = new HashMap<>(); + for (FunctionDefinition f : functions) { + defs.put(f.name(), f); + for (String alias : f.aliases()) { + Object old = aliases.put(alias, f.name()); + if (old != null) { + throw new IllegalArgumentException("alias [" + alias + "] is used by [" + old + "] and [" + f.name() + "]"); + } + defs.put(alias, f); } } } - //TODO: change this to some type of auto discovery or auto creation of the discovery (annotation or the like) - protected abstract Collection> functions(); - - protected abstract Map aliases(); - - @Override public Function resolveFunction(UnresolvedFunction ur, DateTimeZone timeZone) { FunctionDefinition def = defs.get(normalize(ur.name())); if (def == null) { throw new SqlIllegalArgumentException("Cannot find function %s; this should have been caught during analysis", ur.name()); } - return createInstance(def.clazz(), ur, timeZone); + return def.builder().apply(ur, timeZone); } @Override public String concreteFunctionName(String alias) { String normalized = normalize(alias); - return aliases().getOrDefault(normalized, normalized); + return aliases.getOrDefault(normalized, normalized); } @Override @@ -73,7 +67,7 @@ abstract class AbstractFunctionRegistry implements FunctionRegistry { @Override public Collection listFunctions() { return defs.entrySet().stream() - .map(e -> new FunctionDefinition(e.getKey(), emptyList(), e.getValue().clazz())) + .map(e -> new FunctionDefinition(e.getKey(), emptyList(), e.getValue().clazz(), e.getValue().builder())) .collect(toList()); } @@ -82,101 +76,128 @@ abstract class AbstractFunctionRegistry implements FunctionRegistry { Pattern p = Strings.hasText(pattern) ? StringUtils.likeRegex(normalize(pattern)) : null; return defs.entrySet().stream() .filter(e -> p == null || p.matcher(e.getKey()).matches()) - .map(e -> new FunctionDefinition(e.getKey(), emptyList(), e.getValue().clazz())) + .map(e -> new FunctionDefinition(e.getKey(), emptyList(), e.getValue().clazz(), e.getValue().builder())) .collect(toList()); } - private static FunctionDefinition def(Class function, Map aliases) { - String primaryName = normalize(function.getSimpleName()); - List al = aliases.entrySet().stream() - .filter(e -> primaryName.equals(e.getValue())) - .map(Map.Entry::getKey) - .collect(toList()); + /** + * Build a {@linkplain FunctionDefinition} for a no-argument function that + * is not aware of time zone and does not support {@code DISTINCT}. + */ + protected static FunctionDefinition def(Class function, + java.util.function.Function ctorRef, String... aliases) { + FunctionBuilder builder = (location, children, distinct, tz) -> { + if (false == children.isEmpty()) { + throw new IllegalArgumentException("expects only a single argument"); + } + if (distinct) { + throw new IllegalArgumentException("does not support DISTINCT yet it was specified"); + } + return ctorRef.apply(location); + }; + return def(function, builder, aliases); + } - return new FunctionDefinition(primaryName, al, function); + /** + * Build a {@linkplain FunctionDefinition} for a unary function that is not + * aware of time zone and does not support {@code DISTINCT}. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, + BiFunction ctorRef, String... aliases) { + FunctionBuilder builder = (location, children, distinct, tz) -> { + if (children.size() != 1) { + throw new IllegalArgumentException("expects only a single argument"); + } + if (distinct) { + throw new IllegalArgumentException("does not support DISTINCT yet it was specified"); + } + return ctorRef.apply(location, children.get(0)); + }; + return def(function, builder, aliases); + } + + /** + * Build a {@linkplain FunctionDefinition} for a unary function that is not + * aware of time zone but does support {@code DISTINCT}. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, + DistinctAwareUnaryFunctionBuilder ctorRef, String... aliases) { + FunctionBuilder builder = (location, children, distinct, tz) -> { + if (children.size() != 1) { + throw new IllegalArgumentException("expects only a single argument"); + } + return ctorRef.build(location, children.get(0), distinct); + }; + return def(function, builder, aliases); + } + protected interface DistinctAwareUnaryFunctionBuilder { + T build(Location location, Expression target, boolean distinct); + } + + /** + * Build a {@linkplain FunctionDefinition} for a unary function that is + * aware of time zone and does not support {@code DISTINCT}. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, + TimeZoneAwareUnaryFunctionBuilder ctorRef, String... aliases) { + FunctionBuilder builder = (location, children, distinct, tz) -> { + if (children.size() != 1) { + throw new IllegalArgumentException("expects only a single argument"); + } + if (distinct) { + throw new IllegalArgumentException("does not support DISTINCT yet it was specified"); + } + return ctorRef.build(location, children.get(0), tz); + }; + return def(function, builder, aliases); + } + protected interface TimeZoneAwareUnaryFunctionBuilder { + T build(Location location, Expression target, DateTimeZone tz); + } + + /** + * Build a {@linkplain FunctionDefinition} for a binary function that is + * not aware of time zone and does not support {@code DISTINCT}. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, + BinaryFunctionBuilder ctorRef, String... aliases) { + FunctionBuilder builder = (location, children, distinct, tz) -> { + if (children.size() != 2) { + throw new IllegalArgumentException("expects only a single argument"); + } + if (distinct) { + throw new IllegalArgumentException("does not support DISTINCT yet it was specified"); + } + return ctorRef.build(location, children.get(0), children.get(1)); + }; + return def(function, builder, aliases); + } + protected interface BinaryFunctionBuilder { + T build(Location location, Expression lhs, Expression rhs); + } + + private static FunctionDefinition def(Class function, FunctionBuilder builder, String... aliases) { + String primaryName = normalize(function.getSimpleName()); + BiFunction realBuilder = (uf, tz) -> { + try { + return builder.build(uf.location(), uf.children(), uf.distinct(), tz); + } catch (IllegalArgumentException e) { + throw new ParsingException("error builder [" + primaryName + "]: " + e.getMessage(), e, + uf.location().getLineNumber(), uf.location().getColumnNumber()); + } + }; + return new FunctionDefinition(primaryName, unmodifiableList(Arrays.asList(aliases)), function, realBuilder); + } + private interface FunctionBuilder { + Function build(Location location, List children, boolean distinct, DateTimeZone tz); } protected static String normalize(String name) { // translate CamelCase to camel_case return StringUtils.camelCaseToUnderscore(name); } - - // - // Instantiates a function through reflection. - // Picks up the constructor by expecting to be of type (Location,Expression) or (Location,List) depending on the size of given children, parameters. - // If the function has certain 'aware'-ness (based on the interface implemented), the appropriate types are added to the signature - - @SuppressWarnings("rawtypes") - private static Function createInstance(Class clazz, UnresolvedFunction ur, DateTimeZone timeZone) { - NodeInfo info = NodeUtils.info((Class) clazz); - Class[] pTypes = info.ctr.getParameterTypes(); - - boolean distinctAware = DistinctAware.class.isAssignableFrom(clazz); - boolean timezoneAware = TimeZoneAware.class.isAssignableFrom(clazz); - - // constructor types - location - distinct? - timezone? - int expectedParamCount = pTypes.length - (1 + (distinctAware ? 1 : 0) + (timezoneAware ? 1 : 0)); - - // check constructor signature - if (ur.children().size() != expectedParamCount) { - List expected = new ArrayList<>(); - - for (int i = 1; i < expectedParamCount; i++) { - expected.add(pTypes[i].getSimpleName()); - } - - throw new ParsingException(ur.location(), "Invalid number of arguments given to function [%s], expected %d argument(s):%s but received %d:%s", - ur.name(), expected.size(), expected.toString(), ur.children().size(), ur.children()); - } - - // validate distinct ctor - if (!distinctAware && ur.distinct()) { - throw new ParsingException(ur.location(), "Function [%s] does not support DISTINCT yet it was specified", ur.name()); - } - - // List ctorSignature = new ArrayList<>(); - // ctorSignature.add(Location.class); - // - // // might be a constant function - // if (expVal instanceof List && ((List) expVal).isEmpty()) { - // noExpression = Arrays.equals(new Class[] { Location.class }, info.ctr.getParameterTypes()); - // } - // else { - // ctorSignature.add(exp); - // } - // - // // aware stuff - // if (distinctAware) { - // ctorSignature.add(boolean.class); - // } - // if (timezoneAware) { - // ctorSignature.add(DateTimeZone.class); - // } - // - // // validate - // Assert.isTrue(Arrays.equals(ctorSignature.toArray(new Class[ctorSignature.size()]), info.ctr.getParameterTypes()), - // "No constructor with signature %s found for [%s], found %s instead", ctorSignature, clazz.getTypeName(), info.ctr); - - // now add the actual values - try { - List args = new ArrayList<>(); - - // always add location first - args.add(ur.location()); - - // has multiple arguments - args.addAll(ur.children()); - - if (distinctAware) { - args.add(ur.distinct()); - } - if (timezoneAware) { - args.add(timeZone); - } - - return (Function) info.ctr.newInstance(args.toArray()); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - throw new SqlIllegalArgumentException(ex, "Cannot create instance of function %s", ur.name()); - } - } } diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/DefaultFunctionRegistry.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/DefaultFunctionRegistry.java index 24312341f7a..4ef83f8ae3a 100644 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/DefaultFunctionRegistry.java +++ b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/DefaultFunctionRegistry.java @@ -6,7 +6,6 @@ package org.elasticsearch.xpack.sql.expression.function; import org.elasticsearch.xpack.sql.expression.function.Score; -import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.sql.expression.function.aggregate.Avg; import org.elasticsearch.xpack.sql.expression.function.aggregate.Correlation; import org.elasticsearch.xpack.sql.expression.function.aggregate.Count; @@ -25,7 +24,6 @@ import org.elasticsearch.xpack.sql.expression.function.aggregate.StddevPop; import org.elasticsearch.xpack.sql.expression.function.aggregate.Sum; import org.elasticsearch.xpack.sql.expression.function.aggregate.SumOfSquares; import org.elasticsearch.xpack.sql.expression.function.aggregate.VarPop; -import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction; import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfMonth; import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfWeek; import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfYear; @@ -57,98 +55,72 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.math.Sin; import org.elasticsearch.xpack.sql.expression.function.scalar.math.Sinh; import org.elasticsearch.xpack.sql.expression.function.scalar.math.Sqrt; import org.elasticsearch.xpack.sql.expression.function.scalar.math.Tan; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import static java.util.Collections.unmodifiableMap; import static java.util.Collections.unmodifiableList; public class DefaultFunctionRegistry extends AbstractFunctionRegistry { - - private static final Collection> FUNCTIONS = unmodifiableList(Arrays.asList( + private static final List FUNCTIONS = unmodifiableList(Arrays.asList( // Aggregate functions - Avg.class, - Count.class, - Max.class, - Min.class, - Sum.class, + def(Avg.class, Avg::new), + def(Count.class, Count::new), + def(Max.class, Max::new), + def(Min.class, Min::new), + def(Sum.class, Sum::new), // Statistics - Mean.class, - StddevPop.class, - VarPop.class, - Percentile.class, - PercentileRank.class, - SumOfSquares.class, + def(Mean.class, Mean::new), + def(StddevPop.class, StddevPop::new), + def(VarPop.class, VarPop::new), + def(Percentile.class, Percentile::new), + def(PercentileRank.class, PercentileRank::new), + def(SumOfSquares.class, SumOfSquares::new), // Matrix aggs - MatrixCount.class, - MatrixMean.class, - MatrixVariance.class, - Skewness.class, - Kurtosis.class, - Covariance.class, - Correlation.class, + def(MatrixCount.class, MatrixCount::new), + def(MatrixMean.class, MatrixMean::new), + def(MatrixVariance.class, MatrixVariance::new), + def(Skewness.class, Skewness::new), + def(Kurtosis.class, Kurtosis::new), + def(Covariance.class, Covariance::new), + def(Correlation.class, Correlation::new), // Scalar functions // Date - DayOfMonth.class, - DayOfWeek.class, - DayOfYear.class, - HourOfDay.class, - MinuteOfDay.class, - MinuteOfHour.class, - SecondOfMinute.class, - MonthOfYear.class, - Year.class, + def(DayOfMonth.class, DayOfMonth::new, "DAY", "DOM"), + def(DayOfWeek.class, DayOfWeek::new, "DOW"), + def(DayOfYear.class, DayOfYear::new, "DOY"), + def(HourOfDay.class, HourOfDay::new, "HOUR"), + def(MinuteOfDay.class, MinuteOfDay::new), + def(MinuteOfHour.class, MinuteOfHour::new, "MINUTE"), + def(SecondOfMinute.class, SecondOfMinute::new, "SECOND"), + def(MonthOfYear.class, MonthOfYear::new, "MONTH"), + def(Year.class, Year::new), // Math - Abs.class, - ACos.class, - ASin.class, - ATan.class, - Cbrt.class, - Ceil.class, - Cos.class, - Cosh.class, - Degrees.class, - E.class, - Exp.class, - Expm1.class, - Floor.class, - Log.class, - Log10.class, - Pi.class, - Radians.class, - Round.class, - Sin.class, - Sinh.class, - Sqrt.class, - Tan.class, + def(Abs.class, Abs::new), + def(ACos.class, ACos::new), + def(ASin.class, ASin::new), + def(ATan.class, ATan::new), + def(Cbrt.class, Cbrt::new), + def(Ceil.class, Ceil::new), + def(Cos.class, Cos::new), + def(Cosh.class, Cosh::new), + def(Degrees.class, Degrees::new), + def(E.class, E::new), + def(Exp.class, Exp::new), + def(Expm1.class, Expm1::new), + def(Floor.class, Floor::new), + def(Log.class, Log::new), + def(Log10.class, Log10::new), + def(Pi.class, Pi::new), + def(Radians.class, Radians::new), + def(Round.class, Round::new), + def(Sin.class, Sin::new), + def(Sinh.class, Sinh::new), + def(Sqrt.class, Sqrt::new), + def(Tan.class, Tan::new), // Special - Score.class)); + def(Score.class, Score::new))); - private static final Map ALIASES; - static { - Map aliases = new TreeMap<>(); - aliases.put("DAY", "DAY_OF_MONTH"); - aliases.put("DOM", "DAY_OF_MONTH"); - aliases.put("DOW", "DAY_OF_WEEK"); - aliases.put("DOY", "DAY_OF_YEAR"); - aliases.put("HOUR", "HOUR_OF_DAY"); - aliases.put("MINUTE", "MINUTE_OF_HOUR"); - aliases.put("MONTH", "MONTH_OF_YEAR"); - aliases.put("SECOND", "SECOND_OF_MINUTE"); - ALIASES = unmodifiableMap(aliases); - } - - @Override - protected Collection> functions() { - return FUNCTIONS; - } - - @Override - protected Map aliases() { - return ALIASES; + public DefaultFunctionRegistry() { + super(FUNCTIONS); } } diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionDefinition.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionDefinition.java index e7dc8c21628..ea232265151 100644 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionDefinition.java +++ b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionDefinition.java @@ -8,6 +8,8 @@ package org.elasticsearch.xpack.sql.expression.function; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.function.BiFunction; +import org.joda.time.DateTimeZone; import static java.lang.String.format; @@ -16,12 +18,15 @@ public class FunctionDefinition { private final String name; private final List aliases; private final Class clazz; + private final BiFunction builder; private final FunctionType type; - FunctionDefinition(String name, List aliases, Class clazz) { + FunctionDefinition(String name, List aliases, + Class clazz, BiFunction builder) { this.name = name; this.aliases = aliases; this.clazz = clazz; + this.builder = builder; this.type = FunctionType.of(clazz); } @@ -41,21 +46,25 @@ public class FunctionDefinition { return clazz; } + BiFunction builder() { + return builder; + } + @Override public int hashCode() { return Objects.hash(clazz); } - + @Override public boolean equals(Object obj) { if (this == obj) { return true; } - + if (obj == null || getClass() != obj.getClass()) { return false; } - + FunctionDefinition other = (FunctionDefinition) obj; return Objects.equals(clazz, other.clazz) && Objects.equals(name, other.name) && diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aggregate/Count.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aggregate/Count.java index 93df442a8da..0b76c54a103 100644 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aggregate/Count.java +++ b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aggregate/Count.java @@ -7,12 +7,11 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate; import org.elasticsearch.xpack.sql.expression.Expression; import org.elasticsearch.xpack.sql.expression.NamedExpression; -import org.elasticsearch.xpack.sql.expression.function.aware.DistinctAware; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.type.DataType; import org.elasticsearch.xpack.sql.type.DataTypes; -public class Count extends AggregateFunction implements DistinctAware { +public class Count extends AggregateFunction { private final boolean distinct; @@ -44,4 +43,4 @@ public class Count extends AggregateFunction implements DistinctAware { public AggregateFunctionAttribute toAttribute() { return new AggregateFunctionAttribute(location(), name(), dataType(), id(), functionId(), "_count"); } -} \ No newline at end of file +} diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aware/DistinctAware.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aware/DistinctAware.java deleted file mode 100644 index 17043ea8027..00000000000 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aware/DistinctAware.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.sql.expression.function.aware; - -public interface DistinctAware { - -} diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aware/TimeZoneAware.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aware/TimeZoneAware.java deleted file mode 100644 index 9cf7641d17e..00000000000 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/aware/TimeZoneAware.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.sql.expression.function.aware; - -public interface TimeZoneAware { - -} diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java index 69b7d9824fa..a5ffb0f7451 100644 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java +++ b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java @@ -9,7 +9,6 @@ import org.elasticsearch.xpack.sql.expression.Expression; import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.FieldAttribute; import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute; -import org.elasticsearch.xpack.sql.expression.function.aware.TimeZoneAware; import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction; import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor; import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinition; @@ -27,7 +26,7 @@ import java.time.temporal.ChronoField; import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder; import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate.formatTemplate; -public abstract class DateTimeFunction extends UnaryScalarFunction implements TimeZoneAware { +public abstract class DateTimeFunction extends UnaryScalarFunction { private final DateTimeZone timeZone; private final String name; @@ -42,7 +41,7 @@ public abstract class DateTimeFunction extends UnaryScalarFunction implements Ti this.name = sb.toString(); } - + public DateTimeZone timeZone() { return timeZone; } @@ -54,7 +53,7 @@ public abstract class DateTimeFunction extends UnaryScalarFunction implements Ti @Override protected TypeResolution resolveType() { - return field().dataType().same(DataTypes.DATE) ? + return field().dataType().same(DataTypes.DATE) ? TypeResolution.TYPE_RESOLVED : new TypeResolution("Function '%s' cannot be applied on a non-date expression ('%s' of type '%s')", functionName(), Expressions.name(field()), field().dataType().esName()); } @@ -62,7 +61,7 @@ public abstract class DateTimeFunction extends UnaryScalarFunction implements Ti @Override protected ScriptTemplate asScriptFrom(FieldAttribute field) { ParamsBuilder params = paramsBuilder(); - + String template = null; if (DateTimeZone.UTC.equals(timeZone)) { // TODO: it would be nice to be able to externalize the extract function and reuse the script across all extractors @@ -76,13 +75,13 @@ public abstract class DateTimeFunction extends UnaryScalarFunction implements Ti // ideally JodaTime should be used since that's internally used and there are subtle differences between that and the JDK API // all variables are externalized to reuse the script across invocations // the actual script is ZonedDateTime.ofInstant(Instant.ofEpochMilli(.value.millis), ZoneId.of()).get(ChronoField.get(MONTH_OF_YEAR)) - + template = formatTemplate("ZonedDateTime.ofInstant(Instant.ofEpochMilli(doc[{}].value.millis), ZoneId.of({})).get(ChronoField.valueOf({}))"); params.variable(field.name()) .variable(timeZone.getID()) .variable(chronoField().name()); } - + return new ScriptTemplate(template, params.build(), dataType()); } @@ -121,4 +120,4 @@ public abstract class DateTimeFunction extends UnaryScalarFunction implements Ti public String name() { return name; } -} \ No newline at end of file +} diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeHistogramFunction.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeHistogramFunction.java index 5f74c47d49a..93f2bde3aa4 100644 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeHistogramFunction.java +++ b/sql/server/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeHistogramFunction.java @@ -6,7 +6,6 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.datetime; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.function.aware.TimeZoneAware; import org.elasticsearch.xpack.sql.tree.Location; import org.joda.time.DateTimeZone; @@ -14,7 +13,7 @@ import org.joda.time.DateTimeZone; * DateTimeFunctions that can be mapped as histogram. This means the dates order is maintained * Unfortunately this means only YEAR works since everything else changes the order */ -public abstract class DateTimeHistogramFunction extends DateTimeFunction implements TimeZoneAware { +public abstract class DateTimeHistogramFunction extends DateTimeFunction { DateTimeHistogramFunction(Location location, Expression field, DateTimeZone timeZone) { super(location, field, timeZone); diff --git a/sql/server/src/main/java/org/elasticsearch/xpack/sql/parser/ParsingException.java b/sql/server/src/main/java/org/elasticsearch/xpack/sql/parser/ParsingException.java index a897cff1677..298b9cbe12c 100644 --- a/sql/server/src/main/java/org/elasticsearch/xpack/sql/parser/ParsingException.java +++ b/sql/server/src/main/java/org/elasticsearch/xpack/sql/parser/ParsingException.java @@ -18,7 +18,7 @@ public class ParsingException extends ClientSqlException { private final int line; private final int charPositionInLine; - public ParsingException(String message, RecognitionException cause, int line, int charPositionInLine) { + public ParsingException(String message, Exception cause, int line, int charPositionInLine) { super(message, cause); this.line = line;