diff --git a/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionRegistry.java b/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionRegistry.java index 2c2ba9a3244b..b6edfdec0700 100644 --- a/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionRegistry.java +++ b/pinot-common/src/main/java/org/apache/pinot/common/function/FunctionRegistry.java @@ -216,5 +216,11 @@ public static Object clpDecode(String logtypeFieldName, String dictVarsFieldName String defaultValue) { throw new UnsupportedOperationException("Placeholder scalar function, should not reach here"); } + + @ScalarFunction(names = {"arrayToMV", "array_to_mv"}, + isPlaceholder = true) + public static String arrayToMV(Object multiValue) { + throw new UnsupportedOperationException("Placeholder scalar function, should not reach here"); + } } } diff --git a/pinot-common/src/main/java/org/apache/pinot/common/function/TransformFunctionType.java b/pinot-common/src/main/java/org/apache/pinot/common/function/TransformFunctionType.java index 2ae2f8060371..0aa780ec96e9 100644 --- a/pinot-common/src/main/java/org/apache/pinot/common/function/TransformFunctionType.java +++ b/pinot-common/src/main/java/org/apache/pinot/common/function/TransformFunctionType.java @@ -90,6 +90,11 @@ public enum TransformFunctionType { // date type conversion functions CAST("cast"), + // object type + ARRAY_TO_MV("arrayToMV", + ReturnTypes.cascade(opBinding -> positionalComponentReturnType(opBinding, 0), SqlTypeTransforms.FORCE_NULLABLE), + OperandTypes.family(SqlTypeFamily.ARRAY), "array_to_mv"), + // string functions JSONEXTRACTSCALAR("jsonExtractScalar", ReturnTypes.cascade(opBinding -> positionalReturnTypeInferenceFromStringLiteral(opBinding, 2, @@ -280,6 +285,13 @@ private static RelDataType positionalReturnTypeInferenceFromStringLiteral(SqlOpe return opBinding.getTypeFactory().createSqlType(defaultSqlType); } + private static RelDataType positionalComponentReturnType(SqlOperatorBinding opBinding, int pos) { + if (opBinding.getOperandCount() > pos) { + return opBinding.getOperandType(pos).getComponentType(); + } + throw new IllegalArgumentException("Invalid number of arguments for function " + opBinding.getOperator().getName()); + } + private static RelDataType dateTimeConverterReturnTypeInference(SqlOperatorBinding opBinding) { int outputFormatPos = 2; if (opBinding.getOperandCount() > outputFormatPos 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 783a7a205302..3f706bf566e8 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 @@ -306,7 +306,7 @@ public static TransformFunction get(ExpressionContext expression, Map _multistageSingleValuePredicateGenerators = Arrays.asList(new SingleValueComparisonPredicateGenerator(), new SingleValueInPredicateGenerator(), new SingleValueBetweenPredicateGenerator()); + // TODO: add MultiValueBetweenPredicateGenerator back once the BETWEEEN AND operator is supported in multistage engine private final List _multiValuePredicateGenerators = - Arrays.asList(new MultiValueComparisonPredicateGenerator(), new MultiValueInPredicateGenerator(), - new MultiValueBetweenPredicateGenerator()); + Arrays.asList(new MultiValueComparisonPredicateGenerator(), new MultiValueInPredicateGenerator()); private final String _pinotTableName; private final String _h2TableName; @@ -351,10 +351,12 @@ private PredicateQueryFragment generatePredicate() { if (!_columnToValueList.get(columnName).isEmpty()) { if (!_multiValueColumnMaxNumElements.containsKey(columnName)) { // Single-value column. - predicates.add(pickRandom(getSingleValuePredicateGenerators()).generatePredicate(columnName)); + predicates.add(pickRandom(getSingleValuePredicateGenerators()).generatePredicate(columnName, + _useMultistageEngine)); } else if (!_skipMultiValuePredicates) { // Multi-value column. - predicates.add(pickRandom(_multiValuePredicateGenerators).generatePredicate(columnName)); + predicates.add( + pickRandom(_multiValuePredicateGenerators).generatePredicate(columnName, _useMultistageEngine)); } } } @@ -407,10 +409,11 @@ private interface PredicateGenerator { /** * Generate a predicate query fragment on a column. * - * @param columnName column name. + * @param columnName column name. + * @param useMultistageEngine * @return generated predicate query fragment. */ - QueryFragment generatePredicate(String columnName); + QueryFragment generatePredicate(String columnName, boolean useMultistageEngine); } /** @@ -485,16 +488,47 @@ public AggregationQuery(List aggregateColumnsAndFunctions, PredicateQuer @Override public String generatePinotQuery() { + List pinotAggregateColumnAndFunctions = + (_useMultistageEngine && !_skipMultiValuePredicates) ? generatePinotMultistageQuery() + : _aggregateColumnsAndFunctions; if (_groupColumns.isEmpty()) { - return joinWithSpaces("SELECT", StringUtils.join(_aggregateColumnsAndFunctions, ", "), "FROM", _pinotTableName, - _predicate.generatePinotQuery()); + return joinWithSpaces("SELECT", StringUtils.join(pinotAggregateColumnAndFunctions, ", "), "FROM", + _pinotTableName, _predicate.generatePinotQuery()); } else { - return joinWithSpaces("SELECT", StringUtils.join(_aggregateColumnsAndFunctions, ", "), "FROM", _pinotTableName, - _predicate.generatePinotQuery(), "GROUP BY", StringUtils.join(_groupColumns, ", "), + return joinWithSpaces("SELECT", StringUtils.join(pinotAggregateColumnAndFunctions, ", "), "FROM", + _pinotTableName, _predicate.generatePinotQuery(), "GROUP BY", StringUtils.join(_groupColumns, ", "), _havingPredicate.generatePinotQuery(), _limit.generatePinotQuery()); } } + public List generatePinotMultistageQuery() { + List pinotAggregateColumnAndFunctions = new ArrayList<>(); + for (String aggregateColumnAndFunction : _aggregateColumnsAndFunctions) { + String pinotAggregateFunction = aggregateColumnAndFunction; + String pinotAggregateColumnAndFunction = pinotAggregateFunction; + if (!pinotAggregateFunction.equals("COUNT(*)")) { + pinotAggregateFunction = pinotAggregateFunction.replace("(", "(`").replace(")", "`)"); + } + if (!pinotAggregateFunction.contains("(")) { + pinotAggregateFunction = String.format("`%s`", pinotAggregateFunction); + } + if (AGGREGATION_FUNCTIONS.contains(pinotAggregateFunction.substring(0, 3))) { + // For multistage query, we need to explicit hoist the data type to avoid overflow. + String aggFunctionName = pinotAggregateFunction.substring(0, 3); + String replacedPinotAggregationFunction = + pinotAggregateFunction.replace(aggFunctionName + "(", aggFunctionName + "(CAST("); + if ("SUM".equalsIgnoreCase(aggFunctionName)) { + pinotAggregateColumnAndFunction = replacedPinotAggregationFunction.replace(")", " AS BIGINT))"); + } + if ("AVG".equalsIgnoreCase(aggFunctionName)) { + pinotAggregateColumnAndFunction = replacedPinotAggregationFunction.replace(")", " AS DOUBLE))"); + } + } + pinotAggregateColumnAndFunctions.add(pinotAggregateColumnAndFunction); + } + return pinotAggregateColumnAndFunctions; + } + @Override public String generateH2Query() { List h2AggregateColumnAndFunctions = new ArrayList<>(); @@ -923,7 +957,7 @@ private String generateRandomValue(boolean generateInt) { private class SingleValueComparisonPredicateGenerator implements PredicateGenerator { @Override - public QueryFragment generatePredicate(String columnName) { + public QueryFragment generatePredicate(String columnName, boolean useMultistageEngine) { String columnValue = pickRandom(_columnToValueList.get(columnName)); String comparisonOperator = pickRandom(COMPARISON_OPERATORS); return new StringQueryFragment(joinWithSpaces(columnName, comparisonOperator, columnValue), @@ -937,7 +971,7 @@ public QueryFragment generatePredicate(String columnName) { private class SingleValueInPredicateGenerator implements PredicateGenerator { @Override - public QueryFragment generatePredicate(String columnName) { + public QueryFragment generatePredicate(String columnName, boolean useMultistageEngine) { List columnValues = _columnToValueList.get(columnName); int numValues = Math.min(RANDOM.nextInt(MAX_NUM_IN_CLAUSE_VALUES) + 1, columnValues.size()); @@ -964,7 +998,7 @@ public QueryFragment generatePredicate(String columnName) { private class SingleValueBetweenPredicateGenerator implements PredicateGenerator { @Override - public QueryFragment generatePredicate(String columnName) { + public QueryFragment generatePredicate(String columnName, boolean useMultistageEngine) { List columnValues = _columnToValueList.get(columnName); String leftValue = pickRandom(columnValues); String rightValue = pickRandom(columnValues); @@ -981,7 +1015,7 @@ private class SingleValueRegexPredicateGenerator implements PredicateGenerator { Random _random = new Random(); @Override - public QueryFragment generatePredicate(String columnName) { + public QueryFragment generatePredicate(String columnName, boolean useMultistageEngine) { List columnValues = _columnToValueList.get(columnName); String value = pickRandom(columnValues); // do regex only for string type @@ -1008,7 +1042,7 @@ public QueryFragment generatePredicate(String columnName) { private class MultiValueComparisonPredicateGenerator implements PredicateGenerator { @Override - public QueryFragment generatePredicate(String columnName) { + public QueryFragment generatePredicate(String columnName, boolean useMultistageEngine) { String columnValue = pickRandom(_columnToValueList.get(columnName)); String comparisonOperator = pickRandom(COMPARISON_OPERATORS); @@ -1024,7 +1058,8 @@ public QueryFragment generatePredicate(String columnName) { joinWithSpaces(String.format("%s[%d]", columnName, i), comparisonOperator, columnValue)); } - return new StringQueryFragment(joinWithSpaces(columnName, comparisonOperator, columnValue), + return new StringQueryFragment( + joinWithSpaces(generateMultiValueColumn(columnName, useMultistageEngine), comparisonOperator, columnValue), generateH2QueryConditionPredicate(h2ComparisonClauses)); } } @@ -1036,7 +1071,7 @@ public QueryFragment generatePredicate(String columnName) { private class MultiValueInPredicateGenerator implements PredicateGenerator { @Override - public QueryFragment generatePredicate(String columnName) { + public QueryFragment generatePredicate(String columnName, boolean useMultistageEngine) { List columnValues = _columnToValueList.get(columnName); int numValues = Math.min(RANDOM.nextInt(MAX_NUM_IN_CLAUSE_VALUES) + 1, columnValues.size()); @@ -1052,7 +1087,8 @@ public QueryFragment generatePredicate(String columnName) { h2InClauses.add(String.format("%s[%d] IN (%s)", columnName, i, inValues)); } - return new StringQueryFragment(String.format("%s IN (%s)", columnName, inValues), + return new StringQueryFragment( + String.format("%s IN (%s)", generateMultiValueColumn(columnName, useMultistageEngine), inValues), generateH2QueryConditionPredicate(h2InClauses)); } } @@ -1063,7 +1099,7 @@ public QueryFragment generatePredicate(String columnName) { private class MultiValueBetweenPredicateGenerator implements PredicateGenerator { @Override - public QueryFragment generatePredicate(String columnName) { + public QueryFragment generatePredicate(String columnName, boolean useMultistageEngine) { List columnValues = _columnToValueList.get(columnName); String leftValue = pickRandom(columnValues); String rightValue = pickRandom(columnValues); @@ -1074,13 +1110,24 @@ public QueryFragment generatePredicate(String columnName) { h2ComparisonClauses.add(String.format("%s[%d] BETWEEN %s AND %s", columnName, i, leftValue, rightValue)); } - return new StringQueryFragment(String.format("%s BETWEEN %s AND %s", columnName, leftValue, rightValue), + return new StringQueryFragment( + String.format("%s BETWEEN %s AND %s", generateMultiValueColumn(columnName, useMultistageEngine), leftValue, + rightValue), generateH2QueryConditionPredicate(h2ComparisonClauses)); } } + + private String generateMultiValueColumn(String columnName, boolean useMultistageEngine) { + if (useMultistageEngine) { + return String.format("ARRAY_TO_MV(%s)", columnName); + } + return columnName; + } + private static String generateH2QueryConditionPredicate(List conditionList) { return generateH2QueryConditionPredicate(conditionList, " OR "); } + private static String generateH2QueryConditionPredicate(List conditionList, String separator) { return String.format("( %s )", StringUtils.join(conditionList, separator)); } diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BaseClusterIntegrationTestSet.java b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BaseClusterIntegrationTestSet.java index 8331d10235d5..b7f32c79c38c 100644 --- a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BaseClusterIntegrationTestSet.java +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BaseClusterIntegrationTestSet.java @@ -101,17 +101,6 @@ protected void cleanupTestTableDataManager(String tableNameWithType) { }, 600_000L, "Failed to delete table data managers"); } - /** - * Test features supported in V2 Multi-stage Engine. - * - Some V1 features will not be supported. - * - Some V1 features will be added as V2 engine feature development progresses. - * @throws Exception - */ - public void testHardcodedQueriesMultiStage() - throws Exception { - testHardcodedQueriesCommon(); - } - /** * Test hard-coded queries. * @throws Exception @@ -119,7 +108,11 @@ public void testHardcodedQueriesMultiStage() public void testHardcodedQueries() throws Exception { testHardcodedQueriesCommon(); - testHardCodedQueriesV1(); + if (useMultiStageQueryEngine()) { + testHardcodedQueriesV2(); + } else { + testHardCodedQueriesV1(); + } } /** @@ -282,6 +275,29 @@ private void testHardcodedQueriesCommon() testQuery(query, h2Query); } + private void testHardcodedQueriesV2() + throws Exception { + String query; + String h2Query; + + query = + "SELECT DistanceGroup FROM mytable WHERE \"Month\" BETWEEN 1 AND 1 AND arrayToMV(DivAirportSeqIDs) IN " + + "(1078102, 1142303, 1530402, 1172102, 1291503) OR SecurityDelay IN (1, 0, 14, -9999) LIMIT 10"; + h2Query = + "SELECT DistanceGroup FROM mytable WHERE `Month` BETWEEN 1 AND 1 AND (DivAirportSeqIDs[1] IN (1078102, " + + "1142303, 1530402, 1172102, 1291503) OR DivAirportSeqIDs[2] IN (1078102, 1142303, 1530402, 1172102, " + + "1291503) OR DivAirportSeqIDs[3] IN (1078102, 1142303, 1530402, 1172102, 1291503) OR " + + "DivAirportSeqIDs[4] IN (1078102, 1142303, 1530402, 1172102, 1291503) OR DivAirportSeqIDs[5] IN " + + "(1078102, 1142303, 1530402, 1172102, 1291503)) OR SecurityDelay IN (1, 0, 14, -9999) LIMIT 10000"; + testQuery(query, h2Query); + + query = "SELECT MIN(ArrDelayMinutes), AVG(CAST(DestCityMarketID AS DOUBLE)) FROM mytable WHERE DivArrDelay < 196"; + h2Query = + "SELECT MIN(CAST(`ArrDelayMinutes` AS DOUBLE)), AVG(CAST(`DestCityMarketID` AS DOUBLE)) FROM mytable WHERE " + + "`DivArrDelay` < 196"; + testQuery(query, h2Query); + } + private void testHardCodedQueriesV1() throws Exception { String query; @@ -295,17 +311,6 @@ private void testHardCodedQueriesV1() "SELECT CAST(CAST(ArrTime AS varchar) AS LONG) FROM mytable WHERE DaysSinceEpoch <> 16312 AND Carrier = 'DL' " + "ORDER BY ArrTime DESC"; testQuery(query); - // TODO: move to common when multistage support MV columns - query = - "SELECT DistanceGroup FROM mytable WHERE \"Month\" BETWEEN 1 AND 1 AND DivAirportSeqIDs IN (1078102, 1142303," - + " 1530402, 1172102, 1291503) OR SecurityDelay IN (1, 0, 14, -9999) LIMIT 10"; - h2Query = - "SELECT DistanceGroup FROM mytable WHERE `Month` BETWEEN 1 AND 1 AND (DivAirportSeqIDs[1] IN (1078102, " - + "1142303, 1530402, 1172102, 1291503) OR DivAirportSeqIDs[2] IN (1078102, 1142303, 1530402, 1172102, " - + "1291503) OR DivAirportSeqIDs[3] IN (1078102, 1142303, 1530402, 1172102, 1291503) OR " - + "DivAirportSeqIDs[4] IN (1078102, 1142303, 1530402, 1172102, 1291503) OR DivAirportSeqIDs[5] IN " - + "(1078102, 1142303, 1530402, 1172102, 1291503)) OR SecurityDelay IN (1, 0, 14, -9999) LIMIT 10000"; - testQuery(query, h2Query); // Non-Standard SQL syntax: // IN_ID_SET @@ -472,8 +477,13 @@ protected void testGeneratedQueries(boolean withMultiValues, boolean useMultista for (int i = 0; i < numQueriesToGenerate; i++) { QueryGenerator.Query query = queryGenerator.generateQuery(); if (useMultistageEngine) { - // multistage engine follows standard SQL thus should use H2 query string for testing. - testQuery(query.generateH2Query().replace("`", "\""), query.generateH2Query()); + if (withMultiValues) { + // For multistage query with MV columns, we need to use Pinot query string for testing. + testQuery(query.generatePinotQuery().replace("`", "\""), query.generateH2Query()); + } else { + // multistage engine follows standard SQL thus should use H2 query string for testing. + testQuery(query.generateH2Query().replace("`", "\""), query.generateH2Query()); + } } else { testQuery(query.generatePinotQuery(), query.generateH2Query()); } diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/MultiStageEngineIntegrationTest.java b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/MultiStageEngineIntegrationTest.java index c4039874b073..f74e1bd24fde 100644 --- a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/MultiStageEngineIntegrationTest.java +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/MultiStageEngineIntegrationTest.java @@ -31,6 +31,7 @@ import org.apache.pinot.spi.config.table.TableConfig; import org.apache.pinot.spi.data.Schema; import org.apache.pinot.util.TestUtils; +import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -95,17 +96,17 @@ protected boolean useMultiStageQueryEngine() { @Test @Override - public void testHardcodedQueriesMultiStage() + public void testHardcodedQueries() throws Exception { - super.testHardcodedQueriesMultiStage(); + super.testHardcodedQueries(); } @Test @Override public void testGeneratedQueries() throws Exception { - // test multistage engine, currently we don't support MV columns. super.testGeneratedQueries(false, true); + super.testGeneratedQueries(true, true); } @Test @@ -485,6 +486,25 @@ public void testLiteralOnlyFunc() assertEquals(results.get(10).asText(), "hello!"); } + @Test + public void testMultiValueColumnGroupBy() + throws Exception { + String pinotQuery = "SELECT count(*), arrayToMV(RandomAirports) FROM mytable " + + "GROUP BY arrayToMV(RandomAirports)"; + JsonNode jsonNode = postQuery(pinotQuery); + Assert.assertEquals(jsonNode.get("resultTable").get("rows").size(), 154); + } + + @Test + public void testMultiValueColumnGroupByOrderBy() + throws Exception { + String pinotQuery = "SELECT count(*), arrayToMV(RandomAirports) FROM mytable " + + "GROUP BY arrayToMV(RandomAirports) " + + "ORDER BY arrayToMV(RandomAirports) DESC"; + JsonNode jsonNode = postQuery(pinotQuery); + Assert.assertEquals(jsonNode.get("resultTable").get("rows").size(), 154); + } + @AfterClass public void tearDown() throws Exception { diff --git a/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java b/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java index 52b51f89c886..632471f6b0f2 100644 --- a/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java +++ b/pinot-query-planner/src/main/java/org/apache/pinot/query/parser/CalciteRexExpressionParser.java @@ -50,6 +50,7 @@ public class CalciteRexExpressionParser { private static final Logger LOGGER = LoggerFactory.getLogger(CalciteRexExpressionParser.class); private static final Map CANONICAL_NAME_TO_SPECIAL_KEY_MAP; + private static final String ARRAY_TO_MV_FUNCTION_NAME = "arraytomv"; static { CANONICAL_NAME_TO_SPECIAL_KEY_MAP = new HashMap<>(); @@ -199,6 +200,12 @@ private static Expression compileFunctionExpression(RexExpression.FunctionCall r return compileOrExpression(rexCall, pinotQuery); case OTHER_FUNCTION: functionName = rexCall.getFunctionName(); + // Special handle for leaf stage multi-value columns, as the default behavior for filter and group by is not + // sql standard, so need to use `array_to_mv` to convert the array to v1 multi-value column for behavior + // consistency meanwhile not violating the sql standard. + if (ARRAY_TO_MV_FUNCTION_NAME.equals(canonicalizeFunctionName(functionName))) { + return toExpression(rexCall.getFunctionOperands().get(0), pinotQuery); + } break; default: functionName = functionKind.name(); diff --git a/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RelToPlanNodeConverter.java b/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RelToPlanNodeConverter.java index 20181be6e964..d5097e7ed7ad 100644 --- a/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RelToPlanNodeConverter.java +++ b/pinot-query-planner/src/main/java/org/apache/pinot/query/planner/logical/RelToPlanNodeConverter.java @@ -63,6 +63,7 @@ import org.apache.pinot.query.planner.plannode.ValueNode; import org.apache.pinot.query.planner.plannode.WindowNode; import org.apache.pinot.spi.data.FieldSpec; +import org.slf4j.Logger; /** @@ -70,6 +71,8 @@ */ public final class RelToPlanNodeConverter { + private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(RelToPlanNodeConverter.class); + private RelToPlanNodeConverter() { // do not instantiate. } @@ -207,7 +210,7 @@ private static DataSchema toDataSchema(RelDataType rowType) { public static DataSchema.ColumnDataType convertToColumnDataType(RelDataType relDataType) { SqlTypeName sqlTypeName = relDataType.getSqlTypeName(); - boolean isArray = sqlTypeName == SqlTypeName.ARRAY; + boolean isArray = (sqlTypeName == SqlTypeName.ARRAY); if (isArray) { sqlTypeName = relDataType.getComponentType().getSqlTypeName(); } @@ -240,6 +243,10 @@ public static DataSchema.ColumnDataType convertToColumnDataType(RelDataType relD case VARBINARY: return isArray ? DataSchema.ColumnDataType.BYTES_ARRAY : DataSchema.ColumnDataType.BYTES; default: + if (relDataType.getComponentType() != null) { + throw new IllegalArgumentException("Unsupported collection type: " + relDataType); + } + LOGGER.warn("Unexpected SQL type: {}, use BYTES instead", sqlTypeName); return DataSchema.ColumnDataType.BYTES; } } diff --git a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java index 616413f3add3..51fb4fed9334 100644 --- a/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java +++ b/pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/plan/server/ServerPlanRequestUtils.java @@ -237,7 +237,7 @@ static void attachDynamicFilter(PinotQuery pinotQuery, JoinNode.JoinKeys joinKey private static List computeInOperands(List dataContainer, DataSchema dataSchema, int colIdx) { final DataSchema.ColumnDataType columnDataType = dataSchema.getColumnDataType(colIdx); - final FieldSpec.DataType storedType = columnDataType.getStoredType().toDataType();; + final FieldSpec.DataType storedType = columnDataType.getStoredType().toDataType(); final int numRows = dataContainer.size(); List expressions = new ArrayList<>(); switch (storedType) {