imay closed pull request #255: Simplify constant Expr
URL: https://github.com/apache/incubator-doris/pull/255
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/fe/src/main/java/org/apache/doris/analysis/Analyzer.java
b/fe/src/main/java/org/apache/doris/analysis/Analyzer.java
index 23ee0f0f..a3941d26 100644
--- a/fe/src/main/java/org/apache/doris/analysis/Analyzer.java
+++ b/fe/src/main/java/org/apache/doris/analysis/Analyzer.java
@@ -37,6 +37,7 @@
import org.apache.doris.rewrite.BetweenToCompoundRule;
import org.apache.doris.rewrite.ExprRewriteRule;
import org.apache.doris.rewrite.ExprRewriter;
+import org.apache.doris.rewrite.FoldConstantsRule;
import org.apache.doris.rewrite.NormalizeBinaryPredicatesRule;
import org.apache.doris.thrift.TQueryGlobals;
@@ -237,6 +238,7 @@ public GlobalState(Catalog catalog, ConnectContext context)
{
// Binary predicates must be rewritten to a canonical form for
both Kudu predicate
// pushdown and Parquet row group pruning based on min/max
statistics.
rules.add(NormalizeBinaryPredicatesRule.INSTANCE);
+ rules.add(FoldConstantsRule.INSTANCE);
exprRewriter_ = new ExprRewriter(rules);
}
};
diff --git a/fe/src/main/java/org/apache/doris/analysis/Expr.java
b/fe/src/main/java/org/apache/doris/analysis/Expr.java
index 27281521..5d38b61c 100644
--- a/fe/src/main/java/org/apache/doris/analysis/Expr.java
+++ b/fe/src/main/java/org/apache/doris/analysis/Expr.java
@@ -396,6 +396,19 @@ protected void computeNumDistinctValues() {
return childTypes;
}
+ public List<Expr> getChildrenWithoutCast() {
+ List<Expr> result = new ArrayList<>();
+ for (int i = 0; i < children.size(); ++i) {
+ if (children.get(i) instanceof CastExpr) {
+ CastExpr castExpr = (CastExpr) children.get(i);
+ result.add(castExpr.getChild(0));
+ } else {
+ result.add(children.get(i));
+ }
+ }
+ return result;
+ }
+
/**
* Helper function: analyze list of exprs
*
diff --git a/fe/src/main/java/org/apache/doris/catalog/ScalarType.java
b/fe/src/main/java/org/apache/doris/catalog/ScalarType.java
index c53f8f5a..0b79a0a4 100644
--- a/fe/src/main/java/org/apache/doris/catalog/ScalarType.java
+++ b/fe/src/main/java/org/apache/doris/catalog/ScalarType.java
@@ -118,6 +118,47 @@ public static ScalarType createType(PrimitiveType type) {
}
}
+ public static ScalarType createType(String type) {
+ switch (type) {
+ case "INVALID_TYPE":
+ return INVALID;
+ case "NULL_TYPE":
+ return NULL;
+ case "BOOLEAN":
+ return BOOLEAN;
+ case "SMALLINT":
+ return SMALLINT;
+ case "TINYINT":
+ return TINYINT;
+ case "INT":
+ return INT;
+ case "BIGINT":
+ return BIGINT;
+ case "FLOAT":
+ return FLOAT;
+ case "DOUBLE":
+ return DOUBLE;
+ case "CHAR":
+ return CHAR;
+ case "VARCHAR":
+ return createVarcharType();
+ case "HLL":
+ return createHllType();
+ case "DATE":
+ return DATE;
+ case "DATETIME":
+ return DATETIME;
+ case "DECIMAL":
+ return (ScalarType) createDecimalType();
+ case "LARGEINT":
+ return LARGEINT;
+ default:
+ LOG.warn("type={}", type);
+ Preconditions.checkState(false);
+ return NULL;
+ }
+ }
+
public static ScalarType createCharType(int len) {
ScalarType type = new ScalarType(PrimitiveType.CHAR);
type.len = len;
diff --git a/fe/src/main/java/org/apache/doris/rewrite/FEFunction.java
b/fe/src/main/java/org/apache/doris/rewrite/FEFunction.java
new file mode 100644
index 00000000..d3e4c3fe
--- /dev/null
+++ b/fe/src/main/java/org/apache/doris/rewrite/FEFunction.java
@@ -0,0 +1,33 @@
+// 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.doris.rewrite;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface FEFunction {
+ String name();
+
+ String[] argTypes();
+
+ String returnType();
+}
\ No newline at end of file
diff --git a/fe/src/main/java/org/apache/doris/rewrite/FEFunctions.java
b/fe/src/main/java/org/apache/doris/rewrite/FEFunctions.java
new file mode 100644
index 00000000..f816cc18
--- /dev/null
+++ b/fe/src/main/java/org/apache/doris/rewrite/FEFunctions.java
@@ -0,0 +1,259 @@
+// 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.doris.rewrite;
+
+import org.apache.commons.lang.time.DateFormatUtils;
+import org.apache.commons.lang.time.DateUtils;
+import org.apache.doris.analysis.DateLiteral;
+import org.apache.doris.analysis.DecimalLiteral;
+import org.apache.doris.analysis.FloatLiteral;
+import org.apache.doris.analysis.IntLiteral;
+import org.apache.doris.analysis.LargeIntLiteral;
+import org.apache.doris.analysis.LiteralExpr;
+import org.apache.doris.analysis.StringLiteral;
+import org.apache.doris.catalog.Type;
+import org.apache.doris.common.AnalysisException;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * compute functions in FE.
+ *
+ * when you add a new function, please ensure the name, argTypes , returnType
and compute logic are consistent with BE's function
+ */
+public class FEFunctions {
+ /**
+ * date and time function
+ */
+
+ @FEFunction(name = "datediff", argTypes = { "DATETIME", "DATETIME" },
returnType = "INT")
+ public static IntLiteral dateDiff(LiteralExpr first, LiteralExpr second)
throws AnalysisException {
+ long diff = getTime(first) - getTime(second);
+ long datediff = diff / 1000 / 60 / 60 / 24;
+ return new IntLiteral(datediff, Type.INT);
+ }
+
+ @FEFunction(name = "date_add", argTypes = { "DATETIME", "INT" },
returnType = "DATETIME")
+ public static DateLiteral dateAdd(LiteralExpr date, LiteralExpr day)
throws AnalysisException {
+ Date d = new Date(getTime(date));
+ d = DateUtils.addDays(d, (int) day.getLongValue());
+ return new DateLiteral(DateFormatUtils.format(d, "yyyy-MM-dd
HH:mm:ss"), Type.DATETIME);
+ }
+
+ @FEFunction(name = "date_format", argTypes = { "DATETIME", "VARCHAR" },
returnType = "VARCHAR")
+ public static StringLiteral dateFormat(LiteralExpr date, StringLiteral
fmtLiteral) throws AnalysisException {
+ String result = DateFormatUtils.format(new Date(getTime(date)),
fmtLiteral.getStringValue());
+ return new StringLiteral(result);
+ }
+
+ @FEFunction(name = "date_sub", argTypes = { "DATETIME", "INT" },
returnType = "DATETIME")
+ public static DateLiteral dateSub(LiteralExpr date, LiteralExpr day)
throws AnalysisException {
+ Date d = new Date(getTime(date));
+ d = DateUtils.addDays(d, -(int) day.getLongValue());
+ return new DateLiteral(DateFormatUtils.format(d, "yyyy-MM-dd
HH:mm:ss"), Type.DATETIME);
+ }
+
+
+ @FEFunction(name = "year", argTypes = { "DATETIME" }, returnType = "INT")
+ public static IntLiteral year(LiteralExpr arg) throws AnalysisException {
+ long timestamp = getTime(arg);
+ Calendar instance = Calendar.getInstance();
+ instance.setTimeInMillis(timestamp);
+ return new IntLiteral(instance.get(Calendar.YEAR), Type.INT);
+ }
+
+ @FEFunction(name = "month", argTypes = { "DATETIME" }, returnType = "INT")
+ public static IntLiteral month(LiteralExpr arg) throws AnalysisException {
+ long timestamp = getTime(arg);
+ Calendar instance = Calendar.getInstance();
+ instance.setTimeInMillis(timestamp);
+ return new IntLiteral(instance.get(Calendar.MONTH) + 1, Type.INT);
+ }
+
+ @FEFunction(name = "day", argTypes = { "DATETIME" }, returnType = "INT")
+ public static IntLiteral day(LiteralExpr arg) throws AnalysisException {
+ long timestamp = getTime(arg);
+ Calendar instance = Calendar.getInstance();
+ instance.setTimeInMillis(timestamp);
+ return new IntLiteral(instance.get(Calendar.DAY_OF_MONTH), Type.INT);
+ }
+
+ private static long getTime(LiteralExpr expr) throws AnalysisException {
+ try {
+ String[] parsePatterns = { "yyyyMMdd", "yyyy-MM-dd", "yyyy-MM-dd
HH:mm:ss" };
+ long time;
+ if (expr instanceof DateLiteral) {
+ time = expr.getLongValue();
+ } else {
+ time = DateUtils.parseDate(expr.getStringValue(),
parsePatterns).getTime();
+ }
+ return time;
+ } catch (ParseException e) {
+ throw new AnalysisException(e.getLocalizedMessage());
+ }
+ }
+
+ /**
+
------------------------------------------------------------------------------
+ */
+
+
+ /**
+ * Cast
+ */
+
+ @FEFunction(name = "casttoint", argTypes = { "VARCHAR"}, returnType =
"INT")
+ public static IntLiteral castToInt(StringLiteral expr) throws
AnalysisException {
+ return new IntLiteral(expr.getLongValue(), Type.INT);
+ }
+
+
+ /**
+
------------------------------------------------------------------------------
+ */
+
+ /**
+ * Math function
+ */
+
+ @FEFunction(name = "floor", argTypes = { "DOUBLE"}, returnType = "BIGINT")
+ public static IntLiteral floor(LiteralExpr expr) throws AnalysisException {
+ long result = (long)Math.floor(expr.getDoubleValue());
+ return new IntLiteral(result, Type.BIGINT);
+ }
+
+ /**
+
------------------------------------------------------------------------------
+ */
+
+ /**
+ * Arithmetic function
+ */
+
+ @FEFunction(name = "add", argTypes = { "BIGINT", "BIGINT" }, returnType =
"BIGINT")
+ public static IntLiteral addInt(LiteralExpr first, LiteralExpr second)
throws AnalysisException {
+ long result = Math.addExact(first.getLongValue(),
second.getLongValue());
+ return new IntLiteral(result, Type.BIGINT);
+ }
+
+ @FEFunction(name = "add", argTypes = { "DOUBLE", "DOUBLE" }, returnType =
"DOUBLE")
+ public static FloatLiteral addDouble(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ double result = first.getDoubleValue() + second.getDoubleValue();
+ return new FloatLiteral(result, Type.DOUBLE);
+ }
+
+ @FEFunction(name = "add", argTypes = { "DECIMAL", "DECIMAL" }, returnType
= "DECIMAL")
+ public static DecimalLiteral addDecimal(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ BigDecimal left = new BigDecimal(first.getStringValue());
+ BigDecimal right = new BigDecimal(second.getStringValue());
+
+ BigDecimal result = left.add(right);
+ return new DecimalLiteral(result);
+ }
+
+ @FEFunction(name = "add", argTypes = { "LARGEINT", "LARGEINT" },
returnType = "LARGEINT")
+ public static LargeIntLiteral addBigInt(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ BigInteger left = new BigInteger(first.getStringValue());
+ BigInteger right = new BigInteger(second.getStringValue());
+
+ BigInteger result = left.add(right);
+ return new LargeIntLiteral(result.toString());
+ }
+
+ @FEFunction(name = "subtract", argTypes = { "BIGINT", "BIGINT" },
returnType = "BIGINT")
+ public static IntLiteral subtractInt(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ long result = Math.subtractExact(first.getLongValue(),
second.getLongValue());
+ return new IntLiteral(result, Type.BIGINT);
+ }
+
+ @FEFunction(name = "subtract", argTypes = { "DOUBLE", "DOUBLE" },
returnType = "DOUBLE")
+ public static FloatLiteral subtractDouble(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ double result = first.getDoubleValue() - second.getDoubleValue();
+ return new FloatLiteral(result, Type.DOUBLE);
+ }
+
+ @FEFunction(name = "subtract", argTypes = { "DECIMAL", "DECIMAL" },
returnType = "DECIMAL")
+ public static DecimalLiteral subtractDecimal(LiteralExpr first,
LiteralExpr second) throws AnalysisException {
+ BigDecimal left = new BigDecimal(first.getStringValue());
+ BigDecimal right = new BigDecimal(second.getStringValue());
+
+ BigDecimal result = left.subtract(right);
+ return new DecimalLiteral(result);
+ }
+
+ @FEFunction(name = "subtract", argTypes = { "LARGEINT", "LARGEINT" },
returnType = "LARGEINT")
+ public static LargeIntLiteral subtractBigInt(LiteralExpr first,
LiteralExpr second) throws AnalysisException {
+ BigInteger left = new BigInteger(first.getStringValue());
+ BigInteger right = new BigInteger(second.getStringValue());
+
+ BigInteger result = left.subtract(right);
+ return new LargeIntLiteral(result.toString());
+ }
+
+ @FEFunction(name = "multiply", argTypes = { "BIGINT", "BIGINT" },
returnType = "BIGINT")
+ public static IntLiteral multiplyInt(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ long left = first.getLongValue();
+ long right = second.getLongValue();
+
+ long result = Math.multiplyExact(left, right);
+ return new IntLiteral(result, Type.BIGINT);
+ }
+
+ @FEFunction(name = "multiply", argTypes = { "DOUBLE", "DOUBLE" },
returnType = "DOUBLE")
+ public static FloatLiteral multiplyDouble(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ double result = first.getDoubleValue() * second.getDoubleValue();
+ return new FloatLiteral(result, Type.DOUBLE);
+ }
+
+ @FEFunction(name = "multiply", argTypes = { "DECIMAL", "DECIMAL" },
returnType = "DECIMAL")
+ public static DecimalLiteral multiplyDecimal(LiteralExpr first,
LiteralExpr second) throws AnalysisException {
+ BigDecimal left = new BigDecimal(first.getStringValue());
+ BigDecimal right = new BigDecimal(second.getStringValue());
+
+ BigDecimal result = left.multiply(right);
+ return new DecimalLiteral(result);
+ }
+
+ @FEFunction(name = "multiply", argTypes = { "LARGEINT", "LARGEINT" },
returnType = "LARGEINT")
+ public static LargeIntLiteral multiplyBigInt(LiteralExpr first,
LiteralExpr second) throws AnalysisException {
+ BigInteger left = new BigInteger(first.getStringValue());
+ BigInteger right = new BigInteger(second.getStringValue());
+
+ BigInteger result = left.multiply(right);
+ return new LargeIntLiteral(result.toString());
+ }
+
+ @FEFunction(name = "divide", argTypes = { "DOUBLE", "DOUBLE" }, returnType
= "DOUBLE")
+ public static FloatLiteral divideDouble(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ double result = first.getDoubleValue() / second.getDoubleValue();
+ return new FloatLiteral(result, Type.DOUBLE);
+ }
+
+ @FEFunction(name = "divide", argTypes = { "DECIMAL", "DECIMAL" },
returnType = "DECIMAL")
+ public static DecimalLiteral divideDecimal(LiteralExpr first, LiteralExpr
second) throws AnalysisException {
+ BigDecimal left = new BigDecimal(first.getStringValue());
+ BigDecimal right = new BigDecimal(second.getStringValue());
+
+ BigDecimal result = left.divide(right);
+ return new DecimalLiteral(result);
+ }
+}
diff --git a/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java
b/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java
new file mode 100644
index 00000000..201e2204
--- /dev/null
+++ b/fe/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java
@@ -0,0 +1,239 @@
+// 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.doris.rewrite;
+
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import org.apache.doris.analysis.Analyzer;
+import org.apache.doris.analysis.ArithmeticExpr;
+import org.apache.doris.analysis.CastExpr;
+import org.apache.doris.analysis.Expr;
+import org.apache.doris.analysis.FunctionCallExpr;
+import org.apache.doris.analysis.LiteralExpr;
+import org.apache.doris.analysis.NullLiteral;
+import org.apache.doris.catalog.Function;
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.catalog.Type;
+import org.apache.doris.common.AnalysisException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * This rule replaces a constant Expr with its equivalent LiteralExpr by
evaluating the
+ * Expr in the BE. Exprs that are already LiteralExprs are not changed.
+ *
+ * TODO: Expressions fed into this rule are currently not required to be
analyzed
+ * in order to support constant folding in expressions that contain unresolved
+ * references to select-list aliases (such expressions cannot be analyzed).
+ * The cross-dependencies between rule transformations and analysis are vague
at the
+ * moment and make rule application overly complicated.
+ *
+ * Examples:
+ * 1 + 1 + 1 --> 3
+ * toupper('abc') --> 'ABC'
+ * cast('2016-11-09' as timestamp) --> TIMESTAMP '2016-11-09 00:00:00'
+ */
+public class FoldConstantsRule implements ExprRewriteRule {
+ public static ExprRewriteRule INSTANCE = new FoldConstantsRule();
+
+ private Multimap<String, FEFunctionInvoker> functions =
ArrayListMultimap.create();
+
+ @Override
+ public Expr apply(Expr expr, Analyzer analyzer) throws AnalysisException {
+ if (functions.isEmpty()) {
+ registerFunctions();
+ }
+
+ // Avoid calling Expr.isConstant() because that would lead to repeated
traversals
+ // of the Expr tree. Assumes the bottom-up application of this rule.
Constant
+ // children should have been folded at this point.
+ for (Expr child : expr.getChildren()) {
+ if (!child.isLiteral() && !(child instanceof CastExpr)) {
+ return expr;
+ }
+ }
+
+ if (expr.isLiteral() || !expr.isConstant()) {
+ return expr;
+ }
+
+ // Do not constant fold cast(null as dataType) because we cannot
preserve the
+ // cast-to-types and that can lead to query failures, e.g., CTAS
+ if (expr instanceof CastExpr) {
+ CastExpr castExpr = (CastExpr) expr;
+ if (castExpr.getChild(0) instanceof NullLiteral) {
+ return expr;
+ }
+ }
+ // Analyze constant exprs, if necessary. Note that the 'expr' may
become non-constant
+ // after analysis (e.g., aggregate functions).
+ if (!expr.isAnalyzed()) {
+ expr.analyze(analyzer);
+ if (!expr.isConstant()) {
+ return expr;
+ }
+ }
+ return simplify(expr);
+ }
+
+ private Expr simplify(Expr constExpr) throws AnalysisException {
+ if (constExpr instanceof ArithmeticExpr
+ || constExpr instanceof FunctionCallExpr
+ || constExpr instanceof CastExpr) {
+ Function fn = constExpr.getFn();
+ List<ScalarType> argTypes = new ArrayList<>();
+ for (Type type : fn.getArgs()) {
+ argTypes.add((ScalarType) type);
+ }
+ FEFunctionSignature signature = new
FEFunctionSignature(fn.functionName(),
+ argTypes.toArray(new ScalarType[argTypes.size()]),
(ScalarType) fn.getReturnType());
+ FEFunctionInvoker invoker = getFunction(signature);
+ if (invoker != null) {
+ try {
+ return invoker.invoke(constExpr.getChildrenWithoutCast());
+ } catch (AnalysisException e) {
+ return constExpr;
+ }
+ }
+ }
+ return constExpr;
+ }
+
+ private FEFunctionInvoker getFunction(FEFunctionSignature signature) {
+ Collection<FEFunctionInvoker> functionInvokers =
functions.get(signature.getName());
+
+ if (functionInvokers == null) {
+ return null;
+ }
+
+ for (FEFunctionInvoker invoker : functionInvokers) {
+ if
(!invoker.getSignature().returnType.equals(signature.getReturnType())) {
+ continue;
+ }
+
+ ScalarType[] argTypes1 = invoker.getSignature().getArgTypes();
+ ScalarType[] argTypes2 = signature.getArgTypes();
+
+ if (!Arrays.equals(argTypes1, argTypes2)) {
+ continue;
+ }
+
+ return invoker;
+ }
+ return null;
+ }
+
+ private synchronized void registerFunctions() {
+ // double checked locking pattern
+ // functions only need to init once
+ if (!functions.isEmpty()) {
+ return;
+ }
+
+ Class clazz = FEFunctions.class;
+ for (Method method : clazz.getDeclaredMethods()) {
+ FEFunction annotation = method.getAnnotation(FEFunction.class);
+ if (annotation != null) {
+ String name = annotation.name();
+ ScalarType returnType =
ScalarType.createType(annotation.returnType());
+ List<ScalarType> argTypes = new ArrayList<>();
+ for (String type : annotation.argTypes()) {
+ argTypes.add(ScalarType.createType(type));
+ }
+
+ FEFunctionSignature signature = new FEFunctionSignature(name,
+ argTypes.toArray(new ScalarType[argTypes.size()]),
returnType);
+ functions.put(name, new FEFunctionInvoker(method, signature));
+ }
+ }
+ }
+
+ public static class FEFunctionInvoker {
+ private final Method method;
+ private final FEFunctionSignature signature;
+
+ public FEFunctionInvoker(Method method, FEFunctionSignature signature)
{
+ this.method = method;
+ this.signature = signature;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ public FEFunctionSignature getSignature() {
+ return signature;
+ }
+
+ public LiteralExpr invoke(List<Expr> args) throws AnalysisException {
+ try {
+ return (LiteralExpr) method.invoke(null, args.toArray());
+ } catch (InvocationTargetException | IllegalAccessException e) {
+ throw new AnalysisException(e.getLocalizedMessage());
+ }
+ }
+
+ }
+
+ public static class FEFunctionSignature {
+ private final String name;
+ private final ScalarType[] argTypes;
+ private final ScalarType returnType;
+
+ public FEFunctionSignature(String name, ScalarType[] argTypes,
ScalarType returnType) {
+ this.name = name;
+ this.argTypes = argTypes;
+ this.returnType = returnType;
+ }
+
+ public ScalarType[] getArgTypes() {
+ return argTypes;
+ }
+
+ public ScalarType getReturnType() {
+ return returnType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ FEFunctionSignature signature = (FEFunctionSignature) o;
+ return Objects.equals(name, signature.name) &&
Arrays.equals(argTypes, signature.argTypes)
+ && Objects.equals(returnType, signature.returnType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, argTypes, returnType);
+ }
+ }
+}
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]