You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by cw...@apache.org on 2022/10/12 23:28:51 UTC

[druid] branch master updated: fix json_value sql planning with decimal type, fix vectorized expression math null value handling in default mode (#13214)

This is an automated email from the ASF dual-hosted git repository.

cwylie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 6eff6c9ae4 fix json_value sql planning with decimal type, fix vectorized expression math null value handling in default mode (#13214)
6eff6c9ae4 is described below

commit 6eff6c9ae42c7a4689bd77e2337735c9edf38c54
Author: Clint Wylie <cw...@apache.org>
AuthorDate: Wed Oct 12 16:28:41 2022 -0700

    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
---
 .../druid/math/expr/BinaryMathOperatorExpr.java    | 10 ++--
 ...variateDoubleFunctionVectorValueProcessor.java} | 25 ++++++----
 .../vector/BivariateFunctionVectorProcessor.java   |  5 +-
 ...BivariateLongFunctionVectorValueProcessor.java} | 25 ++++++----
 ...bleOutDoubleInFunctionVectorValueProcessor.java | 12 ++---
 ...utDoubleLongInFunctionVectorValueProcessor.java | 13 ++---
 ...leOutDoublesInFunctionVectorValueProcessor.java | 13 ++---
 ...utLongDoubleInFunctionVectorValueProcessor.java | 13 ++---
 ...oubleOutLongInFunctionVectorValueProcessor.java | 12 ++---
 ...ubleOutLongsInFunctionVectorValueProcessor.java | 13 ++---
 ...ongOutDoubleInFunctionVectorValueProcessor.java | 13 ++---
 ...utDoubleLongInFunctionVectorValueProcessor.java | 13 ++---
 ...ngOutDoublesInFunctionVectorValueProcessor.java | 13 ++---
 ...utLongDoubleInFunctionVectorValueProcessor.java | 13 ++---
 .../LongOutLongInFunctionVectorValueProcessor.java | 13 ++---
 ...LongOutLongsInFunctionVectorValueProcessor.java | 13 ++---
 ...variateDoubleFunctionVectorValueProcessor.java} | 23 ++++++---
 ...nivariateLongFunctionVectorValueProcessor.java} | 23 ++++++---
 .../math/expr/vector/VectorMathProcessors.java     |  6 +--
 .../druid/math/expr/VectorExprSanityTest.java      |  4 +-
 .../org/apache/druid/segment/VirtualColumns.java   |  3 +-
 .../druid/segment/virtual/VirtualColumnsTest.java  | 32 ++++++++++++
 .../builtin/NestedDataOperatorConversions.java     |  3 +-
 .../sql/calcite/CalciteNestedDataQueryTest.java    | 58 ++++++++++++++++++++++
 24 files changed, 207 insertions(+), 164 deletions(-)

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 0b3fb8eeb3..c8a4ce636e 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/BivariateFunctionVectorValueProcessor.java b/core/src/main/java/org/apache/druid/math/expr/vector/BivariateDoubleFunctionVectorValueProcessor.java
similarity index 80%
copy from core/src/main/java/org/apache/druid/math/expr/vector/BivariateFunctionVectorValueProcessor.java
copy to core/src/main/java/org/apache/druid/math/expr/vector/BivariateDoubleFunctionVectorValueProcessor.java
index cc8bcc72c9..904feb5d70 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/BivariateDoubleFunctionVectorValueProcessor.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 double[], see {@link BivariateLongFunctionVectorValueProcessor} for
+ * long[] primitives.
  */
