This is an automated email from the ASF dual-hosted git repository.
yashmayya 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 fffc79c0cc1 Support Object parameters for column arguments in scalar
function wrapper (#19789)
fffc79c0cc1 is described below
commit fffc79c0cc1eb1e72ecb4ffd4dc70e1213252291
Author: Yash Mayya <[email protected]>
AuthorDate: Mon Oct 12 16:43:17 2026 -0700
Support Object parameters for column arguments in scalar function wrapper
(#19789)
---
.../function/ScalarTransformFunctionWrapper.java | 62 ++++++-
.../ScalarTransformFunctionWrapperTest.java | 47 +++++
.../ObjectParameterScalarFunctionsQueriesTest.java | 195 +++++++++++++++++++++
.../queries/ObjectParameterFunctions.json | 60 +++++++
4 files changed, 361 insertions(+), 3 deletions(-)
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapper.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapper.java
index 03f650871ab..f55123a3295 100644
---
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapper.java
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapper.java
@@ -50,6 +50,7 @@ public class ScalarTransformFunctionWrapper extends
BaseTransformFunction {
private int _numNonLiteralArguments;
private int[] _nonLiteralIndices;
private TransformFunction[] _nonLiteralFunctions;
+ private PinotDataType[] _nonLiteralTypes;
private Object[][] _nonLiteralValues;
public ScalarTransformFunctionWrapper(FunctionInfo functionInfo) {
@@ -91,6 +92,7 @@ public class ScalarTransformFunctionWrapper extends
BaseTransformFunction {
_scalarArguments = new Object[numArguments];
_nonLiteralIndices = new int[numArguments];
_nonLiteralFunctions = new TransformFunction[numArguments];
+ _nonLiteralTypes = new PinotDataType[numArguments];
for (int i = 0; i < numArguments; i++) {
TransformFunction transformFunction = arguments.get(i);
if (transformFunction instanceof LiteralTransformFunction) {
@@ -146,6 +148,9 @@ public class ScalarTransformFunctionWrapper extends
BaseTransformFunction {
} else {
_nonLiteralIndices[_numNonLiteralArguments] = i;
_nonLiteralFunctions[_numNonLiteralArguments] = transformFunction;
+ _nonLiteralTypes[_numNonLiteralArguments] = parameterTypes[i] !=
PinotDataType.OBJECT
+ ? parameterTypes[i]
+ : getObjectArgumentType(transformFunction.getResultMetadata());
_numNonLiteralArguments++;
}
}
@@ -374,11 +379,46 @@ public class ScalarTransformFunctionWrapper extends
BaseTransformFunction {
return _stringValuesMV;
}
- /// Helper method to fetch values for the non-literal transform functions
based on the parameter types.
+ /// Returns the type to read an argument for an `Object` parameter, so that
the function gets the external Java value
+ /// of the argument result type, the same as `ColumnDataType.toExternal()`
in the multi-stage engine `FunctionOperand`
+ /// for that type. Complex types such as MAP are not supported.
+ private PinotDataType getObjectArgumentType(TransformResultMetadata
argumentMetadata) {
+ DataType dataType = argumentMetadata.getDataType();
+ boolean singleValue = argumentMetadata.isSingleValue();
+ switch (dataType) {
+ case INT:
+ return singleValue ? PinotDataType.INT :
PinotDataType.PRIMITIVE_INT_ARRAY;
+ case LONG:
+ return singleValue ? PinotDataType.LONG :
PinotDataType.PRIMITIVE_LONG_ARRAY;
+ case FLOAT:
+ return singleValue ? PinotDataType.FLOAT :
PinotDataType.PRIMITIVE_FLOAT_ARRAY;
+ case DOUBLE:
+ return singleValue ? PinotDataType.DOUBLE :
PinotDataType.PRIMITIVE_DOUBLE_ARRAY;
+ case BIG_DECIMAL:
+ return singleValue ? PinotDataType.BIG_DECIMAL :
PinotDataType.BIG_DECIMAL_ARRAY;
+ case BOOLEAN:
+ return singleValue ? PinotDataType.BOOLEAN :
PinotDataType.PRIMITIVE_BOOLEAN_ARRAY;
+ case TIMESTAMP:
+ return singleValue ? PinotDataType.TIMESTAMP :
PinotDataType.TIMESTAMP_ARRAY;
+ case STRING:
+ case JSON:
+ return singleValue ? PinotDataType.STRING : PinotDataType.STRING_ARRAY;
+ case BYTES:
+ return singleValue ? PinotDataType.BYTES : PinotDataType.BYTES_ARRAY;
+ case UUID:
+ return singleValue ? PinotDataType.UUID : PinotDataType.UUID_ARRAY;
+ default:
+ throw new IllegalArgumentException(
+ String.format("Unsupported argument type: %s for Object parameter
of method: %s", dataType,
+ _functionInvoker.getMethod()));
+ }
+ }
+
+ /// Helper method to fetch values for the non-literal transform functions
based on the parameter types. For an
+ /// `Object` parameter, the values are read based on the argument result
type (see [#getObjectArgumentType]).
private void getNonLiteralValues(ValueBlock valueBlock) {
- PinotDataType[] parameterTypes = _functionInvoker.getParameterTypes();
for (int i = 0; i < _numNonLiteralArguments; i++) {
- PinotDataType parameterType = parameterTypes[_nonLiteralIndices[i]];
+ PinotDataType parameterType = _nonLiteralTypes[i];
TransformFunction transformFunction = _nonLiteralFunctions[i];
switch (parameterType) {
case INT:
@@ -485,6 +525,22 @@ public class ScalarTransformFunctionWrapper extends
BaseTransformFunction {
case BYTES_ARRAY:
_nonLiteralValues[i] =
transformFunction.transformToBytesValuesMV(valueBlock);
break;
+ case UUID_ARRAY: {
+ byte[][][] bytesValuesMV =
transformFunction.transformToBytesValuesMV(valueBlock);
+ int numRows = bytesValuesMV.length;
+ UUID[][] uuidValuesMV = new UUID[numRows][];
+ for (int j = 0; j < numRows; j++) {
+ byte[][] bytesValues = bytesValuesMV[j];
+ int numValues = bytesValues.length;
+ UUID[] uuidValues = new UUID[numValues];
+ for (int k = 0; k < numValues; k++) {
+ uuidValues[k] = UuidUtils.toUUID(bytesValues[k]);
+ }
+ uuidValuesMV[j] = uuidValues;
+ }
+ _nonLiteralValues[i] = uuidValuesMV;
+ break;
+ }
default:
throw new IllegalStateException("Unsupported parameter type: " +
parameterType);
}
diff --git
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapperTest.java
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapperTest.java
index 7beecd92954..50e9775d257 100644
---
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapperTest.java
+++
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/ScalarTransformFunctionWrapperTest.java
@@ -49,6 +49,7 @@ import org.apache.pinot.spi.utils.BigDecimalUtils;
import org.apache.pinot.spi.utils.CommonConstants.NullValuePlaceHolder;
import org.apache.pinot.spi.utils.UuidUtils;
import org.roaringbitmap.RoaringBitmap;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
@@ -1712,6 +1713,52 @@ public class ScalarTransformFunctionWrapperTest extends
BaseTransformFunctionTes
testTransformFunction(transformFunction, expectedValues);
}
+ // Test-only scalar function with an `Object` parameter, registered the same
way as the ones above. It returns the
+ // Java class of the argument, so the test below can check which class an
`Object` parameter receives per type.
+
+ @ScalarFunction
+ public static String objectArgumentClass(Object value) {
+ return value.getClass().getSimpleName();
+ }
+
+ @DataProvider
+ public static Object[][] objectArgumentClassDataProvider() {
+ // The argument should be the external Java value, the same as
ColumnDataType.toExternal() in the multi-stage
+ // engine FunctionOperand.
+ return new Object[][]{
+ {INT_SV_COLUMN, "Integer"},
+ {LONG_SV_COLUMN, "Long"},
+ {FLOAT_SV_COLUMN, "Float"},
+ {DOUBLE_SV_COLUMN, "Double"},
+ {BIG_DECIMAL_SV_COLUMN, "BigDecimal"},
+ {String.format("CAST(%s AS BOOLEAN)", INT_SV_COLUMN), "Boolean"},
+ {TIMESTAMP_COLUMN, "Timestamp"},
+ {STRING_SV_COLUMN, "String"},
+ {JSON_COLUMN, "String"},
+ {BYTES_SV_COLUMN, "byte[]"},
+ {UUID_SV_COLUMN, "UUID"},
+ {INT_MV_COLUMN, "int[]"},
+ {LONG_MV_COLUMN, "long[]"},
+ {FLOAT_MV_COLUMN, "float[]"},
+ {DOUBLE_MV_COLUMN, "double[]"},
+ {String.format("CAST(%s AS BIG_DECIMAL)", INT_MV_COLUMN),
"BigDecimal[]"},
+ {String.format("CAST(%s AS BOOLEAN)", INT_MV_COLUMN), "boolean[]"},
+ {String.format("CAST(%s AS TIMESTAMP)", LONG_MV_COLUMN),
"Timestamp[]"},
+ {STRING_MV_COLUMN, "String[]"}
+ };
+ }
+
+ @Test(dataProvider = "objectArgumentClassDataProvider")
+ public void testObjectParameter(String argument, String expectedClass) {
+ ExpressionContext expression =
+
RequestContextUtils.getExpression(String.format("objectArgumentClass(%s)",
argument));
+ TransformFunction transformFunction =
TransformFunctionFactory.get(expression, _dataSourceMap);
+ assertTrue(transformFunction instanceof ScalarTransformFunctionWrapper);
+ String[] expectedValues = new String[NUM_ROWS];
+ Arrays.fill(expectedValues, expectedClass);
+ testTransformFunction(transformFunction, expectedValues);
+ }
+
private static class StaticUuidTransformFunction extends
BaseTransformFunction {
private static final TransformResultMetadata RESULT_METADATA =
new TransformResultMetadata(DataType.UUID, true, false);
diff --git
a/pinot-core/src/test/java/org/apache/pinot/queries/ObjectParameterScalarFunctionsQueriesTest.java
b/pinot-core/src/test/java/org/apache/pinot/queries/ObjectParameterScalarFunctionsQueriesTest.java
new file mode 100644
index 00000000000..870b071662f
--- /dev/null
+++
b/pinot-core/src/test/java/org/apache/pinot/queries/ObjectParameterScalarFunctionsQueriesTest.java
@@ -0,0 +1,195 @@
+/**
+ * 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.queries;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.apache.pinot.common.function.scalar.StringFunctions;
+import org.apache.pinot.common.response.broker.BrokerResponseNative;
+import org.apache.pinot.core.function.scalar.SketchFunctions;
+import
org.apache.pinot.segment.local.indexsegment.immutable.ImmutableSegmentLoader;
+import
org.apache.pinot.segment.local.segment.creator.impl.SegmentIndexCreationDriverImpl;
+import org.apache.pinot.segment.local.segment.readers.GenericRowRecordReader;
+import org.apache.pinot.segment.spi.ImmutableSegment;
+import org.apache.pinot.segment.spi.IndexSegment;
+import org.apache.pinot.segment.spi.creator.SegmentGeneratorConfig;
+import org.apache.pinot.spi.config.table.TableConfig;
+import org.apache.pinot.spi.config.table.TableType;
+import org.apache.pinot.spi.data.FieldSpec.DataType;
+import org.apache.pinot.spi.data.Schema;
+import org.apache.pinot.spi.data.readers.GenericRow;
+import org.apache.pinot.spi.utils.ReadMode;
+import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+
+/// Queries test for scalar functions with an `Object` parameter (e.g. the
sketch functions and `jsonFormat`) on column
+/// arguments. The function should get the external Java value of the column
type.
+public class ObjectParameterScalarFunctionsQueriesTest extends BaseQueriesTest
{
+ private static final File INDEX_DIR =
+ new File(FileUtils.getTempDirectory(),
"ObjectParameterScalarFunctionsQueriesTest");
+ private static final String RAW_TABLE_NAME = "testTable";
+ private static final String SEGMENT_NAME = "testSegment";
+
+ private static final String INT_COLUMN = "intCol";
+ private static final String LONG_COLUMN = "longCol";
+ private static final String FLOAT_COLUMN = "floatCol";
+ private static final String DOUBLE_COLUMN = "doubleCol";
+ private static final String BIG_DECIMAL_COLUMN = "bigDecimalCol";
+ private static final String BOOLEAN_COLUMN = "booleanCol";
+ private static final String TIMESTAMP_COLUMN = "timestampCol";
+ private static final String STRING_COLUMN = "stringCol";
+ private static final String BYTES_COLUMN = "bytesCol";
+ private static final String UUID_COLUMN = "uuidCol";
+ private static final String INT_MV_COLUMN = "intMVCol";
+ private static final String BOOLEAN_MV_COLUMN = "booleanMVCol";
+ private static final String STRING_MV_COLUMN = "stringMVCol";
+ private static final String BYTES_MV_COLUMN = "bytesMVCol";
+ private static final String UUID_MV_COLUMN = "uuidMVCol";
+ private static final String UUID_1 = "550e8400-e29b-41d4-a716-446655440000";
+ private static final String UUID_2 = "123e4567-e89b-12d3-a456-426614174000";
+ private static final Schema SCHEMA = new Schema.SchemaBuilder()
+ .addSingleValueDimension(INT_COLUMN, DataType.INT)
+ .addSingleValueDimension(LONG_COLUMN, DataType.LONG)
+ .addSingleValueDimension(FLOAT_COLUMN, DataType.FLOAT)
+ .addSingleValueDimension(DOUBLE_COLUMN, DataType.DOUBLE)
+ .addMetric(BIG_DECIMAL_COLUMN, DataType.BIG_DECIMAL)
+ .addSingleValueDimension(BOOLEAN_COLUMN, DataType.BOOLEAN)
+ .addSingleValueDimension(TIMESTAMP_COLUMN, DataType.TIMESTAMP)
+ .addSingleValueDimension(STRING_COLUMN, DataType.STRING)
+ .addSingleValueDimension(BYTES_COLUMN, DataType.BYTES)
+ .addSingleValueDimension(UUID_COLUMN, DataType.UUID)
+ .addMultiValueDimension(INT_MV_COLUMN, DataType.INT)
+ .addMultiValueDimension(BOOLEAN_MV_COLUMN, DataType.BOOLEAN)
+ .addMultiValueDimension(STRING_MV_COLUMN, DataType.STRING)
+ .addMultiValueDimension(BYTES_MV_COLUMN, DataType.BYTES)
+ .addMultiValueDimension(UUID_MV_COLUMN, DataType.UUID)
+ .build();
+ private static final TableConfig TABLE_CONFIG =
+ new
TableConfigBuilder(TableType.OFFLINE).setTableName(RAW_TABLE_NAME).build();
+
+ private IndexSegment _indexSegment;
+ private List<IndexSegment> _indexSegments;
+
+ @Override
+ protected String getFilter() {
+ return "";
+ }
+
+ @Override
+ protected IndexSegment getIndexSegment() {
+ return _indexSegment;
+ }
+
+ @Override
+ protected List<IndexSegment> getIndexSegments() {
+ return _indexSegments;
+ }
+
+ @BeforeClass
+ public void setUp()
+ throws Exception {
+ FileUtils.deleteDirectory(INDEX_DIR);
+
+ GenericRow record = new GenericRow();
+ record.putValue(INT_COLUMN, 1);
+ record.putValue(LONG_COLUMN, 2L);
+ record.putValue(FLOAT_COLUMN, 1.5f);
+ record.putValue(DOUBLE_COLUMN, 2.5);
+ record.putValue(BIG_DECIMAL_COLUMN, new BigDecimal("3.25"));
+ record.putValue(BOOLEAN_COLUMN, true);
+ record.putValue(TIMESTAMP_COLUMN, 1700000000000L);
+ record.putValue(STRING_COLUMN, "abc");
+ record.putValue(BYTES_COLUMN, new byte[]{1, 2, 3});
+ record.putValue(UUID_COLUMN, UUID_1);
+ record.putValue(INT_MV_COLUMN, new Object[]{1, 2});
+ record.putValue(BOOLEAN_MV_COLUMN, new Object[]{true, false});
+ record.putValue(STRING_MV_COLUMN, new Object[]{"a", "b"});
+ record.putValue(BYTES_MV_COLUMN, new Object[]{new byte[]{1, 2}, new
byte[]{3}});
+ record.putValue(UUID_MV_COLUMN, new Object[]{UUID_1, UUID_2});
+
+ SegmentGeneratorConfig segmentGeneratorConfig = new
SegmentGeneratorConfig(TABLE_CONFIG, SCHEMA);
+ segmentGeneratorConfig.setTableName(RAW_TABLE_NAME);
+ segmentGeneratorConfig.setSegmentName(SEGMENT_NAME);
+ segmentGeneratorConfig.setOutDir(INDEX_DIR.getPath());
+
+ SegmentIndexCreationDriverImpl driver = new
SegmentIndexCreationDriverImpl();
+ driver.init(segmentGeneratorConfig, new
GenericRowRecordReader(List.of(record)));
+ driver.build();
+
+ ImmutableSegment immutableSegment = ImmutableSegmentLoader.load(new
File(INDEX_DIR, SEGMENT_NAME), ReadMode.mmap);
+ _indexSegment = immutableSegment;
+ _indexSegments = List.of(immutableSegment, immutableSegment);
+ }
+
+ @Test
+ public void testSketchFunctions() {
+ String query = "SELECT toBase64(toThetaSketch(intCol)),
toBase64(toHLL(longCol)), "
+ + "toBase64(toCpcSketch(doubleCol)), toBase64(toULL(stringCol)), "
+ + "toBase64(toIntegerSumTupleSketch(bigDecimalCol, intCol)),
toBase64(toThetaSketch(bytesCol)), "
+ + "getThetaSketchEstimate(toThetaSketch(floatCol)) FROM testTable
LIMIT 1";
+ Object[] expectedRow = new Object[]{
+ StringFunctions.toBase64(SketchFunctions.toThetaSketch(1)),
+ StringFunctions.toBase64(SketchFunctions.toHLL(2L)),
+ StringFunctions.toBase64(SketchFunctions.toCpcSketch(2.5)),
+ StringFunctions.toBase64(SketchFunctions.toULL("abc")),
+ StringFunctions.toBase64(SketchFunctions.toIntegerSumTupleSketch(new
BigDecimal("3.25"), 1)),
+ StringFunctions.toBase64(SketchFunctions.toThetaSketch(new byte[]{1,
2, 3})),
+ 1L
+ };
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0), expectedRow);
+ }
+
+ @Test
+ public void testJsonFormat() {
+ String query = "SELECT jsonFormat(intCol), jsonFormat(longCol),
jsonFormat(floatCol), jsonFormat(doubleCol), "
+ + "jsonFormat(bigDecimalCol), jsonFormat(booleanCol),
jsonFormat(timestampCol), jsonFormat(stringCol), "
+ + "jsonFormat(bytesCol), jsonFormat(uuidCol), jsonFormat(intMVCol),
jsonFormat(booleanMVCol), "
+ + "jsonFormat(stringMVCol), jsonFormat(bytesMVCol),
jsonFormat(uuidMVCol) FROM testTable LIMIT 1";
+ Object[] expectedRow = new Object[]{
+ "1", "2", "1.5", "2.5", "3.25", "true", "1700000000000", "\"abc\"",
"\"AQID\"", "\"" + UUID_1 + "\"",
+ "[1,2]", "[true,false]", "[\"a\",\"b\"]", "[\"AQI=\",\"Aw==\"]", "[\""
+ UUID_1 + "\",\"" + UUID_2 + "\"]"
+ };
+ List<Object[]> rows = getRows(query);
+ assertEquals(rows.size(), 1);
+ assertEquals(rows.get(0), expectedRow);
+ }
+
+ private List<Object[]> getRows(String query) {
+ BrokerResponseNative brokerResponse = getBrokerResponse(query);
+ assertTrue(brokerResponse.getExceptions().isEmpty(),
brokerResponse.getExceptions().toString());
+ return brokerResponse.getResultTable().getRows();
+ }
+
+ @AfterClass
+ public void tearDown()
+ throws Exception {
+ _indexSegment.destroy();
+ FileUtils.deleteDirectory(INDEX_DIR);
+ }
+}
diff --git
a/pinot-query-runtime/src/test/resources/queries/ObjectParameterFunctions.json
b/pinot-query-runtime/src/test/resources/queries/ObjectParameterFunctions.json
new file mode 100644
index 00000000000..f12874602e6
--- /dev/null
+++
b/pinot-query-runtime/src/test/resources/queries/ObjectParameterFunctions.json
@@ -0,0 +1,60 @@
+{
+ "object_parameter_functions": {
+ "comments": "Scalar functions with an Object parameter get the external
Java value of the column type. In the leaf stage the call runs in
ScalarTransformFunctionWrapper, above a stage boundary it runs in
FunctionOperand; for column arguments both must return the same result.",
+ "tables": {
+ "tbl": {
+ "schema": [
+ {"name": "intCol", "type": "INT"},
+ {"name": "longCol", "type": "LONG"},
+ {"name": "floatCol", "type": "FLOAT"},
+ {"name": "doubleCol", "type": "DOUBLE"},
+ {"name": "bigDecimalCol", "type": "BIG_DECIMAL"},
+ {"name": "boolCol", "type": "BOOLEAN"},
+ {"name": "strCol", "type": "STRING"},
+ {"name": "bytesCol", "type": "BYTES"},
+ {"name": "intArrayCol", "type": "INT", "isSingleValue": false},
+ {"name": "strArrayCol", "type": "STRING", "isSingleValue": false}
+ ],
+ "inputs": [
+ [1, 10000000001, 1.5, 1.25, "1.125", true, "a", "AA01", [1, 2],
["a", "b"]],
+ ["------"],
+ [2, 10000000002, 2.5, 2.25, "2.375", false, "b", "AA02", [3], ["c"]]
+ ]
+ }
+ },
+ "queries": [
+ {
+ "description": "jsonFormat on columns in the leaf stage",
+ "sql": "SELECT intCol, jsonFormat(intCol), jsonFormat(longCol),
jsonFormat(floatCol), jsonFormat(doubleCol), jsonFormat(bigDecimalCol),
jsonFormat(boolCol), jsonFormat(strCol), jsonFormat(bytesCol),
jsonFormat(intArrayCol), jsonFormat(strArrayCol) FROM {tbl}",
+ "outputs": [
+ [1, "1", "10000000001", "1.5", "1.25", "1.125", "true", "\"a\"",
"\"qgE=\"", "[1,2]", "[\"a\",\"b\"]"],
+ [2, "2", "10000000002", "2.5", "2.25", "2.375", "false", "\"b\"",
"\"qgI=\"", "[3]", "[\"c\"]"]
+ ]
+ },
+ {
+ "description": "jsonFormat on columns above a stage boundary",
+ "sql": "SELECT intCol, jsonFormat(intCol), jsonFormat(longCol),
jsonFormat(floatCol), jsonFormat(doubleCol), jsonFormat(bigDecimalCol),
jsonFormat(boolCol), jsonFormat(strCol), jsonFormat(bytesCol),
jsonFormat(intArrayCol), jsonFormat(strArrayCol) FROM (SELECT * FROM {tbl}
ORDER BY intCol LIMIT 10)",
+ "outputs": [
+ [1, "1", "10000000001", "1.5", "1.25", "1.125", "true", "\"a\"",
"\"qgE=\"", "[1,2]", "[\"a\",\"b\"]"],
+ [2, "2", "10000000002", "2.5", "2.25", "2.375", "false", "\"b\"",
"\"qgI=\"", "[3]", "[\"c\"]"]
+ ]
+ },
+ {
+ "description": "toThetaSketch on a column in the leaf stage",
+ "sql": "SELECT intCol, toBase64(toThetaSketch(intCol)) FROM {tbl}",
+ "outputs": [
+ [1, "AQMDAAA6zJMV+X3LvYahBQ=="],
+ [2, "AQMDAAA6zJPDl/wSgXCdHg=="]
+ ]
+ },
+ {
+ "description": "toThetaSketch on a column above a stage boundary",
+ "sql": "SELECT intCol, toBase64(toThetaSketch(intCol)) FROM (SELECT
intCol FROM {tbl} GROUP BY intCol)",
+ "outputs": [
+ [1, "AQMDAAA6zJMV+X3LvYahBQ=="],
+ [2, "AQMDAAA6zJPDl/wSgXCdHg=="]
+ ]
+ }
+ ]
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]