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

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


The following commit(s) were added to refs/heads/24.0.1 by this push:
     new 8f60ad15b3 [Backport] nested column fixes 24.0.1 (#13279)
8f60ad15b3 is described below

commit 8f60ad15b3a96499f98352ae70bc14f710e58204
Author: Clint Wylie <[email protected]>
AuthorDate: Mon Oct 31 19:29:17 2022 -0700

    [Backport] nested column fixes 24.0.1 (#13279)
    
    * use object[] instead of string[] for vector expressions to be consistent 
with vector object selectors (#13209)
    
    * fix issue with nested column null value index incorrectly matching 
non-null values (#13211)
    
    * fix json_value sql planning with decimal type, fix vectorized expression 
math null value handling in default mode (#13214)
---
 .../druid/math/expr/BinaryMathOperatorExpr.java    |  10 +-
 .../org/apache/druid/math/expr/IdentifierExpr.java |  18 ++--
 ...variateDoubleFunctionVectorValueProcessor.java} |  25 +++--
 .../vector/BivariateFunctionVectorProcessor.java   |   5 +-
 ...BivariateLongFunctionVectorValueProcessor.java} |  25 +++--
 .../expr/vector/CastToStringVectorProcessor.java   |   8 +-
 ...bleOutDoubleInFunctionVectorValueProcessor.java |  12 +--
 ...utDoubleLongInFunctionVectorValueProcessor.java |  13 +--
 ...leOutDoublesInFunctionVectorValueProcessor.java |  13 +--
 ...utLongDoubleInFunctionVectorValueProcessor.java |  13 +--
 ...oubleOutLongInFunctionVectorValueProcessor.java |  12 +--
 ...ubleOutLongsInFunctionVectorValueProcessor.java |  13 +--
 ...StringVector.java => ExprEvalObjectVector.java} |   7 +-
 .../druid/math/expr/vector/ExprEvalVector.java     |   2 +-
 ...ongOutDoubleInFunctionVectorValueProcessor.java |  13 +--
 ...utDoubleLongInFunctionVectorValueProcessor.java |  13 +--
 ...ngOutDoublesInFunctionVectorValueProcessor.java |  13 +--
 ...utLongDoubleInFunctionVectorValueProcessor.java |  13 +--
 .../LongOutLongInFunctionVectorValueProcessor.java |  13 +--
 ...LongOutLongsInFunctionVectorValueProcessor.java |  13 +--
 ...=> LongOutObjectInFunctionVectorProcessor.java} |  17 ++-
 ...> LongOutObjectsInFunctionVectorProcessor.java} |  22 ++--
 ... => ObjectOutMultiObjectInVectorProcessor.java} |  30 +++---
 ...ObjectOutObjectsInFunctionVectorProcessor.java} |  34 +++---
 ...variateDoubleFunctionVectorValueProcessor.java} |  23 ++--
 ...nivariateLongFunctionVectorValueProcessor.java} |  23 ++--
 .../expr/vector/VectorComparisonProcessors.java    | 120 +++++++++++++--------
 .../math/expr/vector/VectorMathProcessors.java     |   6 +-
 .../druid/math/expr/vector/VectorProcessors.java   |  90 +++++++++-------
 .../math/expr/vector/VectorStringProcessors.java   |  38 ++++---
 .../druid/math/expr/VectorExprSanityTest.java      |   4 +-
 .../org/apache/druid/segment/VirtualColumns.java   |   3 +-
 .../column/StringDictionaryEncodedColumn.java      |   2 +-
 .../NestedFieldLiteralColumnIndexSupplier.java     |  10 +-
 .../virtual/ExpressionVectorInputBinding.java      |   4 +-
 ...valuationExpressionDimensionVectorSelector.java |   7 +-
 .../query/groupby/NestedDataGroupByQueryTest.java  |  44 ++++++++
 .../NestedFieldLiteralColumnIndexSupplierTest.java |  18 ++++
 .../ExpressionVectorObjectSelectorTest.java        |   4 +-
 .../virtual/ExpressionVectorSelectorsTest.java     |   3 +-
 .../druid/segment/virtual/VirtualColumnsTest.java  |  32 ++++++
 .../builtin/NestedDataOperatorConversions.java     |   3 +-
 .../sql/calcite/CalciteNestedDataQueryTest.java    |  58 ++++++++++
 43 files changed, 511 insertions(+), 338 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/IdentifierExpr.java 
b/core/src/main/java/org/apache/druid/math/expr/IdentifierExpr.java
index a41d7a9957..01622a5b26 100644
--- a/core/src/main/java/org/apache/druid/math/expr/IdentifierExpr.java
+++ b/core/src/main/java/org/apache/druid/math/expr/IdentifierExpr.java
@@ -23,12 +23,11 @@ import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.math.expr.vector.ExprEvalDoubleVector;
 import org.apache.druid.math.expr.vector.ExprEvalLongVector;
-import org.apache.druid.math.expr.vector.ExprEvalStringVector;
+import org.apache.druid.math.expr.vector.ExprEvalObjectVector;
 import org.apache.druid.math.expr.vector.ExprEvalVector;
 import org.apache.druid.math.expr.vector.ExprVectorProcessor;
 
 import javax.annotation.Nullable;
-import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -158,15 +157,12 @@ class IdentifierExpr implements Expr
     if (inputType == null) {
       // nil column, we can be anything, so be a string because it's the most 
flexible
       // (numbers will be populated with default values in default mode and 
non-null)
-      return new IdentifierVectorProcessor<String[]>(ExpressionType.STRING)
+      return new IdentifierVectorProcessor<Object[]>(ExpressionType.STRING)
       {
         @Override
-        public ExprEvalVector<String[]> evalVector(VectorInputBinding bindings)
+        public ExprEvalVector<Object[]> evalVector(VectorInputBinding bindings)
         {
-          // need to cast to string[] because null columns come out as object[]
-          return new ExprEvalStringVector(
-              Arrays.stream(bindings.getObjectVector(binding)).map(x -> 
(String) x).toArray(String[]::new)
-          );
+          return new ExprEvalObjectVector(bindings.getObjectVector(binding));
         }
       };
     }
@@ -190,12 +186,12 @@ class IdentifierExpr implements Expr
           }
         };
       case STRING:
-        return new IdentifierVectorProcessor<String[]>(inputType)
+        return new IdentifierVectorProcessor<Object[]>(inputType)
         {
           @Override
-          public ExprEvalVector<String[]> evalVector(VectorInputBinding 
bindings)
+          public ExprEvalVector<Object[]> evalVector(VectorInputBinding 
bindings)
           {
-            return new ExprEvalStringVector(bindings.getObjectVector(binding));
+            return new ExprEvalObjectVector(bindings.getObjectVector(binding));
           }
         };
       default:
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/CastToStringVectorProcessor.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/CastToStringVectorProcessor.java
index 27e0d1b9cf..b02afd4f88 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/CastToStringVectorProcessor.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/CastToStringVectorProcessor.java
@@ -23,7 +23,7 @@ import org.apache.druid.math.expr.Evals;
 import org.apache.druid.math.expr.Expr;
 import org.apache.druid.math.expr.ExpressionType;
 
