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 3015b2ec77 Added SHOW TABLES and DESCRIBE table support (#12293)
3015b2ec77 is described below

commit 3015b2ec7783a6a14e6ed51e6b95bc8197dbffcb
Author: Aadil Khalifa <[email protected]>
AuthorDate: Tue Jul 16 04:50:48 2024 +0530

    Added SHOW TABLES and DESCRIBE table support (#12293)
---
 .../common/function/scalar/ArrayFunctions.java     |  44 +++
 .../function/FunctionDefinitionRegistryTest.java   |   4 +-
 .../function/GenerateArrayTransformFunction.java   | 410 +++++++++++++++++++++
 .../function/TransformFunctionFactory.java         |   7 +
 .../GenerateArrayTransformFunctionTest.java        | 159 ++++++++
 .../pinot/integration/tests/custom/ArrayTest.java  | 199 ++++++++++
 6 files changed, 821 insertions(+), 2 deletions(-)

diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/ArrayFunctions.java
 
b/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/ArrayFunctions.java
index 52997d0926..13f77b2c5a 100644
--- 
a/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/ArrayFunctions.java
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/ArrayFunctions.java
@@ -305,4 +305,48 @@ public class ArrayFunctions {
     }
     return arr;
   }
+
+  @ScalarFunction
+  public static int[] generateIntArray(int start, int end, int inc) {
+    int size = (end - start) / inc + 1;
+    int[] arr = new int[size];
+
+    for (int i = 0, value = start; i < size; i++, value += inc) {
+      arr[i] = value;
+    }
+    return arr;
+  }
+
+  @ScalarFunction
+  public static long[] generateLongArray(long start, long end, long inc) {
+    int size = (int) ((end - start) / inc + 1);
+    long[] arr = new long[size];
+
+    for (int i = 0; i < size; i++, start += inc) {
+      arr[i] = start;
+    }
+    return arr;
+  }
+
+  @ScalarFunction
+  public static float[] generateFloatArray(float start, float end, float inc) {
+    int size = (int) ((end - start) / inc + 1);
+    float[] arr = new float[size];
+
+    for (int i = 0; i < size; i++, start += inc) {
+      arr[i] = start;
+    }
+    return arr;
+  }
+
+  @ScalarFunction
+  public static double[] generateDoubleArray(double start, double end, double 
inc) {
+    int size = (int) ((end - start) / inc + 1);
+    double[] arr = new double[size];
+
+    for (int i = 0; i < size; i++, start += inc) {
+      arr[i] = start;
+    }
+    return arr;
+  }
 }
diff --git 
a/pinot-common/src/test/java/org/apache/pinot/common/function/FunctionDefinitionRegistryTest.java
 
