suneet-s commented on a change in pull request #11184:
URL: https://github.com/apache/druid/pull/11184#discussion_r670128506



##########
File path: core/src/test/java/org/apache/druid/math/expr/EvalTest.java
##########
@@ -372,4 +372,111 @@ public void testBooleanReturn()
     Assert.assertFalse(eval.asBoolean());
     Assert.assertEquals(ExprType.DOUBLE, eval.type());
   }
+
+  @Test
+  public void testLogicalOperators()
+  {
+    Expr.ObjectBinding bindings = InputBindings.withMap(
+        ImmutableMap.of()
+    );
+
+    Assert.assertEquals("true", eval("'true' && 'true'", bindings).value());
+    Assert.assertEquals("false", eval("'true' && 'false'", bindings).value());
+    Assert.assertEquals("false", eval("'false' && 'true'", bindings).value());
+    Assert.assertEquals("false", eval("'troo' && 'true'", bindings).value());
+    Assert.assertEquals("false", eval("'false' && 'false'", bindings).value());
+
+    Assert.assertEquals("true", eval("'true' || 'true'", bindings).value());
+    Assert.assertEquals("true", eval("'true' || 'false'", bindings).value());
+    Assert.assertEquals("true", eval("'false' || 'true'", bindings).value());
+    Assert.assertEquals("true", eval("'troo' || 'true'", bindings).value());
+    Assert.assertEquals("false", eval("'false' || 'false'", bindings).value());
+
+    Assert.assertEquals(1L, eval("1 && 1", bindings).value());
+    Assert.assertEquals(1L, eval("100 && 11", bindings).value());
+    Assert.assertEquals(0L, eval("1 && 0", bindings).value());
+    Assert.assertEquals(0L, eval("0 && 1", bindings).value());
+    Assert.assertEquals(0L, eval("0 && 0", bindings).value());
+
+    Assert.assertEquals(1L, eval("1 || 1", bindings).value());
+    Assert.assertEquals(1L, eval("100 || 11", bindings).value());
+    Assert.assertEquals(1L, eval("1 || 0", bindings).value());
+    Assert.assertEquals(1L, eval("0 || 1", bindings).value());
+    Assert.assertEquals(1L, eval("111 || 0", bindings).value());
+    Assert.assertEquals(1L, eval("0 || 111", bindings).value());
+    Assert.assertEquals(0L, eval("0 || 0", bindings).value());
+
+    Assert.assertEquals(1.0, eval("1.0 && 1.0", bindings).value());
+    Assert.assertEquals(1.0, eval("0.100 && 1.1", bindings).value());
+    Assert.assertEquals(0.0, eval("1.0 && 0.0", bindings).value());
+    Assert.assertEquals(0.0, eval("0.0 && 1.0", bindings).value());
+    Assert.assertEquals(0.0, eval("0.0 && 0.0", bindings).value());
+
+    Assert.assertEquals(1.0, eval("1.0 || 1.0", bindings).value());
+    Assert.assertEquals(1.0, eval("0.2 || 0.3", bindings).value());
+    Assert.assertEquals(1.0, eval("1.0 || 0.0", bindings).value());
+    Assert.assertEquals(1.0, eval("0.0 || 1.0", bindings).value());
+    Assert.assertEquals(1.0, eval("1.11 || 0.0", bindings).value());
+    Assert.assertEquals(1.0, eval("0.0 || 0.111", bindings).value());
+    Assert.assertEquals(0.0, eval("0.0 || 0.0", bindings).value());
+
+    Assert.assertEquals(1L, eval("null || 1", bindings).value());
+    Assert.assertEquals(1L, eval("1 || null", bindings).value());
+    Assert.assertEquals(NullHandling.defaultLongValue(), eval("null || 0", 
bindings).value());
+    Assert.assertEquals(NullHandling.defaultLongValue(), eval("0 || null", 
bindings).value());
+    // null/null is evaluated as string typed
+    Assert.assertEquals(null, eval("null || null", bindings).value());
+
+    Assert.assertEquals(NullHandling.defaultLongValue(), eval("null && 1", 
bindings).value());
+    Assert.assertEquals(NullHandling.defaultLongValue(), eval("1 && null", 
bindings).value());
+    Assert.assertEquals(0L, eval("null && 0", bindings).value());
+    Assert.assertEquals(0L, eval("0 && null", bindings).value());
+    // null/null is evaluated as string typed
+    Assert.assertEquals(null, eval("null && null", bindings).value());
+
+
+    // turn on legacy insanity mode
+    NullHandling.initializeForLegacyLogicalOperationsTests(true);
+    Assert.assertEquals(1L, eval("1 && 1", bindings).value());
+    Assert.assertEquals(11L, eval("100 && 11", bindings).value());
+    Assert.assertEquals(0L, eval("1 && 0", bindings).value());
+    Assert.assertEquals(0L, eval("0 && 1", bindings).value());
+    Assert.assertEquals(0L, eval("0 && 0", bindings).value());
+
+    Assert.assertEquals(1L, eval("1 || 1", bindings).value());
+    Assert.assertEquals(100L, eval("100 || 11", bindings).value());
+    Assert.assertEquals(1L, eval("1 || 0", bindings).value());
+    Assert.assertEquals(1L, eval("0 || 1", bindings).value());
+    Assert.assertEquals(111L, eval("111 || 0", bindings).value());
+    Assert.assertEquals(111L, eval("0 || 111", bindings).value());
+    Assert.assertEquals(0L, eval("0 || 0", bindings).value());
+
+    Assert.assertEquals(1.0, eval("1.0 && 1.0", bindings).value());
+    Assert.assertEquals(1.1, eval("0.100 && 1.1", bindings).value());
+    Assert.assertEquals(0.0, eval("1.0 && 0.0", bindings).value());
+    Assert.assertEquals(0.0, eval("0.0 && 1.0", bindings).value());
+    Assert.assertEquals(0.0, eval("0.0 && 0.0", bindings).value());
+
+    Assert.assertEquals(1.0, eval("1.0 || 1.0", bindings).value());
+    Assert.assertEquals(0.2, eval("0.2 || 0.3", bindings).value());
+    Assert.assertEquals(1.0, eval("1.0 || 0.0", bindings).value());
+    Assert.assertEquals(1.0, eval("0.0 || 1.0", bindings).value());
+    Assert.assertEquals(1.11, eval("1.11 || 0.0", bindings).value());
+    Assert.assertEquals(0.111, eval("0.0 || 0.111", bindings).value());
+    Assert.assertEquals(0.0, eval("0.0 || 0.0", bindings).value());
+
+    Assert.assertEquals(1L, eval("null || 1", bindings).value());
+    Assert.assertEquals(1L, eval("1 || null", bindings).value());
+    Assert.assertEquals(0L, eval("null || 0", bindings).value());
+    Assert.assertEquals(null, eval("0 || null", bindings).value());
+    Assert.assertEquals(null, eval("null || null", bindings).value());
+
+    Assert.assertEquals(null, eval("null && 1", bindings).value());
+    Assert.assertEquals(null, eval("1 && null", bindings).value());
+    Assert.assertEquals(null, eval("null && 0", bindings).value());
+    Assert.assertEquals(0L, eval("0 && null", bindings).value());
+    Assert.assertEquals(null, eval("null && null", bindings).value());
+    // reset
+    NullHandling.initializeForTests();

Review comment:
       I think you will want this in a try - finally block so that if 1 test 
fails here, it doesn't throw off any other tests that run in the JVM

##########
File path: core/src/main/java/org/apache/druid/math/expr/Expr.java
##########
@@ -222,6 +222,25 @@ default boolean areNumeric(Expr... args)
       return areNumeric(Arrays.asList(args));
     }
 