-public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightInput, TOutput>
-    implements ExprVectorProcessor<TOutput>
+public abstract class BivariateDoubleFunctionVectorValueProcessor<TLeftInput, TRightInput>
+    implements ExprVectorProcessor<double[]>
 {
   final ExprVectorProcessor<TLeftInput> left;
   final ExprVectorProcessor<TRightInput> right;
   final int maxVectorSize;
   final boolean[] outNulls;
-  final TOutput outValues;
+  final double[] outValues;
 
-  protected BivariateFunctionVectorValueProcessor(
+  protected BivariateDoubleFunctionVectorValueProcessor(
       ExprVectorProcessor<TLeftInput> left,
       ExprVectorProcessor<TRightInput> right,
-      int maxVectorSize,
-      TOutput outValues
+      int maxVectorSize
   )
   {
     this.left = left;
     this.right = right;
     this.maxVectorSize = maxVectorSize;
+    this.outValues = new double[maxVectorSize];
     this.outNulls = new boolean[maxVectorSize];
-    this.outValues = outValues;
   }
 
   @Override
-  public final ExprEvalVector<TOutput> evalVector(Expr.VectorInputBinding bindings)
+  public final ExprEvalVector<double[]> evalVector(Expr.VectorInputBinding bindings)
   {
     final ExprEvalVector<TLeftInput> lhs = left.evalVector(bindings);
     final ExprEvalVector<TRightInput> rhs = right.evalVector(bindings);
@@ -70,6 +72,8 @@ public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightIn
         outNulls[i] = (hasLeftNulls && leftNulls[i]) || (hasRightNulls && rightNulls[i]);
         if (!outNulls[i]) {
           processIndex(leftInput, rightInput, i);
+        } else {
+          outValues[i] = 0.0;
         }
       }
     } else {
@@ -83,5 +87,8 @@ public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightIn
 
   abstract void processIndex(TLeftInput leftInput, TRightInput rightInput, int i);
 
-  abstract ExprEvalVector<TOutput> asEval();
+  final ExprEvalVector<double[]> 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 3476cd7e55..0e5f92bc41 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<TLeftInput, TRightInput, TOutput>
     implements ExprVectorProcessor<TOutput>
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 cc8bcc72c9..243b7ae79b 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<TLeftInput, TRightInput, TOutput>
-    implements ExprVectorProcessor<TOutput>
+public abstract class BivariateLongFunctionVectorValueProcessor<TLeftInput, TRightInput>
+    implements ExprVectorProcessor<long[]>
 {
   final ExprVectorProcessor<TLeftInput> left;
   final ExprVectorProcessor<TRightInput> right;
   final int maxVectorSize;
   final boolean[] outNulls;
-  final TOutput outValues;
+  final long[] outValues;
 
-  protected BivariateFunctionVectorValueProcessor(
+  protected BivariateLongFunctionVectorValueProcessor(
       ExprVectorProcessor<TLeftInput> left,
       ExprVectorProcessor<TRightInput> 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<TOutput> evalVector(Expr.VectorInputBinding bindings)
+  public final ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings)
   {
     final ExprEvalVector<TLeftInput> lhs = left.evalVector(bindings);
     final ExprEvalVector<TRightInput> rhs = right.evalVector(bindings);
@@ -70,6 +72,8 @@ public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightIn
         outNulls[i] = (hasLeftNulls && leftNulls[i]) || (hasRightNulls && rightNulls[i]);
         if (!outNulls[i]) {
           processIndex(leftInput, rightInput, i);
+        } else {
+          outValues[i] = 0L;
         }
       }
     } else {
@@ -83,5 +87,8 @@ public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightIn
 
   abstract void processIndex(TLeftInput leftInput, TRightInput rightInput, int i);
 
-  abstract ExprEvalVector<TOutput> asEval();
+  final ExprEvalVector<long[]> 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 01d40f2aa6..578daf0e48 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<double[], double[]>
+    extends UnivariateDoubleFunctionVectorValueProcessor<double[]>
 {
   public DoubleOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor<double[]> 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<double[]> 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 22315772ec..aac396aa7d 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<double[], long[], double[]>
+    extends BivariateDoubleFunctionVectorValueProcessor<double[], long[]>
 {
   public DoubleOutDoubleLongInFunctionVectorValueProcessor(
       ExprVectorProcessor<double[]> 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<double[]> 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 9a566b67c0..a3a7d77b1d 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<double[], double[], double[]>
+    extends BivariateDoubleFunctionVectorValueProcessor<double[], double[]>
 {
   public DoubleOutDoublesInFunctionVectorValueProcessor(
       ExprVectorProcessor<double[]> 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<double[]> 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 ee2f41b3f3..dc62fe1b02 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<long[], double[], double[]>
+    extends BivariateDoubleFunctionVectorValueProcessor<long[], double[]>
 {
   public DoubleOutLongDoubleInFunctionVectorValueProcessor(
       ExprVectorProcessor<long[]> 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<double[]> 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 1ed8c6ae98..0b833d0208 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<long[], double[]>
+    extends UnivariateDoubleFunctionVectorValueProcessor<long[]>
 {
   public DoubleOutLongInFunctionVectorValueProcessor(ExprVectorProcessor<long[]> 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<double[]> 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 b08ccdcc79..699f66f53f 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<long[], long[], double[]>
+    extends BivariateDoubleFunctionVectorValueProcessor<long[], long[]>
 {
   public DoubleOutLongsInFunctionVectorValueProcessor(
       ExprVectorProcessor<long[]> 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<double[]> 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 8d9c9be3e2..0193e24de2 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<double[], long[]>
+public abstract class LongOutDoubleInFunctionVectorValueProcessor
+    extends UnivariateLongFunctionVectorValueProcessor<double[]>
 {
   public LongOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor<double[]> 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<long[]> 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 a5dd4024c5..25e854ee5b 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<double[], long[], long[]>
+    extends BivariateLongFunctionVectorValueProcessor<double[], long[]>
 {
   public LongOutDoubleLongInFunctionVectorValueProcessor(
       ExprVectorProcessor<double[]> 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<long[]> 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 f5d9fdb7a0..bbd6fa1815 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<double[], double[], long[]>
+    extends BivariateLongFunctionVectorValueProcessor<double[], double[]>
 {
   public LongOutDoublesInFunctionVectorValueProcessor(
       ExprVectorProcessor<double[]> 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<long[]> 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 57f17d37d5..d63ffdd0ce 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<long[], double[], long[]>
+    extends BivariateLongFunctionVectorValueProcessor<long[], double[]>
 {
   public LongOutLongDoubleInFunctionVectorValueProcessor(
       ExprVectorProcessor<long[]> 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<long[]> 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 00f43977c1..c13ae84849 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<long[], long[]>
+public abstract class LongOutLongInFunctionVectorValueProcessor
+    extends UnivariateLongFunctionVectorValueProcessor<long[]>
 {
   public LongOutLongInFunctionVectorValueProcessor(ExprVectorProcessor<long[]> 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<long[]> 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 b5dbf117f2..9646ddf711 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<long[], long[], long[]>
+    extends BivariateLongFunctionVectorValueProcessor<long[], long[]>
 {
   public LongOutLongsInFunctionVectorValueProcessor(
       ExprVectorProcessor<long[]> 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<long[]> asEval()
-  {
-    return new ExprEvalLongVector(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/UnivariateDoubleFunctionVectorValueProcessor.java
similarity index 76%
copy from core/src/main/java/org/apache/druid/math/expr/vector/UnivariateFunctionVectorValueProcessor.java
copy to core/src/main/java/org/apache/druid/math/expr/vector/UnivariateDoubleFunctionVectorValueProcessor.java
index a5293587b4..03f9be1eb9 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/UnivariateDoubleFunctionVectorValueProcessor.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 double[], see {@link UnivariateLongFunctionVectorValueProcessor} for
+ * long[] primitives.
  */
-public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> implements ExprVectorProcessor<TOutput>
+public abstract class UnivariateDoubleFunctionVectorValueProcessor<TInput> implements ExprVectorProcessor<double[]>
 {
   final ExprVectorProcessor<TInput> processor;
   final int maxVectorSize;
   final boolean[] outNulls;
-  final TOutput outValues;
+  final double[] outValues;
 
-  public UnivariateFunctionVectorValueProcessor(
+  public UnivariateDoubleFunctionVectorValueProcessor(
       ExprVectorProcessor<TInput> processor,
-      int maxVectorSize,
-      TOutput outValues
+      int maxVectorSize
   )
   {
     this.processor = processor;
     this.maxVectorSize = maxVectorSize;
     this.outNulls = new boolean[maxVectorSize];
-    this.outValues = outValues;
+    this.outValues = new double[maxVectorSize];
   }
 
   @Override
-  public final ExprEvalVector<TOutput> evalVector(Expr.VectorInputBinding bindings)
+  public final ExprEvalVector<double[]> evalVector(Expr.VectorInputBinding bindings)
   {
     final ExprEvalVector<TInput> lhs = processor.evalVector(bindings);
 
@@ -61,6 +63,8 @@ public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> im
         outNulls[i] = inputNulls[i];
         if (!outNulls[i]) {
           processIndex(input, i);
+        } else {
+          outValues[i] = 0.0;
         }
       }
     } else {
@@ -74,5 +78,8 @@ public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> im
 
   abstract void processIndex(TInput input, int i);
 
-  abstract ExprEvalVector<TOutput> asEval();
+  final ExprEvalVector<double[]> 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 a5293587b4..8694489450 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<TInput, TOutput> implements ExprVectorProcessor<TOutput>
+public abstract class UnivariateLongFunctionVectorValueProcessor<TInput> implements ExprVectorProcessor<long[]>
 {
   final ExprVectorProcessor<TInput> processor;
   final int maxVectorSize;
   final boolean[] outNulls;
-  final TOutput outValues;
+  final long[] outValues;
 
-  public UnivariateFunctionVectorValueProcessor(
+  public UnivariateLongFunctionVectorValueProcessor(
       ExprVectorProcessor<TInput> 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<TOutput> evalVector(Expr.VectorInputBinding bindings)
+  public final ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings)
   {
     final ExprEvalVector<TInput> lhs = processor.evalVector(bindings);
 
@@ -61,6 +63,8 @@ public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> im
         outNulls[i] = inputNulls[i];
         if (!outNulls[i]) {
           processIndex(input, i);
+        } else {
+          outValues[i] = 0L;
         }
       }
     } else {
@@ -74,5 +78,8 @@ public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> im
 
   abstract void processIndex(TInput input, int i);
 
-  abstract ExprEvalVector<TOutput> asEval();
+  final ExprEvalVector<long[]> 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 0d60726203..4499be2f31 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 1362d3f348..4819661f59 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 c3815286d9..823d15ff75 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 b648ecc377..4bbc23068f 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 f6d2af5e83..66a950cb27 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 e95ba65643..acb41e516b 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()
   {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org