b/pinot-common/src/test/java/org/apache/pinot/common/function/FunctionDefinitionRegistryTest.java
index d2771bc626..600016fd8f 100644
--- 
a/pinot-common/src/test/java/org/apache/pinot/common/function/FunctionDefinitionRegistryTest.java
+++ 
b/pinot-common/src/test/java/org/apache/pinot/common/function/FunctionDefinitionRegistryTest.java
@@ -42,8 +42,8 @@ public class FunctionDefinitionRegistryTest {
   private static final List<String> IGNORED_FUNCTION_NAMES = ImmutableList.of(
       // Geo functions are defined in pinot-core
       "geotoh3",
-      // ArrayToMV and ArrayValueConstructor are placeholder functions without 
implementation
-      "arraytomv", "arrayvalueconstructor",
+      // ArrayToMV, ArrayValueConstructor and GenerateArray are placeholder 
functions without implementation
+      "arraytomv", "arrayvalueconstructor", "generatearray",
       // Scalar function
       "scalar",
       // Functions without scalar function counterpart as of now
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/GenerateArrayTransformFunction.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/GenerateArrayTransformFunction.java
new file mode 100644
index 0000000000..44632867ac
--- /dev/null
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/GenerateArrayTransformFunction.java
@@ -0,0 +1,410 @@
+/**
+ * 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.core.operator.transform.function;
+
+import com.google.common.base.Preconditions;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.pinot.common.request.context.ExpressionContext;
+import org.apache.pinot.core.operator.ColumnContext;
+import org.apache.pinot.core.operator.blocks.ValueBlock;
+import org.apache.pinot.core.operator.transform.TransformResultMetadata;
+import org.apache.pinot.segment.spi.index.reader.Dictionary;
+import org.apache.pinot.spi.data.FieldSpec.DataType;
+import org.roaringbitmap.RoaringBitmap;
+
+public class GenerateArrayTransformFunction implements TransformFunction {
+  public static final String FUNCTION_NAME = "generateArray";
+
+  private final DataType _dataType;
+
+  private final int[] _intArrayLiteral;
+  private final long[] _longArrayLiteral;
+  private final float[] _floatArrayLiteral;
+  private final double[] _doubleArrayLiteral;
+  private int[][] _intArrayResult;
+  private long[][] _longArrayResult;
+  private float[][] _floatArrayResult;
+  private double[][] _doubleArrayResult;
+
+  public GenerateArrayTransformFunction(List<ExpressionContext> 
literalContexts) {
+    Preconditions.checkNotNull(literalContexts);
+    if (literalContexts.isEmpty()) {
+      _dataType = DataType.UNKNOWN;
+      _intArrayLiteral = new int[0];
+      _longArrayLiteral = new long[0];
+      _floatArrayLiteral = new float[0];
+      _doubleArrayLiteral = new double[0];
+      return;
+    }
+    Preconditions.checkState(literalContexts.size() == 2 || 
literalContexts.size() == 3,
+        "GenerateArrayTransformFunction takes only 2 or 3 arguments, found: 
%s", literalContexts.size());
+    for (ExpressionContext literalContext : literalContexts) {
+      Preconditions.checkState(literalContext.getType() == 
ExpressionContext.Type.LITERAL,
+          "GenerateArrayTransformFunction only takes literals as arguments, 
found: %s", literalContext);
+    }
+    // Get the type of the first member in the literalContext and generate an 
array
+    _dataType = literalContexts.get(0).getLiteral().getType();
+
+    switch (_dataType) {
+      case INT:
+        int startInt = literalContexts.get(0).getLiteral().getIntValue();
+        int endInt = literalContexts.get(1).getLiteral().getIntValue();
+        int incInt;
+        if (literalContexts.size() == 3) {
+          incInt = literalContexts.get(2).getLiteral().getIntValue();
+        } else {
+          incInt = 1;
+        }
+        Preconditions.checkState((endInt > startInt && incInt > 0) || 
(startInt > endInt
+            && incInt < 0), "Incorrect Step value.");
+        int size = (endInt - startInt) / incInt + 1;
+        _intArrayLiteral = new int[size];
+        for (int i = 0, value = startInt; i < size; i++, value += incInt) {
+          _intArrayLiteral[i] = value;
+        }
+        _longArrayLiteral = null;
+        _floatArrayLiteral = null;
+        _doubleArrayLiteral = null;
+        break;
+      case LONG:
+        long startLong = 
Long.parseLong(literalContexts.get(0).getLiteral().getStringValue());
+        long endLong = 
Long.parseLong(literalContexts.get(1).getLiteral().getStringValue());
+        long incLong;
+        if (literalContexts.size() == 3) {
+          incLong = 
Long.parseLong(literalContexts.get(2).getLiteral().getStringValue());
+        } else {
+          incLong = 1L;
+        }
+        Preconditions.checkState((endLong > startLong && incLong > 0) || 
(startLong > endLong
+            && incLong < 0), "Incorrect Step value.");
+        size = (int) ((endLong - startLong) / incLong + 1);
+        _longArrayLiteral = new long[size];
+        for (int i = 0; i < size; i++, startLong += incLong) {
+          _longArrayLiteral[i] = startLong;
+        }
+        _intArrayLiteral = null;
+        _floatArrayLiteral = null;
+        _doubleArrayLiteral = null;
+        break;
+      case FLOAT:
+        float startFloat = 
Float.parseFloat(literalContexts.get(0).getLiteral().getStringValue());
+        float endFloat = 
Float.parseFloat(literalContexts.get(1).getLiteral().getStringValue());
+        float incFloat;
+        if (literalContexts.size() == 3) {
+          incFloat = 
Float.parseFloat(literalContexts.get(2).getLiteral().getStringValue());
+        } else {
+          incFloat = 1;
+        }
+        Preconditions.checkState((endFloat > startFloat && incFloat > 0) || 
(startFloat > endFloat
+            && incFloat < 0), "Incorrect Step value.");
+        size = (int) ((endFloat - startFloat) / incFloat + 1);
+        _floatArrayLiteral = new float[size];
+        for (int i = 0; i < size; i++, startFloat += incFloat) {
+          _floatArrayLiteral[i] = startFloat;
+        }
+        _intArrayLiteral = null;
+        _longArrayLiteral = null;
+        _doubleArrayLiteral = null;
+        break;
+      case DOUBLE:
+        double startDouble = 
Double.parseDouble(literalContexts.get(0).getLiteral().getStringValue());
+        double endDouble = 
Double.parseDouble(literalContexts.get(1).getLiteral().getStringValue());
+        double incDouble;
+        if (literalContexts.size() == 3) {
+          incDouble = 
Double.parseDouble(literalContexts.get(2).getLiteral().getStringValue());
+        } else {
+          incDouble = 1.0;
+        }
+        Preconditions.checkState((endDouble > startDouble && incDouble > 0) || 
(startDouble > endDouble
+            && incDouble < 0), "Incorrect Step value.");
+        size = (int) ((endDouble - startDouble) / incDouble + 1);
+        _doubleArrayLiteral = new double[size];
+        for (int i = 0; i < size; i++, startDouble += incDouble) {
+          _doubleArrayLiteral[i] = startDouble;
+        }
+        _intArrayLiteral = null;
+        _longArrayLiteral = null;
+        _floatArrayLiteral = null;
+        break;
+      default:
+        throw new IllegalStateException(
+            "Illegal data type for GenerateArrayTransformFunction: " + 
_dataType + ", literal contexts: "
+                + Arrays.toString(literalContexts.toArray()));
+    }
+  }
+
+  public int[] getIntArrayLiteral() {
+    return _intArrayLiteral;
+  }
+
+  public long[] getLongArrayLiteral() {
+    return _longArrayLiteral;
+  }
+
+  public float[] getFloatArrayLiteral() {
+    return _floatArrayLiteral;
+  }
+
+  public double[] getDoubleArrayLiteral() {
+    return _doubleArrayLiteral;
+  }
+
+  @Override
+  public String getName() {
+    return FUNCTION_NAME;
+  }
+
+  @Override
+  public void init(List<TransformFunction> arguments, Map<String, 
ColumnContext> columnContextMap) {
+    if (arguments.size() < 2) {
+      throw new IllegalArgumentException("At least 2 arguments are required 
for generateArray function");
+    }
+  }
+
+  @Override
+  public TransformResultMetadata getResultMetadata() {
+    return new TransformResultMetadata(_dataType, false, false);
+  }
+
+  @Nullable
+  @Override
+  public Dictionary getDictionary() {
+    return null;
+  }
+
+  @Override
+  public int[] transformToDictIdsSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public int[][] transformToDictIdsMV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public int[] transformToIntValuesSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public long[] transformToLongValuesSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public float[] transformToFloatValuesSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public double[] transformToDoubleValuesSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public BigDecimal[] transformToBigDecimalValuesSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public String[] transformToStringValuesSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public byte[][] transformToBytesValuesSV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public int[][] transformToIntValuesMV(ValueBlock valueBlock) {
+    int numDocs = valueBlock.getNumDocs();
+    int[][] intArrayResult = _intArrayResult;
+    if (intArrayResult == null || intArrayResult.length < numDocs) {
+      intArrayResult = new int[numDocs][];
+      int[] intArrayLiteral = _intArrayLiteral;
+      if (intArrayLiteral == null) {
+        switch (_dataType) {
+          case LONG:
+            intArrayLiteral = new int[_longArrayLiteral.length];
+            for (int i = 0; i < _longArrayLiteral.length; i++) {
+              intArrayLiteral[i] = (int) _longArrayLiteral[i];
+            }
+            break;
+          case FLOAT:
+            intArrayLiteral = new int[_floatArrayLiteral.length];
+            for (int i = 0; i < _floatArrayLiteral.length; i++) {
+              intArrayLiteral[i] = (int) _floatArrayLiteral[i];
+            }
+            break;
+          case DOUBLE:
+            intArrayLiteral = new int[_doubleArrayLiteral.length];
+            for (int i = 0; i < _doubleArrayLiteral.length; i++) {
+              intArrayLiteral[i] = (int) _doubleArrayLiteral[i];
+            }
+            break;
+          default:
+            throw new IllegalStateException("Unable to convert data type: " + 
_dataType + " to in array");
+        }
+      }
+      Arrays.fill(intArrayResult, intArrayLiteral);
+      _intArrayResult = intArrayResult;
+    }
+    return intArrayResult;
+  }
+
+  @Override
+  public long[][] transformToLongValuesMV(ValueBlock valueBlock) {
+    int numDocs = valueBlock.getNumDocs();
+    long[][] longArrayResult = _longArrayResult;
+    if (longArrayResult == null || longArrayResult.length < numDocs) {
+      longArrayResult = new long[numDocs][];
+      long[] longArrayLiteral = _longArrayLiteral;
+      if (longArrayLiteral == null) {
+        switch (_dataType) {
+          case INT:
+            longArrayLiteral = new long[_intArrayLiteral.length];
+            for (int i = 0; i < _intArrayLiteral.length; i++) {
+              longArrayLiteral[i] = _intArrayLiteral[i];
+            }
+            break;
+          case FLOAT:
+            longArrayLiteral = new long[_floatArrayLiteral.length];
+            for (int i = 0; i < _floatArrayLiteral.length; i++) {
+              longArrayLiteral[i] = (long) _floatArrayLiteral[i];
+            }
+            break;
+          case DOUBLE:
+            longArrayLiteral = new long[_doubleArrayLiteral.length];
+            for (int i = 0; i < _doubleArrayLiteral.length; i++) {
+              longArrayLiteral[i] = (long) _doubleArrayLiteral[i];
+            }
+            break;
+          default:
+            throw new IllegalStateException("Unable to convert data type: " + 
_dataType + " to long array");
+        }
+      }
+      Arrays.fill(longArrayResult, longArrayLiteral);
+      _longArrayResult = longArrayResult;
+    }
+    return longArrayResult;
+  }
+
+  @Override
+  public float[][] transformToFloatValuesMV(ValueBlock valueBlock) {
+    int numDocs = valueBlock.getNumDocs();
+    float[][] floatArrayResult = _floatArrayResult;
+    if (floatArrayResult == null || floatArrayResult.length < numDocs) {
+      floatArrayResult = new float[numDocs][];
+      float[] floatArrayLiteral = _floatArrayLiteral;
+      if (floatArrayLiteral == null) {
+        switch (_dataType) {
+          case INT:
+            floatArrayLiteral = new float[_intArrayLiteral.length];
+            for (int i = 0; i < _intArrayLiteral.length; i++) {
+              floatArrayLiteral[i] = _intArrayLiteral[i];
+            }
+            break;
+          case LONG:
+            floatArrayLiteral = new float[_longArrayLiteral.length];
+            for (int i = 0; i < _longArrayLiteral.length; i++) {
+              floatArrayLiteral[i] = _longArrayLiteral[i];
+            }
+            break;
+          case DOUBLE:
+            floatArrayLiteral = new float[_doubleArrayLiteral.length];
+            for (int i = 0; i < _doubleArrayLiteral.length; i++) {
+              floatArrayLiteral[i] = (float) _doubleArrayLiteral[i];
+            }
+            break;
+          default:
+            throw new IllegalStateException("Unable to convert data type: " + 
_dataType + " to float array");
+        }
+      }
+      Arrays.fill(floatArrayResult, floatArrayLiteral);
+      _floatArrayResult = floatArrayResult;
+    }
+    return floatArrayResult;
+  }
+
+  @Override
+  public double[][] transformToDoubleValuesMV(ValueBlock valueBlock) {
+    int numDocs = valueBlock.getNumDocs();
+    double[][] doubleArrayResult = _doubleArrayResult;
+    if (doubleArrayResult == null || doubleArrayResult.length < numDocs) {
+      doubleArrayResult = new double[numDocs][];
+      double[] doubleArrayLiteral = _doubleArrayLiteral;
+      if (doubleArrayLiteral == null) {
+        switch (_dataType) {
+          case INT:
+            doubleArrayLiteral = new double[_intArrayLiteral.length];
+            for (int i = 0; i < _intArrayLiteral.length; i++) {
+              doubleArrayLiteral[i] = _intArrayLiteral[i];
+            }
+            break;
+          case LONG:
+            doubleArrayLiteral = new double[_longArrayLiteral.length];
+            for (int i = 0; i < _longArrayLiteral.length; i++) {
+              doubleArrayLiteral[i] = _longArrayLiteral[i];
+            }
+            break;
+          case FLOAT:
+            doubleArrayLiteral = new double[_floatArrayLiteral.length];
+            for (int i = 0; i < _floatArrayLiteral.length; i++) {
+              doubleArrayLiteral[i] = _floatArrayLiteral[i];
+            }
+            break;
+          default:
+            throw new IllegalStateException("Unable to convert data type: " + 
_dataType + " to double array");
+        }
+      }
+      Arrays.fill(doubleArrayResult, doubleArrayLiteral);
+      _doubleArrayResult = doubleArrayResult;
+    }
+    return doubleArrayResult;
+  }
+
+  @Override
+  public String[][] transformToStringValuesMV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public byte[][][] transformToBytesValuesMV(ValueBlock valueBlock) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Nullable
+  @Override
+  public RoaringBitmap getNullBitmap(ValueBlock block) {
+    // Treat all unknown type values as null regardless of the value.
+    if (_dataType != DataType.UNKNOWN) {
+      return null;
+    }
+    int length = block.getNumDocs();
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(0L, length);
+    return bitmap;
+  }
+}
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java
index de7668ca26..7643959d11 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TransformFunctionFactory.java
@@ -299,6 +299,13 @@ public class TransformFunctionFactory {
               ArrayLiteralTransformFunction::new);
         }
 
+        // Check if the function is GenerateArray transform function
+        if 
(functionName.equalsIgnoreCase(GenerateArrayTransformFunction.FUNCTION_NAME)) {
+          return 
queryContext.getOrComputeSharedValue(GenerateArrayTransformFunction.class,
+              expression.getFunction().getArguments(),
+              GenerateArrayTransformFunction::new);
+        }
+
         TransformFunction transformFunction;
         Class<? extends TransformFunction> transformFunctionClass = 
TRANSFORM_FUNCTION_MAP.get(functionName);
         if (transformFunctionClass != null) {
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/GenerateArrayTransformFunctionTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/GenerateArrayTransformFunctionTest.java
new file mode 100644
index 0000000000..72bd48f7ff
--- /dev/null
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/GenerateArrayTransformFunctionTest.java
@@ -0,0 +1,159 @@
+/**
+ * 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.core.operator.transform.function;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.pinot.common.request.context.ExpressionContext;
+import org.apache.pinot.core.operator.blocks.ProjectionBlock;
+import org.apache.pinot.spi.data.FieldSpec.DataType;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.mockito.Mockito.when;
+
+public class GenerateArrayTransformFunctionTest {
+  private static final int NUM_DOCS = 100;
+  private AutoCloseable _mocks;
+
+  @Mock
+  private ProjectionBlock _projectionBlock;
+
+  @BeforeMethod
+  public void setUp() {
+    _mocks = MockitoAnnotations.openMocks(this);
+    when(_projectionBlock.getNumDocs()).thenReturn(NUM_DOCS);
+  }
+
+  @AfterMethod
+  public void tearDown()
+      throws Exception {
+    _mocks.close();
+  }
+  @Test
+  public void testGenerateIntArrayTransformFunction() {
+    List<ExpressionContext> arrayExpressions = new ArrayList<>();
+    int[] inputArray = {0, 10, 1};
+    for (int j : inputArray) {
+      arrayExpressions.add(ExpressionContext.forLiteral(DataType.INT, j));
+    }
+
+    GenerateArrayTransformFunction intArray = new 
GenerateArrayTransformFunction(arrayExpressions);
+    Assert.assertEquals(intArray.getResultMetadata().getDataType(), 
DataType.INT);
+    Assert.assertEquals(intArray.getIntArrayLiteral(), new int[]{
+        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
+    });
+  }
+
+  @Test
+  public void testGenerateLongArrayTransformFunction() {
+    List<ExpressionContext> arrayExpressions = new ArrayList<>();
+    int[] inputArray = {0, 10, 1};
+    for (int j : inputArray) {
+      arrayExpressions.add(ExpressionContext.forLiteral(DataType.LONG, (long) 
j));
+    }
+
+    GenerateArrayTransformFunction longArray = new 
GenerateArrayTransformFunction(arrayExpressions);
+    Assert.assertEquals(longArray.getResultMetadata().getDataType(), 
DataType.LONG);
+    Assert.assertEquals(longArray.getLongArrayLiteral(), new long[]{
+        0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L
+    });
+  }
+
+  @Test
+  public void testGenerateFloatArrayTransformFunction() {
+    List<ExpressionContext> arrayExpressions = new ArrayList<>();
+    int[] inputArray = {0, 10, 1};
+    for (int j : inputArray) {
+      arrayExpressions.add(ExpressionContext.forLiteral(DataType.FLOAT, 
(float) j));
+    }
+
+    GenerateArrayTransformFunction floatArray = new 
GenerateArrayTransformFunction(arrayExpressions);
+    Assert.assertEquals(floatArray.getResultMetadata().getDataType(), 
DataType.FLOAT);
+    Assert.assertEquals(floatArray.getFloatArrayLiteral(), new float[]{
+        0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f
+    });
+  }
+
+  @Test
+  public void testGenerateDoubleArrayTransformFunction() {
+    List<ExpressionContext> arrayExpressions = new ArrayList<>();
+    int[] inputArray = {0, 10, 1};
+    for (int j : inputArray) {
+      arrayExpressions.add(ExpressionContext.forLiteral(DataType.DOUBLE, 
(double) j));
+    }
+
+    GenerateArrayTransformFunction doubleArray = new 
GenerateArrayTransformFunction(arrayExpressions);
+    Assert.assertEquals(doubleArray.getResultMetadata().getDataType(), 
DataType.DOUBLE);
+    Assert.assertEquals(doubleArray.getDoubleArrayLiteral(), new double[]{
+        0d, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d, 10d
+    });
+  }
+  @Test
+  public void testGenerateEmptyArrayTransformFunction() {
+    List<ExpressionContext> arrayExpressions = new ArrayList<>();
+    GenerateArrayTransformFunction emptyLiteral = new 
GenerateArrayTransformFunction(arrayExpressions);
+    Assert.assertEquals(emptyLiteral.getIntArrayLiteral(), new int[0]);
+    Assert.assertEquals(emptyLiteral.getLongArrayLiteral(), new long[0]);
+    Assert.assertEquals(emptyLiteral.getFloatArrayLiteral(), new float[0]);
+    Assert.assertEquals(emptyLiteral.getDoubleArrayLiteral(), new double[0]);
+
+    int[][] ints = emptyLiteral.transformToIntValuesMV(_projectionBlock);
+    Assert.assertEquals(ints.length, NUM_DOCS);
+    for (int i = 0; i < NUM_DOCS; i++) {
+      Assert.assertEquals(ints[i].length, 0);
+    }
+
+    long[][] longs = emptyLiteral.transformToLongValuesMV(_projectionBlock);
+    Assert.assertEquals(longs.length, NUM_DOCS);
+    for (int i = 0; i < NUM_DOCS; i++) {
+      Assert.assertEquals(longs[i].length, 0);
+    }
+
+    float[][] floats = emptyLiteral.transformToFloatValuesMV(_projectionBlock);
+    Assert.assertEquals(floats.length, NUM_DOCS);
+    for (int i = 0; i < NUM_DOCS; i++) {
+      Assert.assertEquals(floats[i].length, 0);
+    }
+
+    double[][] doubles = 
emptyLiteral.transformToDoubleValuesMV(_projectionBlock);
+    Assert.assertEquals(doubles.length, NUM_DOCS);
+    for (int i = 0; i < NUM_DOCS; i++) {
+      Assert.assertEquals(doubles[i].length, 0);
+    }
+  }
+  @Test
+  public void testGenerateIntArrayTransformFunctionWithIncorrectStepValue() {
+    List<ExpressionContext> arrayExpressions = new ArrayList<>();
+    int[] inputArray = {0, 10, -1};
+    for (int j : inputArray) {
+      arrayExpressions.add(ExpressionContext.forLiteral(DataType.INT, j));
+    }
+
+    try {
+      GenerateArrayTransformFunction intArray = new 
GenerateArrayTransformFunction(arrayExpressions);
+      Assert.fail();
+    } catch (IllegalStateException ignored) {
+    }
+  }
+}
diff --git 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/custom/ArrayTest.java
 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/custom/ArrayTest.java
index cc9d6eb420..cf72b636d3 100644
--- 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/custom/ArrayTest.java
+++ 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/custom/ArrayTest.java
@@ -581,6 +581,205 @@ public class ArrayTest extends 
CustomDataQueryClusterIntegrationTest {
     }
   }
 
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateIntArray(boolean useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(1, 3, 1) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 3);
+    assertEquals(row.get(0).get(0).asInt(), 1);
+    assertEquals(row.get(0).get(1).asInt(), 2);
+    assertEquals(row.get(0).get(2).asInt(), 3);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateIntArrayWithoutStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(1, 3) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 3);
+    assertEquals(row.get(0).get(0).asInt(), 1);
+    assertEquals(row.get(0).get(1).asInt(), 2);
+    assertEquals(row.get(0).get(2).asInt(), 3);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateIntArrayWithIncorrectStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(1, 3, -1) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    assertEquals(jsonNode.get("exceptions").size(), 1);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateLongArray(boolean useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(2147483648, 2147483650, 2) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 2);
+    assertEquals(row.get(0).get(0).asLong(), 2147483648L);
+    assertEquals(row.get(0).get(1).asLong(), 2147483650L);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateLongArrayWithoutStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(2147483648, 2147483650) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 3);
+    assertEquals(row.get(0).get(0).asLong(), 2147483648L);
+    assertEquals(row.get(0).get(1).asLong(), 2147483649L);
+    assertEquals(row.get(0).get(2).asLong(), 2147483650L);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateLongArrayWithIncorrectStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(2147483648, 2147483650, -1) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    assertEquals(jsonNode.get("exceptions").size(), 1);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateFloatArray(boolean useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(0.1, 0.3, 0.1) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 3);
+    assertEquals(row.get(0).get(0).asDouble(), 0.1);
+    assertEquals(row.get(0).get(1).asDouble(), 0.1 + 0.1 * 1);
+    assertEquals(row.get(0).get(2).asDouble(), 0.1 + 0.1 * 2);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateFloatArrayWithoutStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(0.3, 3.1) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 3);
+    assertEquals(row.get(0).get(0).asDouble(), 0.3);
+    assertEquals(row.get(0).get(1).asDouble(), 1.3);
+    assertEquals(row.get(0).get(2).asDouble(), 2.3);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateFloatArrayWithIncorrectStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(0.3, 0.1, 1.1) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    assertEquals(jsonNode.get("exceptions").size(), 1);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateDoubleArray(boolean useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(CAST(0.1 AS DOUBLE), CAST(0.3 AS DOUBLE), 
CAST(0.1 AS DOUBLE)) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 3);
+    assertEquals(row.get(0).get(0).asDouble(), 0.1);
+    assertEquals(row.get(0).get(1).asDouble(), 0.1 + 0.1 * 1);
+    assertEquals(row.get(0).get(2).asDouble(), 0.1 + 0.1 * 2);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateDoubleArrayWithoutStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(CAST(0.3 AS DOUBLE), CAST(3.1 AS DOUBLE)) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    JsonNode rows = jsonNode.get("resultTable").get("rows");
+    assertEquals(rows.size(), 1);
+    JsonNode row = rows.get(0);
+    assertEquals(row.size(), 1);
+    assertEquals(row.get(0).size(), 3);
+    assertEquals(row.get(0).get(0).asDouble(), 0.3);
+    assertEquals(row.get(0).get(1).asDouble(), 1.3);
+    assertEquals(row.get(0).get(2).asDouble(), 2.3);
+  }
+
+  @Test(dataProvider = "useV1QueryEngine")
+  public void testGenerateDoubleArrayWithIncorrectStepValue(boolean 
useMultiStageQueryEngine)
+      throws Exception {
+    setUseMultiStageQueryEngine(useMultiStageQueryEngine);
+    String query =
+        String.format("SELECT "
+            + "GENERATE_ARRAY(CAST(0.3 AS DOUBLE), CAST(0.1 AS DOUBLE), 
CAST(1.1 AS DOUBLE)) "
+            + "FROM %s LIMIT 1", getTableName());
+    JsonNode jsonNode = postQuery(query);
+    assertEquals(jsonNode.get("exceptions").size(), 1);
+  }
+
   @Override
   public String getTableName() {
     return DEFAULT_TABLE_NAME;


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


Reply via email to