+    default boolean areSameTypes(List<Expr> args)
+    {
+      ExprType currentType = null;
+      boolean allSame = true;
+      for (Expr arg : args) {
+        ExprType argType = arg.getOutputType(this);
+        if (currentType == null) {
+          currentType = argType;
+        }
+        allSame &= argType == currentType;
+      }
+      return allSame;

Review comment:
       if I'm understanding this correctly - a constant expression of a string 
and a constant expression of null will not be considered the same type. Is this 
the behavior we want?
   
   I was thinking that a null could in theory be any type so `null && String` 
coulbe the same type

##########
File path: 
core/src/main/java/org/apache/druid/math/expr/vector/VectorProcessors.java
##########
@@ -135,6 +178,660 @@ public void processIndex(String[] strings, long[] longs, 
boolean[] outputNulls,
     return (ExprVectorProcessor<T>) processor;
   }
 
+  public static <T> ExprVectorProcessor<T> 
isNull(Expr.VectorInputBindingInspector inspector, Expr expr)
+  {
+
+    final ExprType type = expr.getOutputType(inspector);
+
+    if (type == null) {
+      return constant(1L, inspector.getMaxVectorSize());
+    }
+    final long[] outputValues = new long[inspector.getMaxVectorSize()];
+
+    ExprVectorProcessor<?> processor = null;
+    if (ExprType.STRING == type) {
+      final ExprVectorProcessor<String[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<String[]> inputEval = 
input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final String[] values = inputEval.values();
+          for (int i = 0; i < currentSize; i++) {
+            if (values[i] == null) {
+              outputValues[i] = 1L;
+            } else {
+              outputValues[i] = 0L;
+            }
+          }
+          return new ExprEvalLongVector(outputValues, null);
+        }
+
+        @Override
+        public ExprType getOutputType()
+        {
+          return ExprType.LONG;
+        }
+      };
+    } else if (ExprType.LONG == type) {
+      final ExprVectorProcessor<long[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<long[]> inputEval = input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final boolean[] nulls = inputEval.getNullVector();
+          for (int i = 0; i < currentSize; i++) {
+            if (nulls != null && nulls[i]) {
+              outputValues[i] = 1L;
+            } else {
+              outputValues[i] = 0L;
+            }
+          }
+          return new ExprEvalLongVector(outputValues, null);
+        }
+
+        @Override
+        public ExprType getOutputType()
+        {
+          return ExprType.LONG;
+        }
+      };
+    } else if (ExprType.DOUBLE == type) {
+      final ExprVectorProcessor<double[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<double[]> inputEval = 
input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final boolean[] nulls = inputEval.getNullVector();
+          for (int i = 0; i < currentSize; i++) {
+            if (nulls != null && nulls[i]) {
+              outputValues[i] = 1L;
+            } else {
+              outputValues[i] = 0L;
+            }
+          }
+          return new ExprEvalLongVector(outputValues, null);
+        }
+
+        @Override
+        public ExprType getOutputType()
+        {
+          return ExprType.LONG;
+        }
+      };
+    }
+
+    if (processor == null) {
+      throw Exprs.cannotVectorize();
+    }
+    return (ExprVectorProcessor<T>) processor;
+  }
+
+  public static <T> ExprVectorProcessor<T> 
isNotNull(Expr.VectorInputBindingInspector inspector, Expr expr)
+  {
+
+    final ExprType type = expr.getOutputType(inspector);
+    if (type == null) {
+      return constant(0L, inspector.getMaxVectorSize());
+    }
+
+    final long[] outputValues = new long[inspector.getMaxVectorSize()];
+
+    ExprVectorProcessor<?> processor = null;
+    if (ExprType.STRING == type) {
+      final ExprVectorProcessor<String[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<String[]> inputEval = 
input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final String[] values = inputEval.values();
+          for (int i = 0; i < currentSize; i++) {
+            if (values[i] == null) {
+              outputValues[i] = 0L;
+            } else {
+              outputValues[i] = 1L;
+            }
+          }
+          return new ExprEvalLongVector(outputValues, null);
+        }
+
+        @Override
+        public ExprType getOutputType()
+        {
+          return ExprType.LONG;
+        }
+      };
+    } else if (ExprType.LONG == type) {
+      final ExprVectorProcessor<long[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<long[]> inputEval = input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final boolean[] nulls = inputEval.getNullVector();
+          for (int i = 0; i < currentSize; i++) {
+            if (nulls != null && nulls[i]) {
+              outputValues[i] = 0L;
+            } else {
+              outputValues[i] = 1L;
+            }
+          }
+          return new ExprEvalLongVector(outputValues, null);
+        }
+
+        @Override
+        public ExprType getOutputType()
+        {
+          return ExprType.LONG;
+        }
+      };
+    } else if (ExprType.DOUBLE == type) {
+      final ExprVectorProcessor<double[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<double[]> inputEval = 
input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final boolean[] nulls = inputEval.getNullVector();
+          for (int i = 0; i < currentSize; i++) {
+            if (nulls != null && nulls[i]) {
+              outputValues[i] = 0L;
+            } else {
+              outputValues[i] = 1L;
+            }
+          }
+          return new ExprEvalLongVector(outputValues, null);
+        }
+
+        @Override
+        public ExprType getOutputType()
+        {
+          return ExprType.LONG;
+        }
+      };
+    }
+
+    if (processor == null) {
+      throw Exprs.cannotVectorize();
+    }
+    return (ExprVectorProcessor<T>) processor;
+  }
+
+  public static <T> ExprVectorProcessor<T> 
nvl(Expr.VectorInputBindingInspector inspector, Expr left, Expr right)
+  {
+    final int maxVectorSize = inspector.getMaxVectorSize();
+
+    return makeSymmetricalProcessor(
+        inspector,
+        left,
+        right,
+        () -> new SymmetricalBivariateFunctionVectorProcessor<long[]>(
+            ExprType.LONG,
+            left.buildVectorized(inspector),
+            right.buildVectorized(inspector)
+        )
+        {
+          final long[] output = new long[maxVectorSize];
+          final boolean[] outputNulls = new boolean[maxVectorSize];
+
+          @Override
+          public void processIndex(
+              long[] leftInput,
+              @Nullable boolean[] leftNulls,
+              long[] rightInput,
+              @Nullable boolean[] rightNulls,
+              int i
+          )
+          {
+            if (leftNulls != null && leftNulls[i]) {
+              if (rightNulls != null) {
+                output[i] = rightNulls[i] ? 0L : rightInput[i];
+                outputNulls[i] = rightNulls[i];
+              } else {
+                output[i] = rightInput[i];
+              }
+            } else {
+              output[i] = leftInput[i];
+            }
+          }
+
+          @Override
+          public ExprEvalVector<long[]> asEval()
+          {
+            return new ExprEvalLongVector(output, outputNulls);
+          }
+        },
+        () -> new SymmetricalBivariateFunctionVectorProcessor<double[]>(
+            ExprType.DOUBLE,
+            left.buildVectorized(inspector),
+            right.buildVectorized(inspector)
+        )
+        {
+          final double[] output = new double[maxVectorSize];
+          final boolean[] outputNulls = new boolean[maxVectorSize];
+
+          @Override
+          public void processIndex(
+              double[] leftInput,
+              @Nullable boolean[] leftNulls,
+              double[] rightInput,
+              @Nullable boolean[] rightNulls,
+              int i
+          )
+          {
+            if (leftNulls != null && leftNulls[i]) {
+              if (rightNulls != null) {
+                output[i] = rightNulls[i] ? 0.0 : rightInput[i];
+                outputNulls[i] = rightNulls[i];
+              } else {
+                output[i] = rightInput[i];
+              }
+            } else {
+              output[i] = leftInput[i];
+            }
+          }
+
+          @Override
+          public ExprEvalVector<double[]> asEval()
+          {
+            return new ExprEvalDoubleVector(output, outputNulls);
+          }
+        },
+        () -> new SymmetricalBivariateFunctionVectorProcessor<String[]>(
+            ExprType.STRING,
+            left.buildVectorized(inspector),
+            right.buildVectorized(inspector)
+        )
+        {
+          final String[] output = new String[maxVectorSize];
+
+          @Override
+          public void processIndex(
+              String[] leftInput,
+              @Nullable boolean[] leftNulls,
+              String[] rightInput,
+              @Nullable boolean[] rightNulls,
+              int i
+          )
+          {
+            output[i] = leftInput[i] != null ? leftInput[i] : rightInput[i];
+          }
+
+          @Override
+          public ExprEvalVector<String[]> asEval()
+          {
+            return new ExprEvalStringVector(output);
+          }
+        }
+    );
+  }
+
+  public static <T> ExprVectorProcessor<T> 
not(Expr.VectorInputBindingInspector inspector, Expr expr)
+  {
+    final ExprType inputType = expr.getOutputType(inspector);
+    final int maxVectorSize = inspector.getMaxVectorSize();
+    ExprVectorProcessor<?> processor = null;
+    if (ExprType.STRING.equals(inputType)) {
+      processor = new 
LongOutStringInFunctionVectorProcessor(expr.buildVectorized(inspector), 
maxVectorSize)
+      {
+        @Override
+        public void processIndex(String[] strings, long[] longs, boolean[] 
outputNulls, int i)
+        {
+          outputNulls[i] = strings[i] == null;
+          if (!outputNulls[i]) {
+            longs[i] = Evals.asLong(!Evals.asBoolean(strings[i]));
+          }
+        }
+      };
+    } else if (ExprType.LONG.equals(inputType)) {
+      processor = new 
LongOutLongInFunctionVectorValueProcessor(expr.buildVectorized(inspector), 
maxVectorSize)
+      {
+        @Override
+        public long apply(long input)
+        {
+          return Evals.asLong(!Evals.asBoolean(input));
+        }
+      };
+    } else if (ExprType.DOUBLE.equals(inputType)) {
+      processor = new 
DoubleOutDoubleInFunctionVectorValueProcessor(expr.buildVectorized(inspector), 
maxVectorSize)
+      {
+        @Override
+        public double apply(double input)
+        {
+          return Evals.asDouble(!Evals.asBoolean(input));
+        }
+      };
+    }
+    if (processor == null) {
+      throw Exprs.cannotVectorize();
+    }
+    return (ExprVectorProcessor<T>) processor;
+  }
+
+  public static <T> ExprVectorProcessor<T> or(Expr.VectorInputBindingInspector 
inspector, Expr left, Expr right)
+  {
+    final int maxVectorSize = inspector.getMaxVectorSize();
+    return makeSymmetricalProcessor(
+        inspector,
+        left,
+        right,
+        () -> new SymmetricalBivariateFunctionVectorProcessor<long[]>(
+            ExprType.LONG,
+            left.buildVectorized(inspector),
+            right.buildVectorized(inspector)
+        )
+        {
+          final long[] output = new long[maxVectorSize];
+          final boolean[] outputNulls = new boolean[maxVectorSize];
+
+          @Override
+          public void processIndex(
+              long[] leftInput,
+              @Nullable boolean[] leftNulls,
+              long[] rightInput,
+              @Nullable boolean[] rightNulls,
+              int i
+          )
+          {
+            if (NullHandling.sqlCompatible()) {
+              // true/null, null/true, null/null -> true
+              // false/null, null/false -> null

Review comment:
       It seems like this comment doesn't match the implementation
   
   `null /null -> null` which is what's described in `docs/misc/math-expr.md` 
but this comment says it should be true.

##########
File path: docs/misc/math-expr.md
##########
@@ -254,7 +256,34 @@ supported features:
 * constants and identifiers are supported for any column type
 * `cast` is supported for numeric and string types
 * math operators: `+`,`-`,`*`,`/`,`%`,`^` are supported for numeric types
-* comparison operators: `=`, `!=`, `>`, `>=`, `<`, `<=` are supported for 
numeric types
+* logical operators: `!`, `&&`, `||`, are supported for string and numeric 
types
+* comparison operators: `=`, `!=`, `>`, `>=`, `<`, `<=` are supported for 
string and numeric types
 * math functions: `abs`, `acos`, `asin`, `atan`, `cbrt`, `ceil`, `cos`, 
`cosh`, `cot`, `exp`, `expm1`, `floor`, `getExponent`, `log`, `log10`, `log1p`, 
`nextUp`, `rint`, `signum`, `sin`, `sinh`, `sqrt`, `tan`, `tanh`, `toDegrees`, 
`toRadians`, `ulp`, `atan2`, `copySign`, `div`, `hypot`, `max`, `min`, 
`nextAfter`,  `pow`, `remainder`, `scalb` are supported for numeric types
 * time functions: `timestamp_floor` (with constant granularity argument) is 
supported for numeric types
+* boolean functions: `isnull`, `notnull` are supported for string and numeric 
types
+* conditional functions: `nvl` is supported for string and numeric types
+* string functions: the concatenation operator (`+`) and `concat` function are 
supported for string and numeric types
 * other: `parse_long` is supported for numeric and string types
+
+## Legacy logical operator mode
+In earlier releases of Druid, the logical 'and' and 'or' operators behaved in 
a non-standard manner, but this behavior has been changed so that these 
operations output 'homogeneous' boolean values.

Review comment:
       nit: Perhaps we can be more specific about which version.
   ```suggestion
   Prior to the 0.22 release of Apache Druid, the logical 'and' and 'or' 
operators behaved in a non-standard manner, but this behavior has been changed 
so that these operations output 'homogeneous' boolean values.
   ```

##########
File path: 
core/src/main/java/org/apache/druid/math/expr/vector/VectorProcessors.java
##########
@@ -135,6 +178,660 @@ public void processIndex(String[] strings, long[] longs, 
boolean[] outputNulls,
     return (ExprVectorProcessor<T>) processor;
   }
 
+  public static <T> ExprVectorProcessor<T> 
isNull(Expr.VectorInputBindingInspector inspector, Expr expr)
+  {
+
+    final ExprType type = expr.getOutputType(inspector);
+
+    if (type == null) {
+      return constant(1L, inspector.getMaxVectorSize());
+    }
+    final long[] outputValues = new long[inspector.getMaxVectorSize()];
+
+    ExprVectorProcessor<?> processor = null;
+    if (ExprType.STRING == type) {
+      final ExprVectorProcessor<String[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<String[]> inputEval = 
input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final String[] values = inputEval.values();
+          for (int i = 0; i < currentSize; i++) {
+            if (values[i] == null) {
+              outputValues[i] = 1L;
+            } else {
+              outputValues[i] = 0L;
+            }
+          }
+          return new ExprEvalLongVector(outputValues, null);
+        }
+
+        @Override
+        public ExprType getOutputType()
+        {
+          return ExprType.LONG;
+        }
+      };
+    } else if (ExprType.LONG == type) {
+      final ExprVectorProcessor<long[]> input = 
expr.buildVectorized(inspector);
+      processor = new ExprVectorProcessor<long[]>()
+      {
+        @Override
+        public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding 
bindings)
+        {
+          final ExprEvalVector<long[]> inputEval = input.evalVector(bindings);
+
+          final int currentSize = bindings.getCurrentVectorSize();
+          final boolean[] nulls = inputEval.getNullVector();
+          for (int i = 0; i < currentSize; i++) {
+            if (nulls != null && nulls[i]) {

Review comment:
       nit: is the optimizer smart enough to optimize this to
   ```suggestion
             for (int i = 0; nulls !=null && i < currentSize; i++) {
               if (nulls[i]) {
   ```
   
   since if `nulls == null` we don't have to iterate over the list because long 
arrays default to 0L iirc.
   Similar comment elsewhere this pattern is used




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to