From 6eff6c9ae42c7a4689bd77e2337735c9edf38c54 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Wed, 12 Oct 2022 16:28:41 -0700 Subject: [PATCH] fix json_value sql planning with decimal type, fix vectorized expression math null value handling in default mode (#13214) * fix json_value sql planning with decimal type, fix vectorized expression math null value handling in default mode changes: * json_value 'returning' decimal will now plan to native double typed query instead of ending up with default string typing, allowing decimal vector math expressions to work with this type * vector math expressions now zero out 'null' values even in 'default' mode (druid.generic.useDefaultValueForNull=false) to prevent downstream things that do not check the null vector from producing incorrect results * more better * test and why not vectorize * more test, more fix --- .../math/expr/BinaryMathOperatorExpr.java | 10 +- ...ateDoubleFunctionVectorValueProcessor.java | 94 +++++++++++++++++++ .../BivariateFunctionVectorProcessor.java | 5 +- ...iateLongFunctionVectorValueProcessor.java} | 25 +++-- ...tDoubleInFunctionVectorValueProcessor.java | 12 +-- ...bleLongInFunctionVectorValueProcessor.java | 13 +-- ...DoublesInFunctionVectorValueProcessor.java | 13 +-- ...gDoubleInFunctionVectorValueProcessor.java | 13 +-- ...OutLongInFunctionVectorValueProcessor.java | 12 +-- ...utLongsInFunctionVectorValueProcessor.java | 13 +-- ...tDoubleInFunctionVectorValueProcessor.java | 13 +-- ...bleLongInFunctionVectorValueProcessor.java | 13 +-- ...DoublesInFunctionVectorValueProcessor.java | 13 +-- ...gDoubleInFunctionVectorValueProcessor.java | 13 +-- ...OutLongInFunctionVectorValueProcessor.java | 13 +-- ...utLongsInFunctionVectorValueProcessor.java | 13 +-- ...ateDoubleFunctionVectorValueProcessor.java | 85 +++++++++++++++++ ...iateLongFunctionVectorValueProcessor.java} | 23 +++-- .../expr/vector/VectorMathProcessors.java | 6 +- .../druid/math/expr/VectorExprSanityTest.java | 4 +- .../apache/druid/segment/VirtualColumns.java | 3 +- .../segment/virtual/VirtualColumnsTest.java | 32 +++++++ .../NestedDataOperatorConversions.java | 3 +- .../calcite/CalciteNestedDataQueryTest.java | 58 ++++++++++++ 24 files changed, 355 insertions(+), 147 deletions(-) create mode 100644 core/src/main/java/org/apache/druid/math/expr/vector/BivariateDoubleFunctionVectorValueProcessor.java rename core/src/main/java/org/apache/druid/math/expr/vector/{BivariateFunctionVectorValueProcessor.java => BivariateLongFunctionVectorValueProcessor.java} (80%) create mode 100644 core/src/main/java/org/apache/druid/math/expr/vector/UnivariateDoubleFunctionVectorValueProcessor.java rename core/src/main/java/org/apache/druid/math/expr/vector/{UnivariateFunctionVectorValueProcessor.java => UnivariateLongFunctionVectorValueProcessor.java} (77%) diff --git a/core/src/main/java/org/apache/druid/math/expr/BinaryMathOperatorExpr.java b/core/src/main/java/org/apache/druid/math/expr/BinaryMathOperatorExpr.java index 0b3fb8eeb39..c8a4ce636eb 100644 --- a/core/src/main/java/org/apache/druid/math/expr/BinaryMathOperatorExpr.java +++ b/core/src/main/java/org/apache/druid/math/expr/BinaryMathOperatorExpr.java @@ -112,7 +112,7 @@ final class BinMinusExpr extends BinaryEvalOpExprBase @Override public boolean canVectorize(InputBindingInspector inspector) { - return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); + return inspector.areScalar(left, right) && inspector.canVectorize(left, right); } @Override @@ -151,7 +151,7 @@ final class BinMulExpr extends BinaryEvalOpExprBase @Override public boolean canVectorize(InputBindingInspector inspector) { - return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); + return inspector.areScalar(left, right) && inspector.canVectorize(left, right); } @Override @@ -190,7 +190,7 @@ final class BinDivExpr extends BinaryEvalOpExprBase @Override public boolean canVectorize(InputBindingInspector inspector) { - return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); + return inspector.areScalar(left, right) && inspector.canVectorize(left, right); } @Override @@ -229,7 +229,7 @@ class BinPowExpr extends BinaryEvalOpExprBase @Override public boolean canVectorize(InputBindingInspector inspector) { - return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); + return inspector.areScalar(left, right) && inspector.canVectorize(left, right); } @Override @@ -268,7 +268,7 @@ class BinModuloExpr extends BinaryEvalOpExprBase @Override public boolean canVectorize(InputBindingInspector inspector) { - return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); + return inspector.areScalar(left, right) && inspector.canVectorize(left, right); } @Override diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/BivariateDoubleFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/BivariateDoubleFunctionVectorValueProcessor.java new file mode 100644 index 00000000000..904feb5d705 --- /dev/null +++ b/core/src/main/java/org/apache/druid/math/expr/vector/BivariateDoubleFunctionVectorValueProcessor.java @@ -0,0 +1,94 @@ +/* + * 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.druid.math.expr.vector; + +import org.apache.druid.math.expr.Expr; + +/** + * common machinery for processing two input operators and functions, which should always treat null inputs as null + * output, and are backed by a primitive values instead of an object values (and need to use the null vectors instead of + * checking the vector themselves for nulls) + * + * this one is specialized for producing double[], see {@link BivariateLongFunctionVectorValueProcessor} for + * long[] primitives. + */ +public abstract class BivariateDoubleFunctionVectorValueProcessor + implements ExprVectorProcessor +{ + final ExprVectorProcessor left; + final ExprVectorProcessor right; + final int maxVectorSize; + final boolean[] outNulls; + final double[] outValues; + + protected BivariateDoubleFunctionVectorValueProcessor( + ExprVectorProcessor left, + ExprVectorProcessor right, + int maxVectorSize + ) + { + this.left = left; + this.right = right; + this.maxVectorSize = maxVectorSize; + this.outValues = new double[maxVectorSize]; + this.outNulls = new boolean[maxVectorSize]; + } + + @Override + public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) + { + final ExprEvalVector lhs = left.evalVector(bindings); + final ExprEvalVector rhs = right.evalVector(bindings); + + final int currentSize = bindings.getCurrentVectorSize(); + final boolean[] leftNulls = lhs.getNullVector(); + final boolean[] rightNulls = rhs.getNullVector(); + final boolean hasLeftNulls = leftNulls != null; + final boolean hasRightNulls = rightNulls != null; + final boolean hasNulls = hasLeftNulls || hasRightNulls; + + final TLeftInput leftInput = lhs.values(); + final TRightInput rightInput = rhs.values(); + + if (hasNulls) { + for (int i = 0; i < currentSize; i++) { + outNulls[i] = (hasLeftNulls && leftNulls[i]) || (hasRightNulls && rightNulls[i]); + if (!outNulls[i]) { + processIndex(leftInput, rightInput, i); + } else { + outValues[i] = 0.0; + } + } + } else { + for (int i = 0; i < currentSize; i++) { + processIndex(leftInput, rightInput, i); + outNulls[i] = false; + } + } + return asEval(); + } + + abstract void processIndex(TLeftInput leftInput, TRightInput rightInput, int i); + + final ExprEvalVector asEval() + { + return new ExprEvalDoubleVector(outValues, outNulls); + } +} diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorProcessor.java index 3476cd7e55d..0e5f92bc419 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorProcessor.java @@ -26,8 +26,9 @@ import javax.annotation.Nullable; /** * Basic vector processor that processes 2 inputs and works for both primitive value vectors and object vectors. - * Different from {@link BivariateFunctionVectorValueProcessor} and {@link BivariateFunctionVectorObjectProcessor} in - * that subclasses of this class must check for and directly decide how to handle null values. + * Different from {@link BivariateLongFunctionVectorValueProcessor}, {@link BivariateDoubleFunctionVectorValueProcessor} + * and {@link BivariateFunctionVectorObjectProcessor} in that subclasses of this class must check for and directly + * decide how to handle null values. */ public abstract class BivariateFunctionVectorProcessor implements ExprVectorProcessor diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/BivariateLongFunctionVectorValueProcessor.java similarity index 80% rename from core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorValueProcessor.java rename to core/src/main/java/org/apache/druid/math/expr/vector/BivariateLongFunctionVectorValueProcessor.java index cc8bcc72c95..243b7ae79b5 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/BivariateLongFunctionVectorValueProcessor.java @@ -25,32 +25,34 @@ import org.apache.druid.math.expr.Expr; * common machinery for processing two input operators and functions, which should always treat null inputs as null * output, and are backed by a primitive values instead of an object values (and need to use the null vectors instead of * checking the vector themselves for nulls) + * + * this one is specialized for producing long[], see {@link BivariateDoubleFunctionVectorValueProcessor} for + * double[] primitives. */ -public abstract class BivariateFunctionVectorValueProcessor - implements ExprVectorProcessor +public abstract class BivariateLongFunctionVectorValueProcessor + implements ExprVectorProcessor { final ExprVectorProcessor left; final ExprVectorProcessor right; final int maxVectorSize; final boolean[] outNulls; - final TOutput outValues; + final long[] outValues; - protected BivariateFunctionVectorValueProcessor( + protected BivariateLongFunctionVectorValueProcessor( ExprVectorProcessor left, ExprVectorProcessor right, - int maxVectorSize, - TOutput outValues + int maxVectorSize ) { this.left = left; this.right = right; this.maxVectorSize = maxVectorSize; + this.outValues = new long[maxVectorSize]; this.outNulls = new boolean[maxVectorSize]; - this.outValues = outValues; } @Override - public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) + public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) { final ExprEvalVector lhs = left.evalVector(bindings); final ExprEvalVector rhs = right.evalVector(bindings); @@ -70,6 +72,8 @@ public abstract class BivariateFunctionVectorValueProcessor asEval(); + final ExprEvalVector asEval() + { + return new ExprEvalLongVector(outValues, outNulls); + } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleInFunctionVectorValueProcessor.java index 01d40f2aa63..578daf0e488 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleInFunctionVectorValueProcessor.java @@ -22,14 +22,14 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link UnivariateFunctionVectorValueProcessor} for processing (double[]) -> double[] + * specialized {@link UnivariateDoubleFunctionVectorValueProcessor} for processing (double[]) -> double[] */ public abstract class DoubleOutDoubleInFunctionVectorValueProcessor - extends UnivariateFunctionVectorValueProcessor + extends UnivariateDoubleFunctionVectorValueProcessor { public DoubleOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor processor, int maxVectorSize) { - super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize, new double[maxVectorSize]); + super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize); } public abstract double apply(double input); @@ -45,10 +45,4 @@ public abstract class DoubleOutDoubleInFunctionVectorValueProcessor { outValues[i] = apply(input[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalDoubleVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleLongInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleLongInFunctionVectorValueProcessor.java index 22315772ec6..aac396aa7da 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleLongInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoubleLongInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], long[]) -> double[] + * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (double[], long[]) -> double[] */ public abstract class DoubleOutDoubleLongInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateDoubleFunctionVectorValueProcessor { public DoubleOutDoubleLongInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class DoubleOutDoubleLongInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), - maxVectorSize, - new double[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class DoubleOutDoubleLongInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalDoubleVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoublesInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoublesInFunctionVectorValueProcessor.java index 9a566b67c0b..a3a7d77b1da 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoublesInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutDoublesInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], double[]) -> double[] + * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (double[], double[]) -> double[] */ public abstract class DoubleOutDoublesInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateDoubleFunctionVectorValueProcessor { public DoubleOutDoublesInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class DoubleOutDoublesInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), - maxVectorSize, - new double[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class DoubleOutDoublesInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalDoubleVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongDoubleInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongDoubleInFunctionVectorValueProcessor.java index ee2f41b3f3b..dc62fe1b027 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongDoubleInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongDoubleInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], double[]) -> double[] + * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (long[], double[]) -> double[] */ public abstract class DoubleOutLongDoubleInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateDoubleFunctionVectorValueProcessor { public DoubleOutLongDoubleInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class DoubleOutLongDoubleInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), - maxVectorSize, - new double[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class DoubleOutLongDoubleInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalDoubleVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongInFunctionVectorValueProcessor.java index 1ed8c6ae98f..0b833d02089 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongInFunctionVectorValueProcessor.java @@ -22,14 +22,14 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link UnivariateFunctionVectorValueProcessor} for processing (long[]) -> double[] + * specialized {@link UnivariateDoubleFunctionVectorValueProcessor} for processing (long[]) -> double[] */ public abstract class DoubleOutLongInFunctionVectorValueProcessor - extends UnivariateFunctionVectorValueProcessor + extends UnivariateDoubleFunctionVectorValueProcessor { public DoubleOutLongInFunctionVectorValueProcessor(ExprVectorProcessor processor, int maxVectorSize) { - super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize, new double[maxVectorSize]); + super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize); } public abstract double apply(long input); @@ -45,10 +45,4 @@ public abstract class DoubleOutLongInFunctionVectorValueProcessor { outValues[i] = apply(input[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalDoubleVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongsInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongsInFunctionVectorValueProcessor.java index b08ccdcc791..699f66f53fe 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongsInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/DoubleOutLongsInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], long[]) -> double[] + * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (long[], long[]) -> double[] */ public abstract class DoubleOutLongsInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateDoubleFunctionVectorValueProcessor { public DoubleOutLongsInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class DoubleOutLongsInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), - maxVectorSize, - new double[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class DoubleOutLongsInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalDoubleVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleInFunctionVectorValueProcessor.java index 8d9c9be3e29..0193e24de21 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleInFunctionVectorValueProcessor.java @@ -22,13 +22,14 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link UnivariateFunctionVectorValueProcessor} for processing (long[]) -> long[] + * specialized {@link UnivariateLongFunctionVectorValueProcessor} for processing (long[]) -> long[] */ -public abstract class LongOutDoubleInFunctionVectorValueProcessor extends UnivariateFunctionVectorValueProcessor +public abstract class LongOutDoubleInFunctionVectorValueProcessor + extends UnivariateLongFunctionVectorValueProcessor { public LongOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor processor, int maxVectorSize) { - super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize, new long[maxVectorSize]); + super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize); } public abstract long apply(double input); @@ -44,10 +45,4 @@ public abstract class LongOutDoubleInFunctionVectorValueProcessor extends Univar { outValues[i] = apply(input[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalLongVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleLongInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleLongInFunctionVectorValueProcessor.java index a5dd4024c5c..25e854ee5bd 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleLongInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoubleLongInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], long[]) -> long[] + * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (double[], long[]) -> long[] */ public abstract class LongOutDoubleLongInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateLongFunctionVectorValueProcessor { public LongOutDoubleLongInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class LongOutDoubleLongInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), - maxVectorSize, - new long[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class LongOutDoubleLongInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalLongVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoublesInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoublesInFunctionVectorValueProcessor.java index f5d9fdb7a03..bbd6fa18150 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoublesInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutDoublesInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], double[]) -> long[] + * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (double[], double[]) -> long[] */ public abstract class LongOutDoublesInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateLongFunctionVectorValueProcessor { public LongOutDoublesInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class LongOutDoublesInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), - maxVectorSize, - new long[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class LongOutDoublesInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalLongVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongDoubleInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongDoubleInFunctionVectorValueProcessor.java index 57f17d37d52..d63ffdd0ce5 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongDoubleInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongDoubleInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], double[]) -> long[] + * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (long[], double[]) -> long[] */ public abstract class LongOutLongDoubleInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateLongFunctionVectorValueProcessor { public LongOutLongDoubleInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class LongOutLongDoubleInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), - maxVectorSize, - new long[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class LongOutLongDoubleInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalLongVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongInFunctionVectorValueProcessor.java index 00f43977c13..c13ae84849d 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongInFunctionVectorValueProcessor.java @@ -22,13 +22,14 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link UnivariateFunctionVectorValueProcessor} for processing (long[]) -> long[] + * specialized {@link UnivariateLongFunctionVectorValueProcessor} for processing (long[]) -> long[] */ -public abstract class LongOutLongInFunctionVectorValueProcessor extends UnivariateFunctionVectorValueProcessor +public abstract class LongOutLongInFunctionVectorValueProcessor + extends UnivariateLongFunctionVectorValueProcessor { public LongOutLongInFunctionVectorValueProcessor(ExprVectorProcessor processor, int maxVectorSize) { - super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize, new long[maxVectorSize]); + super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize); } public abstract long apply(long input); @@ -44,10 +45,4 @@ public abstract class LongOutLongInFunctionVectorValueProcessor extends Univaria { outValues[i] = apply(input[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalLongVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongsInFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongsInFunctionVectorValueProcessor.java index b5dbf117f29..9646ddf711a 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongsInFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutLongsInFunctionVectorValueProcessor.java @@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector; import org.apache.druid.math.expr.ExpressionType; /** - * specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], long[]) -> long[] + * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (long[], long[]) -> long[] */ public abstract class LongOutLongsInFunctionVectorValueProcessor - extends BivariateFunctionVectorValueProcessor + extends BivariateLongFunctionVectorValueProcessor { public LongOutLongsInFunctionVectorValueProcessor( ExprVectorProcessor left, @@ -36,8 +36,7 @@ public abstract class LongOutLongsInFunctionVectorValueProcessor super( CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), - maxVectorSize, - new long[maxVectorSize] + maxVectorSize ); } @@ -54,10 +53,4 @@ public abstract class LongOutLongsInFunctionVectorValueProcessor { outValues[i] = apply(leftInput[i], rightInput[i]); } - - @Override - final ExprEvalVector asEval() - { - return new ExprEvalLongVector(outValues, outNulls); - } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/UnivariateDoubleFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/UnivariateDoubleFunctionVectorValueProcessor.java new file mode 100644 index 00000000000..03f9be1eb9a --- /dev/null +++ b/core/src/main/java/org/apache/druid/math/expr/vector/UnivariateDoubleFunctionVectorValueProcessor.java @@ -0,0 +1,85 @@ +/* + * 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.druid.math.expr.vector; + +import org.apache.druid.math.expr.Expr; + +/** + * common machinery for processing single input operators and functions, which should always treat null input as null + * output, and are backed by a primitive value instead of an object value (and need to use the null vector instead of + * checking the vector itself for nulls) + * + * this one is specialized for producing double[], see {@link UnivariateLongFunctionVectorValueProcessor} for + * long[] primitives. + */ +public abstract class UnivariateDoubleFunctionVectorValueProcessor implements ExprVectorProcessor +{ + final ExprVectorProcessor processor; + final int maxVectorSize; + final boolean[] outNulls; + final double[] outValues; + + public UnivariateDoubleFunctionVectorValueProcessor( + ExprVectorProcessor processor, + int maxVectorSize + ) + { + this.processor = processor; + this.maxVectorSize = maxVectorSize; + this.outNulls = new boolean[maxVectorSize]; + this.outValues = new double[maxVectorSize]; + } + + @Override + public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) + { + final ExprEvalVector lhs = processor.evalVector(bindings); + + final int currentSize = bindings.getCurrentVectorSize(); + final boolean[] inputNulls = lhs.getNullVector(); + final boolean hasNulls = inputNulls != null; + + final TInput input = lhs.values(); + + if (hasNulls) { + for (int i = 0; i < currentSize; i++) { + outNulls[i] = inputNulls[i]; + if (!outNulls[i]) { + processIndex(input, i); + } else { + outValues[i] = 0.0; + } + } + } else { + for (int i = 0; i < currentSize; i++) { + outNulls[i] = false; + processIndex(input, i); + } + } + return asEval(); + } + + abstract void processIndex(TInput input, int i); + + final ExprEvalVector asEval() + { + return new ExprEvalDoubleVector(outValues, outNulls); + } +} diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/UnivariateFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/UnivariateLongFunctionVectorValueProcessor.java similarity index 77% rename from core/src/main/java/org/apache/druid/math/expr/vector/UnivariateFunctionVectorValueProcessor.java rename to core/src/main/java/org/apache/druid/math/expr/vector/UnivariateLongFunctionVectorValueProcessor.java index a5293587b4a..86944894508 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/UnivariateFunctionVectorValueProcessor.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/UnivariateLongFunctionVectorValueProcessor.java @@ -25,28 +25,30 @@ import org.apache.druid.math.expr.Expr; * common machinery for processing single input operators and functions, which should always treat null input as null * output, and are backed by a primitive value instead of an object value (and need to use the null vector instead of * checking the vector itself for nulls) + * + * this one is specialized for producing long[], see {@link UnivariateDoubleFunctionVectorValueProcessor} for + * double[] primitives. */ -public abstract class UnivariateFunctionVectorValueProcessor implements ExprVectorProcessor +public abstract class UnivariateLongFunctionVectorValueProcessor implements ExprVectorProcessor { final ExprVectorProcessor processor; final int maxVectorSize; final boolean[] outNulls; - final TOutput outValues; + final long[] outValues; - public UnivariateFunctionVectorValueProcessor( + public UnivariateLongFunctionVectorValueProcessor( ExprVectorProcessor processor, - int maxVectorSize, - TOutput outValues + int maxVectorSize ) { this.processor = processor; this.maxVectorSize = maxVectorSize; this.outNulls = new boolean[maxVectorSize]; - this.outValues = outValues; + this.outValues = new long[maxVectorSize]; } @Override - public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) + public final ExprEvalVector evalVector(Expr.VectorInputBinding bindings) { final ExprEvalVector lhs = processor.evalVector(bindings); @@ -61,6 +63,8 @@ public abstract class UnivariateFunctionVectorValueProcessor im outNulls[i] = inputNulls[i]; if (!outNulls[i]) { processIndex(input, i); + } else { + outValues[i] = 0L; } } } else { @@ -74,5 +78,8 @@ public abstract class UnivariateFunctionVectorValueProcessor im abstract void processIndex(TInput input, int i); - abstract ExprEvalVector asEval(); + final ExprEvalVector asEval() + { + return new ExprEvalLongVector(outValues, outNulls); + } } diff --git a/core/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java b/core/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java index 0d60726203e..4499be2f31f 100644 --- a/core/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java +++ b/core/src/main/java/org/apache/druid/math/expr/vector/VectorMathProcessors.java @@ -158,9 +158,9 @@ public class VectorMathProcessors } } else if (leftType.is(ExprType.STRING)) { if (Types.is(rightType, ExprType.LONG)) { - processor = longOutLongsInProcessor.get(); + processor = doubleOutDoubleLongInProcessor.get(); } else if (Types.is(rightType, ExprType.DOUBLE)) { - processor = doubleOutLongDoubleInProcessor.get(); + processor = doubleOutDoublesInProcessor.get(); } } if (processor == null) { @@ -696,7 +696,7 @@ public class VectorMathProcessors { final ExpressionType leftType = left.getOutputType(inspector); final ExpressionType rightType = right.getOutputType(inspector); - BivariateFunctionVectorValueProcessor processor = null; + ExprVectorProcessor processor = null; if ((Types.is(leftType, ExprType.LONG) && Types.isNullOr(rightType, ExprType.LONG)) || (leftType == null && Types.is(rightType, ExprType.LONG))) { processor = new DoubleOutLongsInFunctionVectorValueProcessor( diff --git a/core/src/test/java/org/apache/druid/math/expr/VectorExprSanityTest.java b/core/src/test/java/org/apache/druid/math/expr/VectorExprSanityTest.java index 1362d3f3487..4819661f592 100644 --- a/core/src/test/java/org/apache/druid/math/expr/VectorExprSanityTest.java +++ b/core/src/test/java/org/apache/druid/math/expr/VectorExprSanityTest.java @@ -88,7 +88,7 @@ public class VectorExprSanityTest extends InitializedNullHandlingTest @Test public void testBinaryMathOperators() { - final String[] columns = new String[]{"d1", "d2", "l1", "l2", "1", "1.0", "nonexistent", "null"}; + final String[] columns = new String[]{"d1", "d2", "l1", "l2", "1", "1.0", "nonexistent", "null", "s1"}; final String[] columns2 = new String[]{"d1", "d2", "l1", "l2", "1", "1.0"}; final String[][] templateInputs = makeTemplateArgs(columns, columns2); final String[] templates = @@ -305,7 +305,7 @@ public class VectorExprSanityTest extends InitializedNullHandlingTest ExprEvalVector vectorEval = parsed.buildVectorized(bindings.rhs).evalVector(bindings.rhs); // 'null' expressions can have an output type of null, but still evaluate in default mode, so skip type checks if (outputType != null) { - Assert.assertEquals(outputType, vectorEval.getType()); + Assert.assertEquals(expr, outputType, vectorEval.getType()); } for (int i = 0; i < VECTOR_SIZE; i++) { ExprEval eval = parsed.eval(bindings.lhs[i]); diff --git a/processing/src/main/java/org/apache/druid/segment/VirtualColumns.java b/processing/src/main/java/org/apache/druid/segment/VirtualColumns.java index c3815286d90..823d15ff759 100644 --- a/processing/src/main/java/org/apache/druid/segment/VirtualColumns.java +++ b/processing/src/main/java/org/apache/druid/segment/VirtualColumns.java @@ -247,7 +247,8 @@ public class VirtualColumns implements Cacheable public boolean canVectorize(ColumnInspector columnInspector) { - return virtualColumns.stream().allMatch(virtualColumn -> virtualColumn.canVectorize(columnInspector)); + final ColumnInspector inspector = wrapInspector(columnInspector); + return virtualColumns.stream().allMatch(virtualColumn -> virtualColumn.canVectorize(inspector)); } /** diff --git a/processing/src/test/java/org/apache/druid/segment/virtual/VirtualColumnsTest.java b/processing/src/test/java/org/apache/druid/segment/virtual/VirtualColumnsTest.java index b648ecc377c..4bbc23068f6 100644 --- a/processing/src/test/java/org/apache/druid/segment/virtual/VirtualColumnsTest.java +++ b/processing/src/test/java/org/apache/druid/segment/virtual/VirtualColumnsTest.java @@ -51,6 +51,7 @@ import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.ValueType; import org.apache.druid.segment.data.IndexedInts; import org.apache.druid.segment.data.ZeroIndexedInts; +import org.apache.druid.segment.nested.NestedDataComplexTypeSerde; import org.apache.druid.testing.InitializedNullHandlingTest; import org.junit.Assert; import org.junit.Rule; @@ -471,6 +472,37 @@ public class VirtualColumnsTest extends InitializedNullHandlingTest Assert.assertTrue(virtualColumns.exists("v2")); } + @Test + public void testCompositeVirtualColumnsCapabilitiesHasAccessToOtherVirtualColumns() + { + final ColumnInspector baseInspector = new ColumnInspector() + { + @Nullable + @Override + public ColumnCapabilities getColumnCapabilities(String column) + { + if ("x".equals(column)) { + return ColumnCapabilitiesImpl.createSimpleNumericColumnCapabilities(ColumnType.LONG); + } + if ("n".equals(column)) { + return ColumnCapabilitiesImpl.createDefault().setType(NestedDataComplexTypeSerde.TYPE); + } + return null; + } + }; + final NestedFieldVirtualColumn v0 = new NestedFieldVirtualColumn("n", "$.x", "v0", ColumnType.STRING); + final NestedFieldVirtualColumn v1 = new NestedFieldVirtualColumn("n", "$.y", "v1", ColumnType.LONG); + final ExpressionVirtualColumn expr1 = new ExpressionVirtualColumn("v2", "v0 * v1", null, TestExprMacroTable.INSTANCE); + final ExpressionVirtualColumn expr2 = new ExpressionVirtualColumn("v3", "v0 * x", null, TestExprMacroTable.INSTANCE); + final VirtualColumns virtualColumns = VirtualColumns.create(ImmutableList.of(v0, v1, expr1, expr2)); + + Assert.assertEquals(ColumnType.STRING, virtualColumns.getColumnCapabilities(baseInspector, "v0").toColumnType()); + Assert.assertEquals(ColumnType.LONG, virtualColumns.getColumnCapabilities(baseInspector, "v1").toColumnType()); + Assert.assertEquals(ColumnType.DOUBLE, virtualColumns.getColumnCapabilities(baseInspector, "v2").toColumnType()); + Assert.assertEquals(ColumnType.DOUBLE, virtualColumns.getColumnCapabilities(baseInspector, "v3").toColumnType()); + Assert.assertTrue(virtualColumns.canVectorize(baseInspector)); + } + private VirtualColumns makeVirtualColumns() { final ExpressionVirtualColumn expr = new ExpressionVirtualColumn( diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java index f6d2af5e831..66a950cb277 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java @@ -276,7 +276,8 @@ public class NestedDataOperatorConversions call.operand(0), call.operand(1) ); - } else if (SqlTypeName.APPROX_TYPES.contains(sqlType.getSqlTypeName())) { + } else if (SqlTypeName.DECIMAL.equals(sqlType.getSqlTypeName()) || + SqlTypeName.APPROX_TYPES.contains(sqlType.getSqlTypeName())) { rewrite = JsonValueDoubleOperatorConversion.FUNCTION.createCall( SqlParserPos.ZERO, call.operand(0), diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java index e95ba656437..acb41e516b9 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java @@ -1951,6 +1951,35 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest ); } + @Test + public void testReturningAndSumPathWithMaths() + { + testQuery( + "SELECT " + + "SUM(JSON_VALUE(nest, '$.x' RETURNING BIGINT) / 100) " + + "FROM druid.nested", + ImmutableList.of( + Druids.newTimeseriesQueryBuilder() + .dataSource(DATA_SOURCE) + .intervals(querySegmentSpec(Filtration.eternity())) + .granularity(Granularities.ALL) + .virtualColumns( + expressionVirtualColumn("v0", "(\"v1\" / 100)", ColumnType.LONG), + new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.LONG) + ) + .aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0"))) + .context(QUERY_CONTEXT_DEFAULT) + .build() + ), + ImmutableList.of( + new Object[]{4L} + ), + RowSignature.builder() + .add("EXPR$0", ColumnType.LONG) + .build() + ); + } + @Test public void testReturningAndSumPathDouble() { @@ -2003,6 +2032,35 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest ); } + @Test + public void testReturningAndSumPathDecimalWithMaths() + { + testQuery( + "SELECT " + + "SUM(JSON_VALUE(nest, '$.x' RETURNING DECIMAL) / 100.0) " + + "FROM druid.nested", + ImmutableList.of( + Druids.newTimeseriesQueryBuilder() + .dataSource(DATA_SOURCE) + .intervals(querySegmentSpec(Filtration.eternity())) + .granularity(Granularities.ALL) + .virtualColumns( + expressionVirtualColumn("v0", "(\"v1\" / 100.0)", ColumnType.DOUBLE), + new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.DOUBLE) + ) + .aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "v0"))) + .context(QUERY_CONTEXT_DEFAULT) + .build() + ), + ImmutableList.of( + new Object[]{4.0} + ), + RowSignature.builder() + .add("EXPR$0", ColumnType.DOUBLE) + .build() + ); + } + @Test public void testReturningAndSumPathStrings() {