-public final class CastToStringVectorProcessor extends 
CastToTypeVectorProcessor<String[]>
+public final class CastToStringVectorProcessor extends 
CastToTypeVectorProcessor<Object[]>
 {
   public CastToStringVectorProcessor(ExprVectorProcessor<?> delegate)
   {
@@ -31,15 +31,15 @@ public final class CastToStringVectorProcessor extends 
CastToTypeVectorProcessor
   }
 
   @Override
-  public ExprEvalVector<String[]> evalVector(Expr.VectorInputBinding bindings)
+  public ExprEvalVector<Object[]> evalVector(Expr.VectorInputBinding bindings)
   {
     ExprEvalVector<?> result = delegate.evalVector(bindings);
     final Object[] objects = result.getObjectVector();
-    final String[] output = new String[objects.length];
+    final Object[] output = new String[objects.length];
     for (int i = 0; i < objects.length; i++) {
       output[i] = Evals.asString(objects[i]);
     }
-    return new ExprEvalStringVector(output);
+    return new ExprEvalObjectVector(output);
   }
 
   @Override
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/ExprEvalStringVector.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalObjectVector.java
similarity index 90%
rename from 
core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalStringVector.java
rename to 
core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalObjectVector.java
index 257e5ecdf8..eaeb0f04f1 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalStringVector.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalObjectVector.java
@@ -20,12 +20,13 @@
 package org.apache.druid.math.expr.vector;
 
 import org.apache.druid.common.config.NullHandling;
+import org.apache.druid.math.expr.Evals;
 import org.apache.druid.math.expr.ExprEval;
 import org.apache.druid.math.expr.ExpressionType;
 
 import javax.annotation.Nullable;
 
-public final class ExprEvalStringVector extends ExprEvalVector<String[]>
+public final class ExprEvalObjectVector extends ExprEvalVector<Object[]>
 {
   @Nullable
   private long[] longs;
@@ -35,7 +36,7 @@ public final class ExprEvalStringVector extends 
ExprEvalVector<String[]>
   @Nullable
   private boolean[] numericNulls;
 
-  public ExprEvalStringVector(String[] values)
+  public ExprEvalObjectVector(Object[] values)
   {
     super(values, null);
   }
@@ -47,7 +48,7 @@ public final class ExprEvalStringVector extends 
ExprEvalVector<String[]>
       doubles = new double[values.length];
       numericNulls = new boolean[values.length];
       for (int i = 0; i < values.length; i++) {
-        Number n = ExprEval.computeNumber(values[i]);
+        Number n = ExprEval.computeNumber(Evals.asString(values[i]));
         if (n != null) {
           longs[i] = n.longValue();
           doubles[i] = n.doubleValue();
diff --git 
a/core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalVector.java 
b/core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalVector.java
index fdb6605989..723b34f12c 100644
--- a/core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalVector.java
+++ b/core/src/main/java/org/apache/druid/math/expr/vector/ExprEvalVector.java
@@ -29,7 +29,7 @@ import java.lang.reflect.Array;
  * Result of {@link ExprVectorProcessor#evalVector} which wraps the actual 
evaluated results of the operation over the
  * input vector(s). Methods to get actual results mirror vectorized value and 
object selectors.
  *
- * The generic parameter T should be the native java array type of the vector 
result (long[], String[], etc.)
+ * The generic parameter T should be the native java array type of the vector 
result (long[], Object[], etc.)
  */
 public abstract class ExprEvalVector<T>
 {
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/LongOutStringInFunctionVectorProcessor.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutObjectInFunctionVectorProcessor.java
similarity index 71%
rename from 
core/src/main/java/org/apache/druid/math/expr/vector/LongOutStringInFunctionVectorProcessor.java
rename to 
core/src/main/java/org/apache/druid/math/expr/vector/LongOutObjectInFunctionVectorProcessor.java
index 2ebc519086..8ae0c4d751 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutStringInFunctionVectorProcessor.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutObjectInFunctionVectorProcessor.java
@@ -22,14 +22,21 @@ package org.apache.druid.math.expr.vector;
 import org.apache.druid.math.expr.ExpressionType;
 
 /**
- * specialized {@link UnivariateFunctionVectorObjectProcessor} for processing 
(String[]) -> long[]
+ * specialized {@link UnivariateFunctionVectorObjectProcessor} for processing 
(Object[]) -> long[]
  */
-public abstract class LongOutStringInFunctionVectorProcessor
-    extends UnivariateFunctionVectorObjectProcessor<String[], long[]>
+public abstract class LongOutObjectInFunctionVectorProcessor
+    extends UnivariateFunctionVectorObjectProcessor<Object[], long[]>
 {
-  public LongOutStringInFunctionVectorProcessor(ExprVectorProcessor<String[]> 
processor, int maxVectorSize)
+  final ExpressionType inputType;
+
+  public LongOutObjectInFunctionVectorProcessor(
+      ExprVectorProcessor<Object[]> processor,
+      int maxVectorSize,
+      ExpressionType inputType
+  )
   {
-    super(CastToTypeVectorProcessor.cast(processor, ExpressionType.STRING), 
maxVectorSize, new long[maxVectorSize]);
+    super(CastToTypeVectorProcessor.cast(processor, inputType), maxVectorSize, 
new long[maxVectorSize]);
+    this.inputType = inputType;
   }
 
   @Override
diff --git 
a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutStringsInFunctionVectorProcessor.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutObjectsInFunctionVectorProcessor.java
similarity index 71%
rename from 
core/src/main/java/org/apache/druid/math/expr/vector/LongOutStringsInFunctionVectorProcessor.java
rename to 
core/src/main/java/org/apache/druid/math/expr/vector/LongOutObjectsInFunctionVectorProcessor.java
index d450b86330..88f2f0ff54 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/LongOutStringsInFunctionVectorProcessor.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/LongOutObjectsInFunctionVectorProcessor.java
@@ -23,19 +23,21 @@ import org.apache.druid.math.expr.ExpressionType;
 
 import javax.annotation.Nullable;
 
-public abstract class LongOutStringsInFunctionVectorProcessor extends 
BivariateFunctionVectorObjectProcessor<String[], String[], long[]>
+public abstract class LongOutObjectsInFunctionVectorProcessor
+    extends BivariateFunctionVectorObjectProcessor<Object[], Object[], long[]>
 {
   private final boolean[] outNulls;
 
-  protected LongOutStringsInFunctionVectorProcessor(
-      ExprVectorProcessor<String[]> left,
-      ExprVectorProcessor<String[]> right,
-      int maxVectorSize
+  protected LongOutObjectsInFunctionVectorProcessor(
+      ExprVectorProcessor<Object[]> left,
+      ExprVectorProcessor<Object[]> right,
+      int maxVectorSize,
+      ExpressionType inputType
   )
   {
     super(
-        CastToTypeVectorProcessor.cast(left, ExpressionType.STRING),
-        CastToTypeVectorProcessor.cast(right, ExpressionType.STRING),
+        CastToTypeVectorProcessor.cast(left, inputType),
+        CastToTypeVectorProcessor.cast(right, inputType),
         maxVectorSize,
         new long[maxVectorSize]
     );
@@ -43,12 +45,12 @@ public abstract class 
LongOutStringsInFunctionVectorProcessor extends BivariateF
   }
 
   @Nullable
-  abstract Long processValue(@Nullable String leftVal, @Nullable String 
rightVal);
+  abstract Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal);
 
   @Override
-  void processIndex(String[] strings, String[] strings2, int i)
+  void processIndex(Object[] in1, Object[] in2, int i)
   {
-    final Long outVal = processValue(strings[i], strings2[i]);
+    final Long outVal = processValue(in1[i], in2[i]);
     if (outVal == null) {
       outValues[i] = 0L;
       outNulls[i] = true;
diff --git 
a/core/src/main/java/org/apache/druid/math/expr/vector/StringOutMultiStringInVectorProcessor.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/ObjectOutMultiObjectInVectorProcessor.java
similarity index 67%
rename from 
core/src/main/java/org/apache/druid/math/expr/vector/StringOutMultiStringInVectorProcessor.java
rename to 
core/src/main/java/org/apache/druid/math/expr/vector/ObjectOutMultiObjectInVectorProcessor.java
index 1008098d60..2a58e3ea82 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/StringOutMultiStringInVectorProcessor.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/ObjectOutMultiObjectInVectorProcessor.java
@@ -19,41 +19,43 @@
 
 package org.apache.druid.math.expr.vector;
 
-import org.apache.druid.common.config.NullHandling;
 import org.apache.druid.math.expr.Expr;
 import org.apache.druid.math.expr.ExpressionType;
 
 /**
  * many strings enter, one string leaves...
  */
-public abstract class StringOutMultiStringInVectorProcessor implements 
ExprVectorProcessor<String[]>
+public abstract class ObjectOutMultiObjectInVectorProcessor implements 
ExprVectorProcessor<Object[]>
 {
-  final ExprVectorProcessor<String[]>[] inputs;
+  final ExprVectorProcessor<Object[]>[] inputs;
   final int maxVectorSize;
-  final String[] outValues;
-  final boolean sqlCompatible = NullHandling.sqlCompatible();
+  final Object[] outValues;
 
-  protected StringOutMultiStringInVectorProcessor(
-      ExprVectorProcessor<String[]>[] inputs,
-      int maxVectorSize
+  final ExpressionType expressionType;
+
+  protected ObjectOutMultiObjectInVectorProcessor(
+      ExprVectorProcessor<Object[]>[] inputs,
+      int maxVectorSize,
+      ExpressionType objectType
   )
   {
     this.inputs = inputs;
     this.maxVectorSize = maxVectorSize;
-    this.outValues = new String[maxVectorSize];
+    this.outValues = new Object[maxVectorSize];
+    this.expressionType = objectType;
   }
 
   @Override
   public ExpressionType getOutputType()
   {
-    return ExpressionType.STRING;
+    return expressionType;
   }
 
   @Override
-  public ExprEvalVector<String[]> evalVector(Expr.VectorInputBinding bindings)
+  public ExprEvalVector<Object[]> evalVector(Expr.VectorInputBinding bindings)
   {
     final int currentSize = bindings.getCurrentVectorSize();
-    final String[][] in = new String[inputs.length][];
+    final Object[][] in = new Object[inputs.length][];
     for (int i = 0; i < inputs.length; i++) {
       in[i] = inputs[i].evalVector(bindings).values();
     }
@@ -61,8 +63,8 @@ public abstract class StringOutMultiStringInVectorProcessor 
implements ExprVecto
     for (int i = 0; i < currentSize; i++) {
       processIndex(in, i);
     }
-    return new ExprEvalStringVector(outValues);
+    return new ExprEvalObjectVector(outValues);
   }
 
-  abstract void processIndex(String[][] in, int i);
+  abstract void processIndex(Object[][] in, int i);
 }
diff --git 
a/core/src/main/java/org/apache/druid/math/expr/vector/StringOutStringsInFunctionVectorProcessor.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/ObjectOutObjectsInFunctionVectorProcessor.java
similarity index 56%
rename from 
core/src/main/java/org/apache/druid/math/expr/vector/StringOutStringsInFunctionVectorProcessor.java
rename to 
core/src/main/java/org/apache/druid/math/expr/vector/ObjectOutObjectsInFunctionVectorProcessor.java
index 7bd7ed1277..93089f5fc5 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/StringOutStringsInFunctionVectorProcessor.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/ObjectOutObjectsInFunctionVectorProcessor.java
@@ -23,30 +23,34 @@ import org.apache.druid.math.expr.ExpressionType;
 
 import javax.annotation.Nullable;
 
-public abstract class StringOutStringsInFunctionVectorProcessor
-    extends BivariateFunctionVectorObjectProcessor<String[], String[], 
String[]>
+public abstract class ObjectOutObjectsInFunctionVectorProcessor
+    extends BivariateFunctionVectorObjectProcessor<Object[], Object[], 
Object[]>
 {
-  protected StringOutStringsInFunctionVectorProcessor(
-      ExprVectorProcessor<String[]> left,
-      ExprVectorProcessor<String[]> right,
-      int maxVectorSize
+  final ExpressionType expressionType;
+
+  protected ObjectOutObjectsInFunctionVectorProcessor(
+      ExprVectorProcessor<Object[]> left,
+      ExprVectorProcessor<Object[]> right,
+      int maxVectorSize,
+      ExpressionType expressionType
   )
   {
     super(
-        CastToTypeVectorProcessor.cast(left, ExpressionType.STRING),
-        CastToTypeVectorProcessor.cast(right, ExpressionType.STRING),
+        CastToTypeVectorProcessor.cast(left, expressionType),
+        CastToTypeVectorProcessor.cast(right, expressionType),
         maxVectorSize,
-        new String[maxVectorSize]
+        new Object[maxVectorSize]
     );
+    this.expressionType = expressionType;
   }
 
   @Nullable
-  protected abstract String processValue(@Nullable String leftVal, @Nullable 
String rightVal);
+  protected abstract Object processValue(@Nullable Object leftVal, @Nullable 
Object rightVal);
 
   @Override
-  void processIndex(String[] strings, String[] strings2, int i)
+  void processIndex(Object[] in1, Object[] in2, int i)
   {
-    outValues[i] = processValue(strings[i], strings2[i]);
+    outValues[i] = processValue(in1[i], in2[i]);
   }
 
   @Override
@@ -56,14 +60,14 @@ public abstract class 
StringOutStringsInFunctionVectorProcessor
   }
 
   @Override
-  ExprEvalVector<String[]> asEval()
+  ExprEvalVector<Object[]> asEval()
   {
-    return new ExprEvalStringVector(outValues);
+    return new ExprEvalObjectVector(outValues);
   }
 
   @Override
   public ExpressionType getOutputType()
   {
-    return ExpressionType.STRING;
+    return expressionType;
   }
 }
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/VectorComparisonProcessors.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/VectorComparisonProcessors.java
index bf4e665925..decfd9b3d4 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/VectorComparisonProcessors.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/VectorComparisonProcessors.java
@@ -38,7 +38,7 @@ public class VectorComparisonProcessors
       Expr.VectorInputBindingInspector inspector,
       Expr left,
       Expr right,
-      Supplier<LongOutStringsInFunctionVectorProcessor> 
longOutStringsInFunctionVectorProcessor,
+      Supplier<LongOutObjectsInFunctionVectorProcessor> 
longOutStringsInFunctionVectorProcessor,
       Supplier<LongOutLongsInFunctionVectorValueProcessor> 
longOutLongsInProcessor,
       Supplier<DoubleOutLongDoubleInFunctionVectorValueProcessor> 
doubleOutLongDoubleInProcessor,
       Supplier<DoubleOutDoubleLongInFunctionVectorValueProcessor> 
doubleOutDoubleLongInProcessor,
@@ -81,7 +81,7 @@ public class VectorComparisonProcessors
       Expr.VectorInputBindingInspector inspector,
       Expr left,
       Expr right,
-      Supplier<LongOutStringsInFunctionVectorProcessor> 
longOutStringsInFunctionVectorProcessor,
+      Supplier<LongOutObjectsInFunctionVectorProcessor> 
longOutStringsInFunctionVectorProcessor,
       Supplier<LongOutLongsInFunctionVectorValueProcessor> 
longOutLongsInProcessor,
       Supplier<LongOutLongDoubleInFunctionVectorValueProcessor> 
longOutLongDoubleInProcessor,
       Supplier<LongOutDoubleLongInFunctionVectorValueProcessor> 
longOutDoubleLongInProcessor,
@@ -136,15 +136,16 @@ public class VectorComparisonProcessors
           inspector,
           left,
           right,
-          () -> new LongOutStringsInFunctionVectorProcessor(
+          () -> new LongOutObjectsInFunctionVectorProcessor(
               left.buildVectorized(inspector),
               right.buildVectorized(inspector),
-              inspector.getMaxVectorSize()
+              inspector.getMaxVectorSize(),
+              ExpressionType.STRING
           )
           {
             @Nullable
             @Override
-            Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+            Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
             {
               return Evals.asLong(Objects.equals(leftVal, rightVal));
             }
@@ -203,15 +204,16 @@ public class VectorComparisonProcessors
         inspector,
         left,
         right,
-        () -> new LongOutStringsInFunctionVectorProcessor(
+        () -> new LongOutObjectsInFunctionVectorProcessor(
             left.buildVectorized(inspector),
             right.buildVectorized(inspector),
-            inspector.getMaxVectorSize()
+            inspector.getMaxVectorSize(),
+            ExpressionType.STRING
         )
         {
           @Nullable
           @Override
-          Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+          Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
           {
             return Evals.asLong(Objects.equals(leftVal, rightVal));
           }
@@ -278,15 +280,16 @@ public class VectorComparisonProcessors
           inspector,
           left,
           right,
-          () -> new LongOutStringsInFunctionVectorProcessor(
+          () -> new LongOutObjectsInFunctionVectorProcessor(
               left.buildVectorized(inspector),
               right.buildVectorized(inspector),
-              inspector.getMaxVectorSize()
+              inspector.getMaxVectorSize(),
+              ExpressionType.STRING
           )
           {
             @Nullable
             @Override
-            Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+            Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
             {
               return Evals.asLong(!Objects.equals(leftVal, rightVal));
             }
@@ -345,15 +348,16 @@ public class VectorComparisonProcessors
         inspector,
         left,
         right,
-        () -> new LongOutStringsInFunctionVectorProcessor(
+        () -> new LongOutObjectsInFunctionVectorProcessor(
             left.buildVectorized(inspector),
             right.buildVectorized(inspector),
-            inspector.getMaxVectorSize()
+            inspector.getMaxVectorSize(),
+            ExpressionType.STRING
         )
         {
           @Nullable
           @Override
-          Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+          Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
           {
             return Evals.asLong(!Objects.equals(leftVal, rightVal));
           }
@@ -420,17 +424,20 @@ public class VectorComparisonProcessors
           inspector,
           left,
           right,
-          () -> new LongOutStringsInFunctionVectorProcessor(
+          () -> new LongOutObjectsInFunctionVectorProcessor(
               left.buildVectorized(inspector),
               right.buildVectorized(inspector),
-              inspector.getMaxVectorSize()
+              inspector.getMaxVectorSize(),
+              ExpressionType.STRING
           )
           {
             @Nullable
             @Override
-            Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+            Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
             {
-              return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
>= 0);
+              return Evals.asLong(
+                  Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) >= 0
+              );
             }
           },
           () -> new LongOutLongsInFunctionVectorValueProcessor(
@@ -487,17 +494,20 @@ public class VectorComparisonProcessors
         inspector,
         left,
         right,
-        () -> new LongOutStringsInFunctionVectorProcessor(
+        () -> new LongOutObjectsInFunctionVectorProcessor(
             left.buildVectorized(inspector),
             right.buildVectorized(inspector),
-            inspector.getMaxVectorSize()
+            inspector.getMaxVectorSize(),
+            ExpressionType.STRING
         )
         {
           @Nullable
           @Override
-          Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+          Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
           {
-            return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
>= 0);
+            return Evals.asLong(
+                Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) >= 0
+            );
           }
         },
         () -> new LongOutLongsInFunctionVectorValueProcessor(
@@ -562,17 +572,20 @@ public class VectorComparisonProcessors
           inspector,
           left,
           right,
-          () -> new LongOutStringsInFunctionVectorProcessor(
+          () -> new LongOutObjectsInFunctionVectorProcessor(
               left.buildVectorized(inspector),
               right.buildVectorized(inspector),
-              inspector.getMaxVectorSize()
+              inspector.getMaxVectorSize(),
+              ExpressionType.STRING
           )
           {
             @Nullable
             @Override
-            Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+            Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
             {
-              return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
> 0);
+              return Evals.asLong(
+                  Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) > 0
+              );
             }
           },
           () -> new LongOutLongsInFunctionVectorValueProcessor(
@@ -629,17 +642,20 @@ public class VectorComparisonProcessors
         inspector,
         left,
         right,
-        () -> new LongOutStringsInFunctionVectorProcessor(
+        () -> new LongOutObjectsInFunctionVectorProcessor(
             left.buildVectorized(inspector),
             right.buildVectorized(inspector),
-            inspector.getMaxVectorSize()
+            inspector.getMaxVectorSize(),
+            ExpressionType.STRING
         )
         {
           @Nullable
           @Override
-          Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+          Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
           {
-            return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
> 0);
+            return Evals.asLong(
+                Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) > 0
+            );
           }
         },
         () -> new LongOutLongsInFunctionVectorValueProcessor(
@@ -704,17 +720,20 @@ public class VectorComparisonProcessors
           inspector,
           left,
           right,
-          () -> new LongOutStringsInFunctionVectorProcessor(
+          () -> new LongOutObjectsInFunctionVectorProcessor(
               left.buildVectorized(inspector),
               right.buildVectorized(inspector),
-              inspector.getMaxVectorSize()
+              inspector.getMaxVectorSize(),
+              ExpressionType.STRING
           )
           {
             @Nullable
             @Override
-            Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+            Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
             {
-              return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
<= 0);
+              return Evals.asLong(
+                  Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) <= 0
+              );
             }
           },
           () -> new LongOutLongsInFunctionVectorValueProcessor(
@@ -771,17 +790,20 @@ public class VectorComparisonProcessors
         inspector,
         left,
         right,
-        () -> new LongOutStringsInFunctionVectorProcessor(
+        () -> new LongOutObjectsInFunctionVectorProcessor(
             left.buildVectorized(inspector),
             right.buildVectorized(inspector),
-            inspector.getMaxVectorSize()
+            inspector.getMaxVectorSize(),
+            ExpressionType.STRING
         )
         {
           @Nullable
           @Override
-          Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+          Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
           {
-            return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
<= 0);
+            return Evals.asLong(
+                Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) <= 0
+            );
           }
         },
         () -> new LongOutLongsInFunctionVectorValueProcessor(
@@ -846,17 +868,20 @@ public class VectorComparisonProcessors
           inspector,
           left,
           right,
-          () -> new LongOutStringsInFunctionVectorProcessor(
+          () -> new LongOutObjectsInFunctionVectorProcessor(
               left.buildVectorized(inspector),
               right.buildVectorized(inspector),
-              inspector.getMaxVectorSize()
+              inspector.getMaxVectorSize(),
+              ExpressionType.STRING
           )
           {
             @Nullable
             @Override
-            Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+            Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
             {
-              return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
< 0);
+              return Evals.asLong(
+                  Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) < 0
+              );
             }
           },
           () -> new LongOutLongsInFunctionVectorValueProcessor(
@@ -913,17 +938,20 @@ public class VectorComparisonProcessors
         inspector,
         left,
         right,
-        () -> new LongOutStringsInFunctionVectorProcessor(
+        () -> new LongOutObjectsInFunctionVectorProcessor(
             left.buildVectorized(inspector),
             right.buildVectorized(inspector),
-            inspector.getMaxVectorSize()
+            inspector.getMaxVectorSize(),
+            ExpressionType.STRING
         )
         {
           @Nullable
           @Override
-          Long processValue(@Nullable String leftVal, @Nullable String 
rightVal)
+          Long processValue(@Nullable Object leftVal, @Nullable Object 
rightVal)
           {
-            return 
Evals.asLong(Comparators.<String>naturalNullsFirst().compare(leftVal, rightVal) 
< 0);
+            return Evals.asLong(
+                Comparators.<String>naturalNullsFirst().compare((String) 
leftVal, (String) rightVal) < 0
+            );
           }
         },
         () -> new LongOutLongsInFunctionVectorValueProcessor(
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/main/java/org/apache/druid/math/expr/vector/VectorProcessors.java 
b/core/src/main/java/org/apache/druid/math/expr/vector/VectorProcessors.java
index 4a548ca10d..ee066065ad 100644
--- a/core/src/main/java/org/apache/druid/math/expr/vector/VectorProcessors.java
+++ b/core/src/main/java/org/apache/druid/math/expr/vector/VectorProcessors.java
@@ -82,9 +82,9 @@ public class VectorProcessors
 
   public static <T> ExprVectorProcessor<T> constant(@Nullable String constant, 
int maxVectorSize)
   {
-    final String[] strings = new String[maxVectorSize];
+    final Object[] strings = new Object[maxVectorSize];
     Arrays.fill(strings, constant);
-    final ExprEvalStringVector eval = new ExprEvalStringVector(strings);
+    final ExprEvalObjectVector eval = new ExprEvalObjectVector(strings);
     return new ExprVectorProcessor<T>()
     {
       @Override
@@ -159,23 +159,29 @@ public class VectorProcessors
 
   public static <T> ExprVectorProcessor<T> 
parseLong(Expr.VectorInputBindingInspector inspector, Expr arg, int radix)
   {
-    final ExprVectorProcessor<?> processor = new 
LongOutStringInFunctionVectorProcessor(
-        CastToTypeVectorProcessor.cast(arg.buildVectorized(inspector), 
ExpressionType.STRING),
-        inspector.getMaxVectorSize()
+    final ExprVectorProcessor<?> processor = new 
LongOutObjectInFunctionVectorProcessor(
+        arg.buildVectorized(inspector),
+        inspector.getMaxVectorSize(),
+        ExpressionType.STRING
     )
     {
       @Override
-      public void processIndex(String[] strings, long[] longs, boolean[] 
outputNulls, int i)
+      public void processIndex(Object[] strings, long[] longs, boolean[] 
outputNulls, int i)
       {
         try {
-          final String input = strings[i];
-          if (radix == 16 && (input.startsWith("0x") || 
input.startsWith("0X"))) {
-            // Strip leading 0x from hex strings.
-            longs[i] = Long.parseLong(input.substring(2), radix);
+          final String input = (String) strings[i];
+          if (input == null) {
+            longs[i] = 0L;
+            outputNulls[i] = NullHandling.sqlCompatible();
           } else {
-            longs[i] = Long.parseLong(input, radix);
+            if (radix == 16 && (input.startsWith("0x") || 
input.startsWith("0X"))) {
+              // Strip leading 0x from hex strings.
+              longs[i] = Long.parseLong(input.substring(2), radix);
+            } else {
+              longs[i] = Long.parseLong(input, radix);
+            }
+            outputNulls[i] = false;
           }
-          outputNulls[i] = false;
         }
         catch (NumberFormatException e) {
           longs[i] = 0L;
@@ -199,16 +205,16 @@ public class VectorProcessors
 
     ExprVectorProcessor<?> processor = null;
     if (Types.is(type, ExprType.STRING)) {
-      final ExprVectorProcessor<String[]> input = 
expr.buildVectorized(inspector);
+      final ExprVectorProcessor<Object[]> input = 
expr.buildVectorized(inspector);
       processor = new ExprVectorProcessor<long[]>()
       {
         @Override
         public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
         {
-          final ExprEvalVector<String[]> inputEval = 
input.evalVector(bindings);
+          final ExprEvalVector<Object[]> inputEval = 
input.evalVector(bindings);
 
           final int currentSize = bindings.getCurrentVectorSize();
-          final String[] values = inputEval.values();
+          final Object[] values = inputEval.values();
           for (int i = 0; i < currentSize; i++) {
             if (values[i] == null) {
               outputValues[i] = 1L;
@@ -307,16 +313,16 @@ public class VectorProcessors
 
     ExprVectorProcessor<?> processor = null;
     if (Types.is(type, ExprType.STRING)) {
-      final ExprVectorProcessor<String[]> input = 
expr.buildVectorized(inspector);
+      final ExprVectorProcessor<Object[]> input = 
expr.buildVectorized(inspector);
       processor = new ExprVectorProcessor<long[]>()
       {
         @Override
         public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
         {
-          final ExprEvalVector<String[]> inputEval = 
input.evalVector(bindings);
+          final ExprEvalVector<Object[]> inputEval = 
input.evalVector(bindings);
 
           final int currentSize = bindings.getCurrentVectorSize();
-          final String[] values = inputEval.values();
+          final Object[] values = inputEval.values();
           for (int i = 0; i < currentSize; i++) {
             if (values[i] == null) {
               outputValues[i] = 0L;
@@ -483,19 +489,19 @@ public class VectorProcessors
             return new ExprEvalDoubleVector(output, outputNulls);
           }
         },
-        () -> new SymmetricalBivariateFunctionVectorProcessor<String[]>(
+        () -> new SymmetricalBivariateFunctionVectorProcessor<Object[]>(
             ExpressionType.STRING,
             left.buildVectorized(inspector),
             right.buildVectorized(inspector)
         )
         {
-          final String[] output = new String[maxVectorSize];
+          final Object[] output = new Object[maxVectorSize];
 
           @Override
           public void processIndex(
-              String[] leftInput,
+              Object[] leftInput,
               @Nullable boolean[] leftNulls,
-              String[] rightInput,
+              Object[] rightInput,
               @Nullable boolean[] rightNulls,
               int i
           )
@@ -504,9 +510,9 @@ public class VectorProcessors
           }
 
           @Override
-          public ExprEvalVector<String[]> asEval()
+          public ExprEvalVector<Object[]> asEval()
           {
-            return new ExprEvalStringVector(output);
+            return new ExprEvalObjectVector(output);
           }
         }
     );
@@ -518,14 +524,18 @@ public class VectorProcessors
     final int maxVectorSize = inspector.getMaxVectorSize();
     ExprVectorProcessor<?> processor = null;
     if (Types.is(inputType, ExprType.STRING)) {
-      processor = new 
LongOutStringInFunctionVectorProcessor(expr.buildVectorized(inspector), 
maxVectorSize)
+      processor = new LongOutObjectInFunctionVectorProcessor(
+          expr.buildVectorized(inspector),
+          maxVectorSize,
+          ExpressionType.STRING
+      )
       {
         @Override
-        public void processIndex(String[] strings, long[] longs, boolean[] 
outputNulls, int i)
+        public void processIndex(Object[] strings, long[] longs, boolean[] 
outputNulls, int i)
         {
           outputNulls[i] = strings[i] == null;
           if (!outputNulls[i]) {
-            longs[i] = Evals.asLong(!Evals.asBoolean(strings[i]));
+            longs[i] = Evals.asLong(!Evals.asBoolean((String) strings[i]));
           }
         }
       };
@@ -670,7 +680,7 @@ public class VectorProcessors
             return new ExprEvalLongVector(output, outputNulls);
           }
         },
-        () -> new BivariateFunctionVectorProcessor<String[], String[], long[]>(
+        () -> new BivariateFunctionVectorProcessor<Object[], Object[], long[]>(
             ExpressionType.LONG,
             left.buildVectorized(inspector),
             right.buildVectorized(inspector)
@@ -681,9 +691,9 @@ public class VectorProcessors
 
           @Override
           public void processIndex(
-              String[] leftInput,
+              Object[] leftInput,
               @Nullable boolean[] leftNulls,
-              String[] rightInput,
+              Object[] rightInput,
               @Nullable boolean[] rightNulls,
               int i
           )
@@ -697,17 +707,17 @@ public class VectorProcessors
                 outputNulls[i] = true;
                 return;
               }
-              final boolean bool = Evals.asBoolean(rightInput[i]);
+              final boolean bool = Evals.asBoolean((String) rightInput[i]);
               output[i] = Evals.asLong(bool);
               outputNulls[i] = !bool;
               return;
             } else if (rightNull) {
-              final boolean bool = Evals.asBoolean(leftInput[i]);
+              final boolean bool = Evals.asBoolean((String) leftInput[i]);
               output[i] = Evals.asLong(bool);
               outputNulls[i] = !bool;
               return;
             }
-            output[i] = Evals.asLong(Evals.asBoolean(leftInput[i]) || 
Evals.asBoolean(rightInput[i]));
+            output[i] = Evals.asLong(Evals.asBoolean((String) leftInput[i]) || 
Evals.asBoolean((String) rightInput[i]));
           }
 
           @Override
@@ -824,7 +834,7 @@ public class VectorProcessors
             return new ExprEvalLongVector(output, outputNulls);
           }
         },
-        () -> new BivariateFunctionVectorProcessor<String[], String[], long[]>(
+        () -> new BivariateFunctionVectorProcessor<Object[], Object[], long[]>(
             ExpressionType.STRING,
             left.buildVectorized(inputTypes),
             right.buildVectorized(inputTypes)
@@ -835,9 +845,9 @@ public class VectorProcessors
 
           @Override
           public void processIndex(
-              String[] leftInput,
+              Object[] leftInput,
               @Nullable boolean[] leftNulls,
-              String[] rightInput,
+              Object[] rightInput,
               @Nullable boolean[] rightNulls,
               int i
           )
@@ -851,17 +861,19 @@ public class VectorProcessors
                 outputNulls[i] = true;
                 return;
               }
-              final boolean bool = Evals.asBoolean(rightInput[i]);
+              final boolean bool = Evals.asBoolean((String) rightInput[i]);
               output[i] = Evals.asLong(bool);
               outputNulls[i] = bool;
               return;
             } else if (rightNull) {
-              final boolean bool = Evals.asBoolean(leftInput[i]);
+              final boolean bool = Evals.asBoolean((String) leftInput[i]);
               output[i] = Evals.asLong(bool);
               outputNulls[i] = bool;
               return;
             }
-            output[i] = Evals.asLong(Evals.asBoolean(leftInput[i]) && 
Evals.asBoolean(rightInput[i]));
+            output[i] = Evals.asLong(
+                Evals.asBoolean((String) leftInput[i]) && 
Evals.asBoolean((String) rightInput[i])
+            );
           }
 
           @Override
diff --git 
a/core/src/main/java/org/apache/druid/math/expr/vector/VectorStringProcessors.java
 
b/core/src/main/java/org/apache/druid/math/expr/vector/VectorStringProcessors.java
index 35c966a754..1ffaa2518d 100644
--- 
a/core/src/main/java/org/apache/druid/math/expr/vector/VectorStringProcessors.java
+++ 
b/core/src/main/java/org/apache/druid/math/expr/vector/VectorStringProcessors.java
@@ -20,6 +20,7 @@
 package org.apache.druid.math.expr.vector;
 
 import org.apache.druid.common.config.NullHandling;
+import org.apache.druid.math.expr.Evals;
 import org.apache.druid.math.expr.Expr;
 import org.apache.druid.math.expr.ExpressionType;
 
@@ -32,32 +33,35 @@ public class VectorStringProcessors
   {
     final ExprVectorProcessor processor;
     if (NullHandling.sqlCompatible()) {
-      processor = new StringOutStringsInFunctionVectorProcessor(
+      processor = new ObjectOutObjectsInFunctionVectorProcessor(
           left.buildVectorized(inspector),
           right.buildVectorized(inspector),
-          inspector.getMaxVectorSize()
+          inspector.getMaxVectorSize(),
+          ExpressionType.STRING
       )
       {
         @Nullable
         @Override
-        protected String processValue(@Nullable String leftVal, @Nullable 
String rightVal)
+        protected String processValue(@Nullable Object leftVal, @Nullable 
Object rightVal)
         {
           // in sql compatible mode, nulls are handled by super class and 
never make it here...
-          return leftVal + rightVal;
+          return leftVal + (String) rightVal;
         }
       };
     } else {
-      processor = new StringOutStringsInFunctionVectorProcessor(
+      processor = new ObjectOutObjectsInFunctionVectorProcessor(
           left.buildVectorized(inspector),
           right.buildVectorized(inspector),
-          inspector.getMaxVectorSize()
+          inspector.getMaxVectorSize(),
+          ExpressionType.STRING
       )
       {
         @Nullable
         @Override
-        protected String processValue(@Nullable String leftVal, @Nullable 
String rightVal)
+        protected Object processValue(@Nullable Object leftVal, @Nullable 
Object rightVal)
         {
-          return NullHandling.nullToEmptyIfNeeded(leftVal) + 
NullHandling.nullToEmptyIfNeeded(rightVal);
+          return NullHandling.nullToEmptyIfNeeded((String) leftVal)
+                 + NullHandling.nullToEmptyIfNeeded((String) rightVal);
         }
       };
     }
@@ -66,28 +70,32 @@ public class VectorStringProcessors
 
   public static <T> ExprVectorProcessor<T> 
concat(Expr.VectorInputBindingInspector inspector, List<Expr> inputs)
   {
-    final ExprVectorProcessor<String[]>[] inputProcessors = new 
ExprVectorProcessor[inputs.size()];
+    final ExprVectorProcessor<Object[]>[] inputProcessors = new 
ExprVectorProcessor[inputs.size()];
     for (int i = 0; i < inputs.size(); i++) {
-      inputProcessors[i] = 
CastToTypeVectorProcessor.cast(inputs.get(i).buildVectorized(inspector), 
ExpressionType.STRING);
+      inputProcessors[i] = CastToTypeVectorProcessor.cast(
+          inputs.get(i).buildVectorized(inspector),
+          ExpressionType.STRING
+      );
     }
-    final ExprVectorProcessor processor = new 
StringOutMultiStringInVectorProcessor(
+    final ExprVectorProcessor processor = new 
ObjectOutMultiObjectInVectorProcessor(
         inputProcessors,
-        inspector.getMaxVectorSize()
+        inspector.getMaxVectorSize(),
+        ExpressionType.STRING
     )
     {
       @Override
-      void processIndex(String[][] in, int i)
+      void processIndex(Object[][] in, int i)
       {
         // Result of concatenation is null if any of the Values is null.
         // e.g. 'select CONCAT(null, "abc") as c;' will return null as per 
Standard SQL spec.
-        String first = NullHandling.nullToEmptyIfNeeded(in[0][i]);
+        String first = 
NullHandling.nullToEmptyIfNeeded(Evals.asString(in[0][i]));
         if (first == null) {
           outValues[i] = null;
           return;
         }
         final StringBuilder builder = new StringBuilder(first);
         for (int inputNumber = 1; inputNumber < in.length; inputNumber++) {
-          final String s = 
NullHandling.nullToEmptyIfNeeded(in[inputNumber][i]);
+          final String s = 
NullHandling.nullToEmptyIfNeeded(Evals.asString(in[inputNumber][i]));
           if (s == null) {
             outValues[i] = null;
             return;
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/main/java/org/apache/druid/segment/column/StringDictionaryEncodedColumn.java
 
b/processing/src/main/java/org/apache/druid/segment/column/StringDictionaryEncodedColumn.java
index e24273f036..ba50991215 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/column/StringDictionaryEncodedColumn.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/column/StringDictionaryEncodedColumn.java
@@ -561,7 +561,7 @@ public class StringDictionaryEncodedColumn implements 
DictionaryEncodedColumn<St
       class DictionaryEncodedStringSingleValueVectorObjectSelector implements 
VectorObjectSelector
       {
         private final int[] vector = new int[offset.getMaxVectorSize()];
-        private final String[] strings = new String[offset.getMaxVectorSize()];
+        private final Object[] strings = new Object[offset.getMaxVectorSize()];
         private int id = ReadableVectorInspector.NULL_ID;
 
         @Override
diff --git 
a/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplier.java
 
b/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplier.java
index de7476bfbc..d3030c66f2 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplier.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplier.java
@@ -108,8 +108,14 @@ public class NestedFieldLiteralColumnIndexSupplier 
implements ColumnIndexSupplie
   public <T> T as(Class<T> clazz)
   {
     if (clazz.equals(NullValueIndex.class)) {
-      // null index is always 0 in the global dictionary, even if there are no 
null rows in any of the literal columns
-      return (T) (NullValueIndex) () -> new 
SimpleImmutableBitmapIndex(bitmaps.get(0));
+      final BitmapColumnIndex nullIndex;
+      if (dictionary.get(0) == 0) {
+        // null index is always 0 in the global dictionary, even if there are 
no null rows in any of the literal columns
+        nullIndex = new SimpleImmutableBitmapIndex(bitmaps.get(0));
+      } else {
+        nullIndex = new 
SimpleImmutableBitmapIndex(bitmapFactory.makeEmptyImmutableBitmap());
+      }
+      return (T) (NullValueIndex) () -> nullIndex;
     } else if (clazz.equals(DictionaryEncodedStringValueIndex.class) || 
clazz.equals(DictionaryEncodedValueIndex.class)) {
       return (T) new NestedLiteralDictionaryEncodedStringValueIndex();
     }
diff --git 
a/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVectorInputBinding.java
 
b/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVectorInputBinding.java
index 9e08749c0b..92c408a7cd 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVectorInputBinding.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVectorInputBinding.java
@@ -69,9 +69,9 @@ public class ExpressionVectorInputBinding implements 
Expr.VectorInputBinding
   }
 
   @Override
-  public <T> T[] getObjectVector(String name)
+  public Object[] getObjectVector(String name)
   {
-    return (T[]) objects.getOrDefault(name, nilSelector).getObjectVector();
+    return objects.getOrDefault(name, nilSelector).getObjectVector();
   }
 
   @Override
diff --git 
a/processing/src/main/java/org/apache/druid/segment/virtual/SingleStringInputDeferredEvaluationExpressionDimensionVectorSelector.java
 
b/processing/src/main/java/org/apache/druid/segment/virtual/SingleStringInputDeferredEvaluationExpressionDimensionVectorSelector.java
index 1cee307adb..4b88497294 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/virtual/SingleStringInputDeferredEvaluationExpressionDimensionVectorSelector.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/virtual/SingleStringInputDeferredEvaluationExpressionDimensionVectorSelector.java
@@ -20,6 +20,7 @@
 package org.apache.druid.segment.virtual;
 
 import org.apache.druid.java.util.common.ISE;
+import org.apache.druid.math.expr.Evals;
 import org.apache.druid.math.expr.Expr;
 import org.apache.druid.math.expr.ExpressionType;
 import org.apache.druid.math.expr.vector.ExprVectorProcessor;
@@ -43,7 +44,7 @@ public class 
SingleStringInputDeferredEvaluationExpressionDimensionVectorSelecto
     implements SingleValueDimensionVectorSelector
 {
   private final SingleValueDimensionVectorSelector selector;
-  private final ExprVectorProcessor<String[]> stringProcessor;
+  private final ExprVectorProcessor<Object[]> stringProcessor;
   private final StringLookupVectorInputBindings inputBinding;
 
   public SingleStringInputDeferredEvaluationExpressionDimensionVectorSelector(
@@ -75,7 +76,7 @@ public class 
SingleStringInputDeferredEvaluationExpressionDimensionVectorSelecto
   public String lookupName(int id)
   {
     inputBinding.currentValue[0] = selector.lookupName(id);
-    return stringProcessor.evalVector(inputBinding).values()[0];
+    return 
Evals.asString(stringProcessor.evalVector(inputBinding).values()[0]);
   }
 
   @Override
@@ -118,7 +119,7 @@ public class 
SingleStringInputDeferredEvaluationExpressionDimensionVectorSelecto
    */
   private static final class StringLookupVectorInputBindings implements 
Expr.VectorInputBinding
   {
-    private final String[] currentValue = new String[1];
+    private final Object[] currentValue = new Object[1];
 
     @Nullable
     @Override
diff --git 
a/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java
 
b/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java
index 3037201296..dac3295e3c 100644
--- 
a/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java
+++ 
b/processing/src/test/java/org/apache/druid/query/groupby/NestedDataGroupByQueryTest.java
@@ -35,12 +35,14 @@ import 
org.apache.druid.query.aggregation.AggregationTestHelper;
 import org.apache.druid.query.aggregation.CountAggregatorFactory;
 import org.apache.druid.query.aggregation.LongSumAggregatorFactory;
 import org.apache.druid.query.dimension.DefaultDimensionSpec;
+import org.apache.druid.query.expression.TestExprMacroTable;
 import org.apache.druid.query.filter.InDimFilter;
 import org.apache.druid.query.groupby.strategy.GroupByStrategySelector;
 import org.apache.druid.segment.Segment;
 import org.apache.druid.segment.column.ColumnType;
 import org.apache.druid.segment.column.RowSignature;
 import org.apache.druid.segment.column.ValueType;
+import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
 import org.apache.druid.segment.virtual.NestedFieldVirtualColumn;
 import org.apache.druid.testing.InitializedNullHandlingTest;
 import org.junit.After;
@@ -76,6 +78,8 @@ public class NestedDataGroupByQueryTest extends 
InitializedNullHandlingTest
   private final TrinaryFn<AggregationTestHelper, TemporaryFolder, Closer, 
List<Segment>> segmentsGenerator;
   private final String segmentsName;
 
+  private boolean cannotVectorize = false;
+
   public NestedDataGroupByQueryTest(
       GroupByQueryConfig config,
       TrinaryFn<AggregationTestHelper, TemporaryFolder, Closer, List<Segment>> 
segmentGenerator,
@@ -273,6 +277,46 @@ public class NestedDataGroupByQueryTest extends 
InitializedNullHandlingTest
     );
   }
 
+  @Test
+  public void testGroupByNonExistentVirtualColumn()
+  {
+    if 
(GroupByStrategySelector.STRATEGY_V1.equals(config.getDefaultStrategy())) {
+      expectedException.expect(RuntimeException.class);
+      expectedException.expectMessage(
+          "GroupBy v1 does not support dimension selectors with unknown 
cardinality."
+      );
+    }
+    GroupByQuery groupQuery = GroupByQuery.builder()
+                                          .setDataSource("test_datasource")
+                                          .setGranularity(Granularities.ALL)
+                                          .setInterval(Intervals.ETERNITY)
+                                          
.setDimensions(DefaultDimensionSpec.of("v1"))
+                                          .setVirtualColumns(
+                                              new 
NestedFieldVirtualColumn("fake", "$.fake", "v0", ColumnType.STRING),
+                                              new ExpressionVirtualColumn(
+                                                  "v1",
+                                                  "concat(v0, 'foo')",
+                                                  ColumnType.STRING,
+                                                  TestExprMacroTable.INSTANCE
+                                              )
+                                          )
+                                          .setAggregatorSpecs(new 
CountAggregatorFactory("count"))
+                                          .setContext(getContext())
+                                          .build();
+
+
+    Sequence<ResultRow> seq = 
helper.runQueryOnSegmentsObjs(segmentsGenerator.apply(helper, tempFolder, 
closer), groupQuery);
+
+    List<ResultRow> results = seq.toList();
+    verifyResults(
+        groupQuery.getResultRowSignature(),
+        results,
+        NullHandling.sqlCompatible()
+        ? ImmutableList.of(new Object[]{null, 16L})
+        : ImmutableList.of(new Object[]{"foo", 16L})
+    );
+  }
+
   private static void verifyResults(RowSignature rowSignature, List<ResultRow> 
results, List<Object[]> expected)
   {
     LOG.info("results:\n%s", results);
diff --git 
a/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplierTest.java
 
b/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplierTest.java
index b4d576ac04..850baf4412 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplierTest.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/nested/NestedFieldLiteralColumnIndexSupplierTest.java
@@ -128,6 +128,24 @@ public class NestedFieldLiteralColumnIndexSupplierTest 
extends InitializedNullHa
     globalDoubles = FixedIndexed.read(doubleBuffer, TypeStrategies.DOUBLE, 
ByteOrder.nativeOrder(), Double.BYTES);
   }
 
+  @Test
+  public void testSingleTypeStringColumnValueIndex() throws IOException
+  {
+    NestedFieldLiteralColumnIndexSupplier indexSupplier = 
makeSingleTypeStringSupplier();
+
+    NullValueIndex nullIndex = indexSupplier.as(NullValueIndex.class);
+    Assert.assertNotNull(nullIndex);
+
+    // 10 rows
+    // local: [b, foo, fooo, z]
+    // column: [foo, b, fooo, b, z, fooo, z, b, b, foo]
+
+    BitmapColumnIndex columnIndex = nullIndex.forNull();
+    Assert.assertNotNull(columnIndex);
+    Assert.assertEquals(0.0, columnIndex.estimateSelectivity(10), 0.0);
+    ImmutableBitmap bitmap = 
columnIndex.computeBitmapResult(bitmapResultFactory);
+    Assert.assertEquals(0, bitmap.size());
+  }
 
   @Test
   public void testSingleTypeStringColumnValueSetIndex() throws IOException
diff --git 
a/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorObjectSelectorTest.java
 
b/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorObjectSelectorTest.java
index 3fde333886..8773bbd6cd 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorObjectSelectorTest.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorObjectSelectorTest.java
@@ -20,7 +20,7 @@
 package org.apache.druid.segment.virtual;
 
 import org.apache.druid.math.expr.Expr;
-import org.apache.druid.math.expr.vector.ExprEvalStringVector;
+import org.apache.druid.math.expr.vector.ExprEvalObjectVector;
 import org.apache.druid.math.expr.vector.ExprEvalVector;
 import org.apache.druid.math.expr.vector.ExprVectorProcessor;
 import org.easymock.EasyMock;
@@ -57,7 +57,7 @@ public class ExpressionVectorObjectSelectorTest
   public void testSelectObject()
   {
     final String[] vector = new String[]{"1", "2", null, "3"};
-    ExprEvalVector vectorEval = new ExprEvalStringVector(vector);
+    ExprEvalVector vectorEval = new ExprEvalObjectVector(vector);
     EasyMock.expect(binding.getCurrentVectorId()).andReturn(1).anyTimes();
     
EasyMock.expect(vectorProcessor.evalVector(binding)).andReturn(vectorEval).once();
     EasyMock.replay(binding, vectorProcessor);
diff --git 
a/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorSelectorsTest.java
 
b/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorSelectorsTest.java
index c3e6a92850..8e0055d44c 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorSelectorsTest.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/virtual/ExpressionVectorSelectorsTest.java
@@ -43,6 +43,7 @@ import 
org.apache.druid.segment.vector.SingleValueDimensionVectorSelector;
 import org.apache.druid.segment.vector.VectorCursor;
 import org.apache.druid.segment.vector.VectorObjectSelector;
 import org.apache.druid.segment.vector.VectorValueSelector;
+import org.apache.druid.testing.InitializedNullHandlingTest;
 import org.apache.druid.timeline.DataSegment;
 import org.apache.druid.timeline.partition.LinearShardSpec;
 import org.junit.AfterClass;
@@ -60,7 +61,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 @RunWith(Parameterized.class)
-public class ExpressionVectorSelectorsTest
+public class ExpressionVectorSelectorsTest extends InitializedNullHandlingTest
 {
   private static List<String> EXPRESSIONS = ImmutableList.of(
       "long1 * long2",
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: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to