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

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


The following commit(s) were added to refs/heads/master by this push:
     new 974e1ea01f Cleanup null value handling in data table (#9429)
974e1ea01f is described below

commit 974e1ea01f1d2635e2343473b089048139024bd6
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Mon Sep 19 16:12:21 2022 -0700

    Cleanup null value handling in data table (#9429)
---
 .../org/apache/pinot/common/utils/DataSchema.java  |  69 +++++++------
 .../blocks/results/AggregationResultsBlock.java    |  14 +--
 .../blocks/results/GroupByResultsBlock.java        |   9 +-
 .../function/CoalesceTransformFunction.java        |  82 ++++++++-------
 .../pinot/core/query/distinct/DistinctTable.java   |  10 +-
 .../query/selection/SelectionOperatorUtils.java    |  13 +--
 .../function/CoalesceTransformFunctionTest.java    | 111 ++++++++++-----------
 .../org/apache/pinot/spi/utils/NullValueUtils.java |  46 ---------
 8 files changed, 157 insertions(+), 197 deletions(-)

diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/DataSchema.java 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/DataSchema.java
index d8a6fa5cf8..4370e7623a 100644
--- a/pinot-common/src/main/java/org/apache/pinot/common/utils/DataSchema.java
+++ b/pinot-common/src/main/java/org/apache/pinot/common/utils/DataSchema.java
@@ -51,9 +51,9 @@ public class DataSchema {
 
   /** Used by both Broker and Server to generate results for EXPLAIN PLAN 
queries. */
   public static final DataSchema EXPLAIN_RESULT_SCHEMA =
-      new DataSchema(new String[]{"Operator", "Operator_Id", "Parent_Id"},
-          new DataSchema.ColumnDataType[]{DataSchema.ColumnDataType.STRING, 
DataSchema.ColumnDataType.INT,
-              DataSchema.ColumnDataType.INT});
+      new DataSchema(new String[]{"Operator", "Operator_Id", "Parent_Id"}, new 
ColumnDataType[]{
+          ColumnDataType.STRING, ColumnDataType.INT, ColumnDataType.INT
+      });
 
   @JsonCreator
   public DataSchema(@JsonProperty("columnNames") String[] columnNames,
@@ -228,8 +228,8 @@ public class DataSchema {
     }
     if (anObject instanceof DataSchema) {
       DataSchema anotherDataSchema = (DataSchema) anObject;
-      return Arrays.equals(_columnNames, anotherDataSchema._columnNames) && 
Arrays
-          .equals(_columnDataTypes, anotherDataSchema._columnDataTypes);
+      return Arrays.equals(_columnNames, anotherDataSchema._columnNames) && 
Arrays.equals(_columnDataTypes,
+          anotherDataSchema._columnDataTypes);
     }
     return false;
   }
@@ -240,33 +240,46 @@ public class DataSchema {
   }
 
   public enum ColumnDataType {
-    INT,
-    LONG,
-    FLOAT,
-    DOUBLE,
-    BIG_DECIMAL,
-    BOOLEAN /* Stored as INT */,
-    TIMESTAMP /* Stored as LONG */,
-    STRING,
-    JSON /* Stored as STRING */,
-    BYTES,
-    OBJECT,
-    INT_ARRAY,
-    LONG_ARRAY,
-    FLOAT_ARRAY,
-    DOUBLE_ARRAY,
-    BOOLEAN_ARRAY /* Stored as INT_ARRAY */,
-    TIMESTAMP_ARRAY /* Stored as LONG_ARRAY */,
-    STRING_ARRAY,
-    BYTES_ARRAY;
+    INT(0),
+    LONG(0L),
+    FLOAT(0f),
+    DOUBLE(0d),
+    BIG_DECIMAL(BigDecimal.ZERO),
+    BOOLEAN(0) /* Stored as INT */,
+    TIMESTAMP(0L) /* Stored as LONG */,
+    STRING(""),
+    JSON("") /* Stored as STRING */,
+    BYTES(new ByteArray(new byte[0])),
+    OBJECT(null),
+    INT_ARRAY(new int[0]),
+    LONG_ARRAY(new long[0]),
+    FLOAT_ARRAY(new float[0]),
+    DOUBLE_ARRAY(new double[0]),
+    BOOLEAN_ARRAY(new int[0]) /* Stored as INT_ARRAY */,
+    TIMESTAMP_ARRAY(new long[0]) /* Stored as LONG_ARRAY */,
+    STRING_ARRAY(new String[0]),
+    BYTES_ARRAY(new byte[0][]);
 
     private static final EnumSet<ColumnDataType> NUMERIC_TYPES = 
EnumSet.of(INT, LONG, FLOAT, DOUBLE, BIG_DECIMAL);
     private static final EnumSet<ColumnDataType> INTEGRAL_TYPES = 
EnumSet.of(INT, LONG);
-    private static final EnumSet<ColumnDataType> ARRAY_TYPES = 
EnumSet.of(INT_ARRAY, LONG_ARRAY, FLOAT_ARRAY,
-        DOUBLE_ARRAY, STRING_ARRAY, BOOLEAN_ARRAY, TIMESTAMP_ARRAY, 
BYTES_ARRAY);
-    private static final EnumSet<ColumnDataType> NUMERIC_ARRAY_TYPES = 
EnumSet.of(INT_ARRAY, LONG_ARRAY, FLOAT_ARRAY,
-        DOUBLE_ARRAY);
+    private static final EnumSet<ColumnDataType> ARRAY_TYPES =
+        EnumSet.of(INT_ARRAY, LONG_ARRAY, FLOAT_ARRAY, DOUBLE_ARRAY, 
STRING_ARRAY, BOOLEAN_ARRAY, TIMESTAMP_ARRAY,
+            BYTES_ARRAY);
+    private static final EnumSet<ColumnDataType> NUMERIC_ARRAY_TYPES =
+        EnumSet.of(INT_ARRAY, LONG_ARRAY, FLOAT_ARRAY, DOUBLE_ARRAY);
     private static final EnumSet<ColumnDataType> INTEGRAL_ARRAY_TYPES = 
EnumSet.of(INT_ARRAY, LONG_ARRAY);
+
+    // Placeholder for null. We need a placeholder for null so that it can be 
serialized in the data table
+    private final Object _nullPlaceholder;
+
+    ColumnDataType(Object nullPlaceHolder) {
+      _nullPlaceholder = nullPlaceHolder;
+    }
+
+    public Object getNullPlaceholder() {
+      return _nullPlaceholder;
+    }
+
     /**
      * Returns the data type stored in Pinot.
      */
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/AggregationResultsBlock.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/AggregationResultsBlock.java
index bba0c6df61..02da5baf44 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/AggregationResultsBlock.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/AggregationResultsBlock.java
@@ -30,7 +30,6 @@ import 
org.apache.pinot.core.common.datatable.DataTableFactory;
 import org.apache.pinot.core.query.aggregation.function.AggregationFunction;
 import org.apache.pinot.core.query.request.context.QueryContext;
 import org.apache.pinot.spi.utils.ByteArray;
-import org.apache.pinot.spi.utils.NullValueUtils;
 import org.roaringbitmap.RoaringBitmap;
 
 
@@ -82,18 +81,13 @@ public class AggregationResultsBlock extends 
BaseResultsBlock {
       dataTableBuilder.startRow();
       for (int i = 0; i < numColumns; i++) {
         Object result = _results.get(i);
+        if (result == null) {
+          result = columnDataTypes[i].getNullPlaceholder();
+          nullBitmaps[i].add(0);
+        }
         if (!returnFinalResult) {
-          if (result == null && columnDataTypes[i] != ColumnDataType.OBJECT) {
-            result = 
NullValueUtils.getDefaultNullValue(columnDataTypes[i].toDataType());
-            nullBitmaps[i].add(0);
-          }
           setIntermediateResult(dataTableBuilder, columnDataTypes, i, result);
         } else {
-          result = _aggregationFunctions[i].extractFinalResult(result);
-          if (result == null) {
-            result = 
NullValueUtils.getDefaultNullValue(columnDataTypes[i].toDataType());
-            nullBitmaps[i].add(0);
-          }
           setFinalResult(dataTableBuilder, columnDataTypes, i, result);
         }
       }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/GroupByResultsBlock.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/GroupByResultsBlock.java
index 1d0a7c5089..3e5c534a65 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/GroupByResultsBlock.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/blocks/results/GroupByResultsBlock.java
@@ -37,7 +37,6 @@ import org.apache.pinot.core.data.table.Table;
 import 
org.apache.pinot.core.query.aggregation.groupby.AggregationGroupByResult;
 import org.apache.pinot.core.query.request.context.QueryContext;
 import org.apache.pinot.spi.utils.ByteArray;
-import org.apache.pinot.spi.utils.NullValueUtils;
 import org.roaringbitmap.RoaringBitmap;
 
 
@@ -134,12 +133,10 @@ public class GroupByResultsBlock extends BaseResultsBlock 
{
     Iterator<Record> iterator = _table.iterator();
     if (queryContext.isNullHandlingEnabled()) {
       RoaringBitmap[] nullBitmaps = new RoaringBitmap[numColumns];
-      Object[] defaultNullValues = new Object[numColumns];
+      Object[] nullPlaceholders = new Object[numColumns];
       for (int colId = 0; colId < numColumns; colId++) {
         nullBitmaps[colId] = new RoaringBitmap();
-        if (storedColumnDataTypes[colId] != ColumnDataType.OBJECT) {
-          defaultNullValues[colId] = 
NullValueUtils.getDefaultNullValue(storedColumnDataTypes[colId].toDataType());
-        }
+        nullPlaceholders[colId] = 
storedColumnDataTypes[colId].getNullPlaceholder();
       }
       int rowId = 0;
       while (iterator.hasNext()) {
@@ -148,7 +145,7 @@ public class GroupByResultsBlock extends BaseResultsBlock {
         for (int colId = 0; colId < numColumns; colId++) {
           Object value = values[colId];
           if (value == null && storedColumnDataTypes[colId] != 
ColumnDataType.OBJECT) {
-            value = defaultNullValues[colId];
+            value = nullPlaceholders[colId];
             nullBitmaps[colId].add(rowId);
           }
           setDataTableColumn(storedColumnDataTypes[colId], dataTableBuilder, 
colId, value);
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunction.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunction.java
index dfc45a8036..0019c49305 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunction.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunction.java
@@ -26,8 +26,7 @@ import org.apache.pinot.common.function.TransformFunctionType;
 import org.apache.pinot.core.operator.blocks.ProjectionBlock;
 import org.apache.pinot.core.operator.transform.TransformResultMetadata;
 import org.apache.pinot.segment.spi.datasource.DataSource;
-import org.apache.pinot.spi.data.FieldSpec;
-import org.apache.pinot.spi.utils.NullValueUtils;
+import org.apache.pinot.spi.data.FieldSpec.DataType;
 import org.roaringbitmap.RoaringBitmap;
 
 
@@ -49,8 +48,15 @@ import org.roaringbitmap.RoaringBitmap;
  *    Coalesce(columnA, columnB)
  */
 public class CoalesceTransformFunction extends BaseTransformFunction {
+  public static final int NULL_INT = Integer.MIN_VALUE;
+  public static final long NULL_LONG = Long.MIN_VALUE;
+  public static final float NULL_FLOAT = Float.NEGATIVE_INFINITY;
+  public static final double NULL_DOUBLE = Double.NEGATIVE_INFINITY;
+  public static final BigDecimal NULL_BIG_DECIMAL = 
BigDecimal.valueOf(Long.MIN_VALUE);
+  public static final String NULL_STRING = "null";
+
   private TransformFunction[] _transformFunctions;
-  private FieldSpec.DataType _storedType;
+  private DataType _dataType;
   private TransformResultMetadata _resultMetadata;
 
   /**
@@ -96,7 +102,7 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
         break;
       }
       if (!hasNonNullValue) {
-        results[i] = (int) NullValueUtils.getDefaultNullValue(_storedType);
+        results[i] = NULL_INT;
       }
     }
     return results;
@@ -129,7 +135,7 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
         break;
       }
       if (!hasNonNullValue) {
-        results[i] = (long) NullValueUtils.getDefaultNullValue(_storedType);
+        results[i] = NULL_LONG;
       }
     }
     return results;
@@ -162,7 +168,7 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
         break;
       }
       if (!hasNonNullValue) {
-        results[i] = (float) NullValueUtils.getDefaultNullValue(_storedType);
+        results[i] = NULL_FLOAT;
       }
     }
     return results;
@@ -172,7 +178,7 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
    * Get transform double results based on store type.
    * @param projectionBlock
    */
-  private double[] getDoublelTransformResults(ProjectionBlock projectionBlock) 
{
+  private double[] getDoubleTransformResults(ProjectionBlock projectionBlock) {
     int length = projectionBlock.getNumDocs();
     double[] results = new double[length];
     int width = _transformFunctions.length;
@@ -195,7 +201,7 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
         break;
       }
       if (!hasNonNullValue) {
-        results[i] = (double) NullValueUtils.getDefaultNullValue(_storedType);
+        results[i] = NULL_DOUBLE;
       }
     }
     return results;
@@ -228,13 +234,12 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
         break;
       }
       if (!hasNonNullValue) {
-        results[i] = (BigDecimal) 
NullValueUtils.getDefaultNullValue(_storedType);
+        results[i] = NULL_BIG_DECIMAL;
       }
     }
     return results;
   }
 
-
   /**
    * Get transform String results based on store type.
    * @param projectionBlock
@@ -262,7 +267,7 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
         break;
       }
       if (!hasNonNullValue) {
-        results[i] = (String) NullValueUtils.getDefaultNullValue(_storedType);
+        results[i] = NULL_STRING;
       }
     }
     return results;
@@ -282,15 +287,16 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
       TransformFunction func = arguments.get(i);
       Preconditions.checkArgument(func instanceof IdentifierTransformFunction,
           "Only column names are supported in COALESCE.");
-      FieldSpec.DataType storedType = 
func.getResultMetadata().getDataType().getStoredType();
-      if (_storedType == null) {
-        _storedType = storedType;
+      DataType dataType = func.getResultMetadata().getDataType();
+      if (_dataType == null) {
+        _dataType = dataType;
       } else {
-        Preconditions.checkArgument(storedType.equals(_storedType), "Argument 
types have to be the same.");
+        Preconditions.checkArgument(dataType == _dataType, "Argument types 
have to be the same.");
       }
       _transformFunctions[i] = func;
     }
-    switch (_storedType) {
+    // TODO: Support BOOLEAN, TIMESTAMP, BYTES
+    switch (_dataType) {
       case INT:
         _resultMetadata = INT_SV_NO_DICTIONARY_METADATA;
         break;
@@ -319,17 +325,9 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
     return _resultMetadata;
   }
 
-  @Override
-  public String[] transformToStringValuesSV(ProjectionBlock projectionBlock) {
-    if (_storedType != FieldSpec.DataType.STRING) {
-      return super.transformToStringValuesSV(projectionBlock);
-    }
-    return getStringTransformResults(projectionBlock);
-  }
-
   @Override
   public int[] transformToIntValuesSV(ProjectionBlock projectionBlock) {
-    if (_storedType != FieldSpec.DataType.INT) {
+    if (_dataType != DataType.INT) {
       return super.transformToIntValuesSV(projectionBlock);
     }
     return getIntTransformResults(projectionBlock);
@@ -337,33 +335,45 @@ public class CoalesceTransformFunction extends 
BaseTransformFunction {
 
   @Override
   public long[] transformToLongValuesSV(ProjectionBlock projectionBlock) {
-    if (_storedType != FieldSpec.DataType.LONG) {
+    if (_dataType != DataType.LONG) {
       return super.transformToLongValuesSV(projectionBlock);
     }
     return getLongTransformResults(projectionBlock);
   }
 
   @Override
-  public BigDecimal[] transformToBigDecimalValuesSV(ProjectionBlock 
projectionBlock) {
-    if (_storedType != FieldSpec.DataType.BIG_DECIMAL) {
-      return super.transformToBigDecimalValuesSV(projectionBlock);
+  public float[] transformToFloatValuesSV(ProjectionBlock projectionBlock) {
+    if (_dataType != DataType.FLOAT) {
+      return super.transformToFloatValuesSV(projectionBlock);
     }
-    return getBigDecimalTransformResults(projectionBlock);
+    return getFloatTransformResults(projectionBlock);
   }
 
   @Override
   public double[] transformToDoubleValuesSV(ProjectionBlock projectionBlock) {
-    if (_storedType != FieldSpec.DataType.DOUBLE) {
+    if (_dataType != DataType.DOUBLE) {
       return super.transformToDoubleValuesSV(projectionBlock);
     }
-    return getDoublelTransformResults(projectionBlock);
+    return getDoubleTransformResults(projectionBlock);
   }
 
   @Override
-  public float[] transformToFloatValuesSV(ProjectionBlock projectionBlock) {
-    if (_storedType != FieldSpec.DataType.FLOAT) {
-      return super.transformToFloatValuesSV(projectionBlock);
+  public BigDecimal[] transformToBigDecimalValuesSV(ProjectionBlock 
projectionBlock) {
+    if (_dataType != DataType.BIG_DECIMAL) {
+      return super.transformToBigDecimalValuesSV(projectionBlock);
     }
-    return getFloatTransformResults(projectionBlock);
+    return getBigDecimalTransformResults(projectionBlock);
+  }
+
+  @Override
+  public String[] transformToStringValuesSV(ProjectionBlock projectionBlock) {
+    if (_dataType != DataType.STRING) {
+      return super.transformToStringValuesSV(projectionBlock);
+    }
+    return getStringTransformResults(projectionBlock);
+  }
+
+  public static void main(String[] args) {
+    System.out.println(BigDecimal.valueOf(Long.MIN_VALUE));
   }
 }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctTable.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctTable.java
index 49e85a5a2d..8a8dddf308 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctTable.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/query/distinct/DistinctTable.java
@@ -40,7 +40,6 @@ import 
org.apache.pinot.core.common.datatable.DataTableBuilder;
 import org.apache.pinot.core.common.datatable.DataTableFactory;
 import org.apache.pinot.core.data.table.Record;
 import org.apache.pinot.spi.utils.ByteArray;
-import org.apache.pinot.spi.utils.NullValueUtils;
 import org.roaringbitmap.RoaringBitmap;
 
 
@@ -277,16 +276,15 @@ public class DistinctTable {
   public byte[] toBytes()
       throws IOException {
     // NOTE: Serialize the DistinctTable as a DataTable
-    DataTableBuilder dataTableBuilder = DataTableFactory.getDataTableBuilder(
-        _dataSchema);
+    DataTableBuilder dataTableBuilder = 
DataTableFactory.getDataTableBuilder(_dataSchema);
     ColumnDataType[] storedColumnDataTypes = 
_dataSchema.getStoredColumnDataTypes();
     int numColumns = storedColumnDataTypes.length;
     RoaringBitmap[] nullBitmaps = null;
     if (_nullHandlingEnabled) {
       nullBitmaps = new RoaringBitmap[numColumns];
-      Object[] colDefaultNullValues = new Object[numColumns];
+      Object[] nullPlaceholders = new Object[numColumns];
       for (int colId = 0; colId < numColumns; colId++) {
-        colDefaultNullValues[colId] = 
NullValueUtils.getDefaultNullValue(storedColumnDataTypes[colId].toDataType());
+        nullPlaceholders[colId] = 
storedColumnDataTypes[colId].getNullPlaceholder();
         nullBitmaps[colId] = new RoaringBitmap();
       }
 
@@ -295,7 +293,7 @@ public class DistinctTable {
         Object[] values = record.getValues();
         for (int colId = 0; colId < numColumns; colId++) {
           if (values[colId] == null) {
-            values[colId] = colDefaultNullValues[colId];
+            values[colId] = nullPlaceholders[colId];
             nullBitmaps[colId].add(rowId);
           }
         }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/query/selection/SelectionOperatorUtils.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/query/selection/SelectionOperatorUtils.java
index 851608330d..e6536d7fe4 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/query/selection/SelectionOperatorUtils.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/query/selection/SelectionOperatorUtils.java
@@ -43,7 +43,6 @@ import 
org.apache.pinot.core.query.request.context.QueryContext;
 import org.apache.pinot.segment.spi.IndexSegment;
 import org.apache.pinot.spi.utils.ArrayCopyUtils;
 import org.apache.pinot.spi.utils.ByteArray;
-import org.apache.pinot.spi.utils.NullValueUtils;
 import org.roaringbitmap.RoaringBitmap;
 
 
@@ -244,21 +243,17 @@ public class SelectionOperatorUtils {
     RoaringBitmap[] nullBitmaps = null;
     if (nullHandlingEnabled) {
       nullBitmaps = new RoaringBitmap[numColumns];
-      Object[] colDefaultNullValues = new Object[numColumns];
+      Object[] nullPlaceholders = new Object[numColumns];
       for (int colId = 0; colId < numColumns; colId++) {
-        if (storedColumnDataTypes[colId] != ColumnDataType.OBJECT && 
!storedColumnDataTypes[colId].isArray()) {
-          colDefaultNullValues[colId] =
-              
NullValueUtils.getDefaultNullValue(storedColumnDataTypes[colId].toDataType());
-        }
         nullBitmaps[colId] = new RoaringBitmap();
+        nullPlaceholders[colId] = 
storedColumnDataTypes[colId].getNullPlaceholder();
       }
-
       int rowId = 0;
       for (Object[] row : rows) {
         for (int i = 0; i < numColumns; i++) {
           Object columnValue = row[i];
           if (columnValue == null) {
-            row[i] = colDefaultNullValues[i];
+            row[i] = nullPlaceholders[i];
             nullBitmaps[i].add(rowId);
           }
         }
@@ -434,7 +429,7 @@ public class SelectionOperatorUtils {
       int numColumns = dataTable.getDataSchema().size();
       int numRows = dataTable.getNumberOfRows();
       if (nullHandlingEnabled) {
-        RoaringBitmap[] nullBitmaps = new RoaringBitmap[numColumns];;
+        RoaringBitmap[] nullBitmaps = new RoaringBitmap[numColumns];
         for (int coldId = 0; coldId < numColumns; coldId++) {
           nullBitmaps[coldId] = dataTable.getNullRowIds(coldId);
         }
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunctionTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunctionTest.java
index 8f7584388e..00569eca15 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunctionTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CoalesceTransformFunctionTest.java
@@ -45,7 +45,6 @@ import org.apache.pinot.spi.config.table.TableType;
 import org.apache.pinot.spi.data.FieldSpec;
 import org.apache.pinot.spi.data.Schema;
 import org.apache.pinot.spi.data.readers.GenericRow;
-import org.apache.pinot.spi.utils.NullValueUtils;
 import org.apache.pinot.spi.utils.ReadMode;
 import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
 import org.testng.Assert;
@@ -267,7 +266,7 @@ public class CoalesceTransformFunctionTest extends 
BaseTransformFunctionTest {
     int[] expectedResults = new int[NUM_ROWS];
     for (int i = 0; i < NUM_ROWS; i++) {
       if (isColumn1Null(i) && isColumn2Null(i)) {
-        expectedResults[i] = (int) 
NullValueUtils.getDefaultNullValue(FieldSpec.DataType.INT);
+        expectedResults[i] = CoalesceTransformFunction.NULL_INT;
       } else if (isColumn1Null(i)) {
         expectedResults[i] = _intSVValues[i] + INT_VALUE_SHIFT;
       } else if (isColumn2Null(i)) {
@@ -280,126 +279,126 @@ public class CoalesceTransformFunctionTest extends 
BaseTransformFunctionTest {
     testIntTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
   }
 
-  // Test the Coalesce on two String columns where one or the other or both 
can be null.
+  // Test the Coalesce on two long columns where one or the other or both can 
be null.
   @Test
-  public void testCoalesceStringColumns()
+  public void testCoalesceLongColumns()
       throws Exception {
     ExpressionContext coalesceExpr =
-        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
STRING_SV_COLUMN1, STRING_SV_COLUMN2));
+        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
LONG_SV_COLUMN1, LONG_SV_COLUMN2));
     TransformFunction coalesceTransformFunction = 
TransformFunctionFactory.get(coalesceExpr, _enableNullDataSourceMap);
     Assert.assertEquals(coalesceTransformFunction.getName(), "coalesce");
-    String[] expectedResults = new String[NUM_ROWS];
+    long[] expectedResults = new long[NUM_ROWS];
     for (int i = 0; i < NUM_ROWS; i++) {
       if (isColumn1Null(i) && isColumn2Null(i)) {
-        expectedResults[i] = (String) 
NullValueUtils.getDefaultNullValue(FieldSpec.DataType.STRING);
+        expectedResults[i] = CoalesceTransformFunction.NULL_LONG;
       } else if (isColumn1Null(i)) {
-        expectedResults[i] = _stringSVValues[i] + SUFFIX;
+        expectedResults[i] = _intSVValues[i] + INT_VALUE_SHIFT;
       } else if (isColumn2Null(i)) {
-        expectedResults[i] = _stringSVValues[i];
+        expectedResults[i] = _intSVValues[i];
       } else {
-        expectedResults[i] = _stringSVValues[i];
+        expectedResults[i] = _intSVValues[i];
       }
     }
-    testStringTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
-    testStringTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
+    testLongTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
+    testLongTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
   }
 
-  // Test the Coalesce on two big decimal columns where one or the other or 
both can be null.
+  // Test the Coalesce on two float columns where one or the other or both can 
be null.
   @Test
-  public void testCoalesceBigDecimalColumns()
+  public void testCoalesceFloatColumns()
       throws Exception {
-    ExpressionContext coalesceExpr = RequestContextUtils.getExpression(
-        String.format("COALESCE(%s,%s)", BIG_DECIMAL_SV_COLUMN1, 
BIG_DECIMAL_SV_COLUMN2));
+    ExpressionContext coalesceExpr =
+        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
FLOAT_SV_COLUMN1, FLOAT_SV_COLUMN2));
     TransformFunction coalesceTransformFunction = 
TransformFunctionFactory.get(coalesceExpr, _enableNullDataSourceMap);
     Assert.assertEquals(coalesceTransformFunction.getName(), "coalesce");
-    BigDecimal[] expectedResults = new BigDecimal[NUM_ROWS];
+    float[] expectedResults = new float[NUM_ROWS];
     for (int i = 0; i < NUM_ROWS; i++) {
       if (isColumn1Null(i) && isColumn2Null(i)) {
-        expectedResults[i] = (BigDecimal) 
NullValueUtils.getDefaultNullValue(FieldSpec.DataType.BIG_DECIMAL);
+        expectedResults[i] = CoalesceTransformFunction.NULL_FLOAT;
       } else if (isColumn1Null(i)) {
-        expectedResults[i] = BigDecimal.valueOf(_intSVValues[i] + 
INT_VALUE_SHIFT);
+        expectedResults[i] = _floatValues[i] + FLOAT_VALUE_SHIFT;
       } else if (isColumn2Null(i)) {
-        expectedResults[i] = BigDecimal.valueOf(_intSVValues[i]);
+        expectedResults[i] = _floatValues[i];
       } else {
-        expectedResults[i] = BigDecimal.valueOf(_intSVValues[i]);
+        expectedResults[i] = _floatValues[i];
       }
     }
-    testBigDecimalTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock,
-        _enableNullDataSourceMap);
-    testBigDecimalTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock,
-        _disableNullDataSourceMap);
+    testFloatTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
+    testFloatTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
   }
 
-  // Test the Coalesce on two long columns where one or the other or both can 
be null.
+  // Test the Coalesce on two double columns where one or the other or both 
can be null.
   @Test
-  public void testCoalesceLongColumns()
+  public void testCoalesceDoubleColumns()
       throws Exception {
     ExpressionContext coalesceExpr =
-        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
LONG_SV_COLUMN1, LONG_SV_COLUMN2));
+        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
DOUBLE_SV_COLUMN1, DOUBLE_SV_COLUMN2));
     TransformFunction coalesceTransformFunction = 
TransformFunctionFactory.get(coalesceExpr, _enableNullDataSourceMap);
     Assert.assertEquals(coalesceTransformFunction.getName(), "coalesce");
-    long[] expectedResults = new long[NUM_ROWS];
+    double[] expectedResults = new double[NUM_ROWS];
     for (int i = 0; i < NUM_ROWS; i++) {
       if (isColumn1Null(i) && isColumn2Null(i)) {
-        expectedResults[i] = (long) 
NullValueUtils.getDefaultNullValue(FieldSpec.DataType.LONG);
+        expectedResults[i] = CoalesceTransformFunction.NULL_DOUBLE;
       } else if (isColumn1Null(i)) {
-        expectedResults[i] = _intSVValues[i] + INT_VALUE_SHIFT;
+        expectedResults[i] = _doubleValues[i] + DOUBLE_VALUE_SHIFT;
       } else if (isColumn2Null(i)) {
-        expectedResults[i] = _intSVValues[i];
+        expectedResults[i] = _doubleValues[i];
       } else {
-        expectedResults[i] = _intSVValues[i];
+        expectedResults[i] = _doubleValues[i];
       }
     }
-    testLongTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
-    testLongTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
+    testDoubleTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
+    testDoubleTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
   }
 
-  // Test the Coalesce on two double columns where one or the other or both 
can be null.
+  // Test the Coalesce on two big decimal columns where one or the other or 
both can be null.
   @Test
-  public void testCoalesceDoubleColumns()
+  public void testCoalesceBigDecimalColumns()
       throws Exception {
-    ExpressionContext coalesceExpr =
-        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
DOUBLE_SV_COLUMN1, DOUBLE_SV_COLUMN2));
+    ExpressionContext coalesceExpr = RequestContextUtils.getExpression(
+        String.format("COALESCE(%s,%s)", BIG_DECIMAL_SV_COLUMN1, 
BIG_DECIMAL_SV_COLUMN2));
     TransformFunction coalesceTransformFunction = 
TransformFunctionFactory.get(coalesceExpr, _enableNullDataSourceMap);
     Assert.assertEquals(coalesceTransformFunction.getName(), "coalesce");
-    double[] expectedResults = new double[NUM_ROWS];
+    BigDecimal[] expectedResults = new BigDecimal[NUM_ROWS];
     for (int i = 0; i < NUM_ROWS; i++) {
       if (isColumn1Null(i) && isColumn2Null(i)) {
-        expectedResults[i] = (double) 
NullValueUtils.getDefaultNullValue(FieldSpec.DataType.DOUBLE);
+        expectedResults[i] = CoalesceTransformFunction.NULL_BIG_DECIMAL;
       } else if (isColumn1Null(i)) {
-        expectedResults[i] = _doubleValues[i] + DOUBLE_VALUE_SHIFT;
+        expectedResults[i] = BigDecimal.valueOf(_intSVValues[i] + 
INT_VALUE_SHIFT);
       } else if (isColumn2Null(i)) {
-        expectedResults[i] = _doubleValues[i];
+        expectedResults[i] = BigDecimal.valueOf(_intSVValues[i]);
       } else {
-        expectedResults[i] = _doubleValues[i];
+        expectedResults[i] = BigDecimal.valueOf(_intSVValues[i]);
       }
     }
-    testDoubleTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
-    testDoubleTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
+    testBigDecimalTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock,
+        _enableNullDataSourceMap);
+    testBigDecimalTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock,
+        _disableNullDataSourceMap);
   }
 
-  // Test the Coalesce on two float columns where one or the other or both can 
be null.
+  // Test the Coalesce on two String columns where one or the other or both 
can be null.
   @Test
-  public void testCoalesceFloatColumns()
+  public void testCoalesceStringColumns()
       throws Exception {
     ExpressionContext coalesceExpr =
-        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
FLOAT_SV_COLUMN1, FLOAT_SV_COLUMN2));
+        RequestContextUtils.getExpression(String.format("COALESCE(%s,%s)", 
STRING_SV_COLUMN1, STRING_SV_COLUMN2));
     TransformFunction coalesceTransformFunction = 
TransformFunctionFactory.get(coalesceExpr, _enableNullDataSourceMap);
     Assert.assertEquals(coalesceTransformFunction.getName(), "coalesce");
-    float[] expectedResults = new float[NUM_ROWS];
+    String[] expectedResults = new String[NUM_ROWS];
     for (int i = 0; i < NUM_ROWS; i++) {
       if (isColumn1Null(i) && isColumn2Null(i)) {
-        expectedResults[i] = (float) 
NullValueUtils.getDefaultNullValue(FieldSpec.DataType.FLOAT);
+        expectedResults[i] = CoalesceTransformFunction.NULL_STRING;
       } else if (isColumn1Null(i)) {
-        expectedResults[i] = _floatValues[i] + FLOAT_VALUE_SHIFT;
+        expectedResults[i] = _stringSVValues[i] + SUFFIX;
       } else if (isColumn2Null(i)) {
-        expectedResults[i] = _floatValues[i];
+        expectedResults[i] = _stringSVValues[i];
       } else {
-        expectedResults[i] = _floatValues[i];
+        expectedResults[i] = _stringSVValues[i];
       }
     }
-    testFloatTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
-    testFloatTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
+    testStringTransformFunction(coalesceExpr, expectedResults, 
_enableNullProjectionBlock, _enableNullDataSourceMap);
+    testStringTransformFunction(coalesceExpr, expectedResults, 
_disableNullProjectionBlock, _disableNullDataSourceMap);
   }
 
   // Test that non-column-names appear in one of the argument.
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/NullValueUtils.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/NullValueUtils.java
deleted file mode 100644
index 09b4531e59..0000000000
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/NullValueUtils.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.pinot.spi.utils;
-
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.pinot.spi.data.FieldSpec;
-import org.apache.pinot.spi.data.FieldSpec.DataType;
-
-
-public class NullValueUtils {
-  private NullValueUtils() {
-  }
-
-  private static final Map<DataType, Object> FIELD_TYPE_DEFAULT_NULL_VALUE_MAP 
= new HashMap<>();
-
-  static {
-    DataType[] types = {DataType.INT, DataType.LONG, DataType.FLOAT, 
DataType.DOUBLE, DataType.BIG_DECIMAL,
-        DataType.BOOLEAN, DataType.TIMESTAMP, DataType.STRING, DataType.JSON, 
DataType.BYTES};
-    for (DataType type : types) {
-      FieldSpec.FieldType fieldType = 
type.equals(FieldSpec.DataType.BIG_DECIMAL)
-          ? FieldSpec.FieldType.METRIC : FieldSpec.FieldType.DIMENSION;
-      FIELD_TYPE_DEFAULT_NULL_VALUE_MAP.put(type, 
FieldSpec.getDefaultNullValue(fieldType, type, null));
-    }
-  }
-
-  public static Object getDefaultNullValue(FieldSpec.DataType dataType) {
-    return FIELD_TYPE_DEFAULT_NULL_VALUE_MAP.get(dataType);
-  }
-}


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


Reply via email to