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 30233a1c6dd Automatically rewrite MIN / MAX on string col to MINSTRING 
/ MAXSTRING (#16980)
30233a1c6dd is described below

commit 30233a1c6dd8edcd781652c47c53fe6dc7f979f9
Author: Yash Mayya <[email protected]>
AuthorDate: Fri Oct 10 14:20:04 2025 -0700

    Automatically rewrite MIN / MAX on string col to MINSTRING / MAXSTRING 
(#16980)
---
 .../pinot/core/query/optimizer/QueryOptimizer.java |   7 +-
 .../AggregateFunctionRewriteOptimizer.java         |  98 ++++++++++++++++++
 .../tests/BaseClusterIntegrationTestSet.java       |   4 +
 .../tests/ErrorCodesIntegrationTest.java           |   8 --
 .../tests/OfflineClusterIntegrationTest.java       |   1 +
 .../rules/PinotAggregateFunctionRewriteRule.java   | 114 +++++++++++++++++++++
 .../calcite/rel/rules/PinotQueryRuleSets.java      |   3 +
 .../src/test/resources/queries/AggregatePlans.json |  48 +++++++++
 .../src/test/resources/queries/Aggregates.json     |  31 +++---
 .../apache/pinot/spi/utils/CommonConstants.java    |   1 +
 10 files changed, 284 insertions(+), 31 deletions(-)

diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/QueryOptimizer.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/QueryOptimizer.java
index a465249ec56..70151b7fec8 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/QueryOptimizer.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/QueryOptimizer.java
@@ -18,8 +18,6 @@
  */
 package org.apache.pinot.core.query.optimizer;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import javax.annotation.Nullable;
 import org.apache.pinot.common.request.Expression;
@@ -32,6 +30,7 @@ import 
org.apache.pinot.core.query.optimizer.filter.MergeRangeFilterOptimizer;
 import org.apache.pinot.core.query.optimizer.filter.NumericalFilterOptimizer;
 import org.apache.pinot.core.query.optimizer.filter.TextMatchFilterOptimizer;
 import 
org.apache.pinot.core.query.optimizer.filter.TimePredicateFilterOptimizer;
+import 
org.apache.pinot.core.query.optimizer.statement.AggregateFunctionRewriteOptimizer;
 import org.apache.pinot.core.query.optimizer.statement.StatementOptimizer;
 import 
org.apache.pinot.core.query.optimizer.statement.StringPredicateFilterOptimizer;
 import org.apache.pinot.spi.data.Schema;
@@ -45,12 +44,12 @@ public class QueryOptimizer {
   // - TimePredicateFilterOptimizer and MergeRangeFilterOptimizer relies on 
NumericalFilterOptimizer to convert the
   //   values to the proper format so that they can be properly parsed
   private static final List<FilterOptimizer> FILTER_OPTIMIZERS =
-      Arrays.asList(new FlattenAndOrFilterOptimizer(), new 
IdenticalPredicateFilterOptimizer(),
+      List.of(new FlattenAndOrFilterOptimizer(), new 
IdenticalPredicateFilterOptimizer(),
           new MergeEqInFilterOptimizer(), new NumericalFilterOptimizer(), new 
TimePredicateFilterOptimizer(),
           new MergeRangeFilterOptimizer(), new TextMatchFilterOptimizer());
 
   private static final List<StatementOptimizer> STATEMENT_OPTIMIZERS =
-      Collections.singletonList(new StringPredicateFilterOptimizer());
+      List.of(new StringPredicateFilterOptimizer(), new 
AggregateFunctionRewriteOptimizer());
 
   /**
    * Optimizes the given query.
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/statement/AggregateFunctionRewriteOptimizer.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/statement/AggregateFunctionRewriteOptimizer.java
new file mode 100644
index 00000000000..e023c820135
--- /dev/null
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/statement/AggregateFunctionRewriteOptimizer.java
@@ -0,0 +1,98 @@
+/**
+ * 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.query.optimizer.statement;
+
+import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.pinot.common.request.Expression;
+import org.apache.pinot.common.request.Function;
+import org.apache.pinot.common.request.PinotQuery;
+import org.apache.pinot.segment.spi.AggregationFunctionType;
+import org.apache.pinot.spi.data.FieldSpec;
+import org.apache.pinot.spi.data.Schema;
+
+/**
+ * Rewrites aggregate functions to type-specific versions in order to support 
polymorphic functions.
+ */
+public class AggregateFunctionRewriteOptimizer implements StatementOptimizer {
+
+  @Override
+  public void optimize(PinotQuery pinotQuery, @Nullable Schema schema) {
+    if (schema == null) {
+      return;
+    }
+
+    List<Expression> selectList = pinotQuery.getSelectList();
+    if (selectList != null) {
+      for (Expression expression : selectList) {
+        maybeRewriteAggregateFunction(expression, schema);
+      }
+    }
+
+    List<Expression> groupByList = pinotQuery.getGroupByList();
+    if (groupByList != null) {
+      for (Expression expression : groupByList) {
+        maybeRewriteAggregateFunction(expression, schema);
+      }
+    }
+
+    List<Expression> orderByList = pinotQuery.getOrderByList();
+    if (orderByList != null) {
+      for (Expression expression : orderByList) {
+        maybeRewriteAggregateFunction(expression, schema);
+      }
+    }
+
+    maybeRewriteAggregateFunction(pinotQuery.getFilterExpression(), schema);
+    maybeRewriteAggregateFunction(pinotQuery.getHavingExpression(), schema);
+  }
+
+  private void maybeRewriteAggregateFunction(@Nullable Expression expression, 
Schema schema) {
+    if (expression == null || !expression.isSetFunctionCall()) {
+      return;
+    }
+
+    Function function = expression.getFunctionCall();
+    String functionName = function.getOperator();
+    if (!AggregationFunctionType.isAggregationFunction(functionName)) {
+      return;
+    }
+
+    // Rewrite MIN(stringCol) and MAX(stringCol) to MINSTRING / MAXSTRING
+    if ((functionName.equals(AggregationFunctionType.MIN.getName())
+        || functionName.equals(AggregationFunctionType.MAX.getName()))
+        && function.getOperandsSize() == 1) {
+      Expression operand = function.getOperands().get(0);
+      // TODO: Handle more complex expressions (e.g. MIN(trim(stringCol)) )
+      if (operand.isSetIdentifier()) {
+        String columnName = operand.getIdentifier().getName();
+        if (schema != null) {
+          FieldSpec fieldSpec = schema.getFieldSpecFor(columnName);
+          if (fieldSpec != null && fieldSpec.getDataType().getStoredType() == 
FieldSpec.DataType.STRING) {
+            String newFunctionName =
+                functionName.equals(AggregationFunctionType.MIN.getName())
+                    ? AggregationFunctionType.MINSTRING.name().toLowerCase()
+                    : AggregationFunctionType.MAXSTRING.name().toLowerCase();
+            function.setOperator(newFunctionName);
+          }
+        }
+      }
+    }
+  }
+}
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 4de86eb3c6c..0a774238f83 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
@@ -326,6 +326,10 @@ public abstract class BaseClusterIntegrationTestSet 
extends BaseClusterIntegrati
             + "'DL' ORDER BY ArrTime DESC";
     testQuery(query, h2Query);
 
+    // Test MIN / MAX on STRING columns (automatically rewritten to MINSTRING 
/ MAXSTRING internally)
+    query = "SELECT MIN(OriginCityName), MAX(OriginCityName) FROM mytable";
+    testQuery(query);
+
     // Test orderedPreferredPools option which will fallbacks to non preferred 
Pools
     // when non of preferred Pools is available
     query = "SELECT count(*) FROM mytable WHERE OriginState LIKE 'A_' 
option(orderedPreferredPools=0|1)";
diff --git 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/ErrorCodesIntegrationTest.java
 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/ErrorCodesIntegrationTest.java
index 069e3fa382d..1fdc45330b2 100644
--- 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/ErrorCodesIntegrationTest.java
+++ 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/ErrorCodesIntegrationTest.java
@@ -141,14 +141,6 @@ public abstract class ErrorCodesIntegrationTest extends 
BaseClusterIntegrationTe
         useMultiStageQueryEngine() ? QueryErrorCode.QUERY_PLANNING : 
QueryErrorCode.QUERY_VALIDATION);
   }
 
-  @Test
-  public void testInvalidAggregationArg()
-      throws Exception {
-    // Cannot use numeric aggregate function for string column
-    testQueryException("SELECT MAX(OriginState) FROM mytable where ArrTime > 
5",
-        QueryErrorCode.QUERY_VALIDATION);
-  }
-
   private void testQueryException(@Language("sql") String query, 
QueryErrorCode errorCode)
       throws Exception {
     QueryAssert queryAssert;
diff --git 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java
 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java
index 10331c51cc8..0018a5ea10b 100644
--- 
a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java
+++ 
b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java
@@ -3510,6 +3510,7 @@ public class OfflineClusterIntegrationTest extends 
BaseClusterIntegrationTestSet
     assertEquals(response1Json.get("rows").get(0).get(2).asText(), "Rule 
Execution Times\n"
         + "Rule: SortRemove -> Time:*\n"
         + "Rule: AggregateProjectMerge -> Time:*\n"
+        + "Rule: AggregateFunctionRewrite -> Time:*\n"
         + "Rule: EvaluateProjectLiteral -> Time:*\n"
         + "Rule: AggregateRemove -> Time:*\n");
 
diff --git 
a/pinot-query-planner/src/main/java/org/apache/pinot/calcite/rel/rules/PinotAggregateFunctionRewriteRule.java
 
b/pinot-query-planner/src/main/java/org/apache/pinot/calcite/rel/rules/PinotAggregateFunctionRewriteRule.java
new file mode 100644
index 00000000000..9b68104daa9
--- /dev/null
+++ 
b/pinot-query-planner/src/main/java/org/apache/pinot/calcite/rel/rules/PinotAggregateFunctionRewriteRule.java
@@ -0,0 +1,114 @@
+/**
+ * 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.calcite.rel.rules;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Aggregate;
+import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.logical.LogicalAggregate;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.sql.SqlFunctionCategory;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.type.ReturnTypes;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.pinot.common.function.sql.PinotSqlAggFunction;
+
+
+/**
+ * Rewrites certain aggregation functions based on operand types to support 
polymorphic aggregations.
+ *
+ * Currently supported rewrites:
+ * - MIN(STRING) -> MINSTRING
+ * - MAX(STRING) -> MAXSTRING
+ */
+public class PinotAggregateFunctionRewriteRule extends RelOptRule {
+  public static final PinotAggregateFunctionRewriteRule INSTANCE =
+      new PinotAggregateFunctionRewriteRule(PinotRuleUtils.PINOT_REL_FACTORY, 
null);
+
+  public static PinotAggregateFunctionRewriteRule 
instanceWithDescription(String description) {
+    return new 
PinotAggregateFunctionRewriteRule(PinotRuleUtils.PINOT_REL_FACTORY, 
description);
+  }
+
+  private PinotAggregateFunctionRewriteRule(RelBuilderFactory factory, String 
description) {
+    super(operand(LogicalAggregate.class, any()), factory, description);
+  }
+
+  @Override
+  public void onMatch(RelOptRuleCall call) {
+    Aggregate aggRel = call.rel(0);
+    RelNode input = aggRel.getInput();
+    List<AggregateCall> originalCalls = aggRel.getAggCallList();
+
+    boolean changed = false;
+    List<AggregateCall> rewrittenCalls = new ArrayList<>(originalCalls.size());
+    for (AggregateCall aggCall : originalCalls) {
+      AggregateCall newCall = maybeRewriteMinMaxOnString(aggCall, input, 
aggRel.getGroupCount());
+      if (newCall != aggCall) {
+        changed = true;
+      }
+      rewrittenCalls.add(newCall);
+    }
+
+    if (!changed) {
+      return;
+    }
+
+    call.transformTo(aggRel.copy(aggRel.getTraitSet(), input, 
aggRel.getGroupSet(), aggRel.getGroupSets(),
+        rewrittenCalls));
+  }
+
+  /**
+   * If the call is MIN or MAX over a STRING input, rewrite it to 
MINSTRING/MAXSTRING.
+   */
+  private static AggregateCall maybeRewriteMinMaxOnString(AggregateCall call, 
RelNode input, int numGroups) {
+    SqlAggFunction aggFunction = call.getAggregation();
+    SqlKind kind = aggFunction.getKind();
+    if (kind != SqlKind.MIN && kind != SqlKind.MAX) {
+      return call;
+    }
+
+    List<Integer> argList = call.getArgList();
+    if (argList.isEmpty()) {
+      return call;
+    }
+
+    int argIndex = argList.get(0);
+    RelDataTypeField field = input.getRowType().getFieldList().get(argIndex);
+    RelDataType fieldType = field.getType();
+    SqlTypeName sqlTypeName = fieldType.getSqlTypeName();
+    if (!SqlTypeName.STRING_TYPES.contains(sqlTypeName)) {
+      return call;
+    }
+
+    String targetName = (kind == SqlKind.MIN) ? "MINSTRING" : "MAXSTRING";
+    SqlAggFunction stringAgg =
+        new PinotSqlAggFunction(targetName, SqlKind.OTHER_FUNCTION, 
ReturnTypes.explicit(call.getType()),
+            aggFunction.getOperandTypeChecker(), 
SqlFunctionCategory.USER_DEFINED_FUNCTION);
+
+    return AggregateCall.create(stringAgg, call.isDistinct(), 
call.isApproximate(), call.ignoreNulls(), argList,
+        call.filterArg, call.distinctKeys, call.getCollation(), numGroups, 
input, call.getType(), call.getName());
+  }
+}
diff --git 
a/pinot-query-planner/src/main/java/org/apache/pinot/calcite/rel/rules/PinotQueryRuleSets.java
 
b/pinot-query-planner/src/main/java/org/apache/pinot/calcite/rel/rules/PinotQueryRuleSets.java
index b9d2604b83e..f64b39404c6 100644
--- 
a/pinot-query-planner/src/main/java/org/apache/pinot/calcite/rel/rules/PinotQueryRuleSets.java
+++ 
b/pinot-query-planner/src/main/java/org/apache/pinot/calcite/rel/rules/PinotQueryRuleSets.java
@@ -147,6 +147,9 @@ public class PinotQueryRuleSets {
       PinotAggregateReduceFunctionsRule
           
.instanceWithDescription(PlannerRuleNames.AGGREGATE_REDUCE_FUNCTIONS),
 
+      PinotAggregateFunctionRewriteRule
+          
.instanceWithDescription(PlannerRuleNames.AGGREGATE_FUNCTION_REWRITE),
+
       // convert CASE-style filtered aggregates into true filtered aggregates
       // put it after AGGREGATE_REDUCE_FUNCTIONS where SUM is converted to SUM0
       AggregateCaseToFilterRule.Config.DEFAULT
diff --git a/pinot-query-planner/src/test/resources/queries/AggregatePlans.json 
b/pinot-query-planner/src/test/resources/queries/AggregatePlans.json
index 1fd3b3cd334..8dbcb446242 100644
--- a/pinot-query-planner/src/test/resources/queries/AggregatePlans.json
+++ b/pinot-query-planner/src/test/resources/queries/AggregatePlans.json
@@ -157,6 +157,54 @@
           "\n                  PinotLogicalTableScan(table=[[default, a]])",
           "\n"
         ]
+      },
+      {
+        "description": "MIN on STRING column rewritten to MINSTRING",
+        "sql": "EXPLAIN PLAN FOR SELECT MIN(a.col1) FROM a",
+        "output": [
+          "Execution Plan",
+          "\nPinotLogicalAggregate(group=[{}], agg#0=[MINSTRING($0)], 
aggType=[FINAL])",
+          "\n  PinotLogicalExchange(distribution=[hash])",
+          "\n    PinotLogicalAggregate(group=[{}], agg#0=[MINSTRING($0)], 
aggType=[LEAF])",
+          "\n      PinotLogicalTableScan(table=[[default, a]])",
+          "\n"
+        ]
+      },
+      {
+        "description": "MIN on INT column not rewritten",
+        "sql": "EXPLAIN PLAN FOR SELECT MIN(a.col3) FROM a",
+        "output": [
+          "Execution Plan",
+          "\nPinotLogicalAggregate(group=[{}], agg#0=[MIN($0)], 
aggType=[FINAL])",
+          "\n  PinotLogicalExchange(distribution=[hash])",
+          "\n    PinotLogicalAggregate(group=[{}], agg#0=[MIN($2)], 
aggType=[LEAF])",
+          "\n      PinotLogicalTableScan(table=[[default, a]])",
+          "\n"
+        ]
+      },
+      {
+        "description": "MAX on STRING column rewritten to MAXSTRING",
+        "sql": "EXPLAIN PLAN FOR SELECT MAX(a.col2) FROM a",
+        "output": [
+          "Execution Plan",
+          "\nPinotLogicalAggregate(group=[{}], agg#0=[MAXSTRING($0)], 
aggType=[FINAL])",
+          "\n  PinotLogicalExchange(distribution=[hash])",
+          "\n    PinotLogicalAggregate(group=[{}], agg#0=[MAXSTRING($1)], 
aggType=[LEAF])",
+          "\n      PinotLogicalTableScan(table=[[default, a]])",
+          "\n"
+        ]
+      },
+      {
+        "description": "MAX on INT column not rewritten",
+        "sql": "EXPLAIN PLAN FOR SELECT MAX(a.col3) FROM a",
+        "output": [
+          "Execution Plan",
+          "\nPinotLogicalAggregate(group=[{}], agg#0=[MAX($0)], 
aggType=[FINAL])",
+          "\n  PinotLogicalExchange(distribution=[hash])",
+          "\n    PinotLogicalAggregate(group=[{}], agg#0=[MAX($2)], 
aggType=[LEAF])",
+          "\n      PinotLogicalTableScan(table=[[default, a]])",
+          "\n"
+        ]
       }
     ]
   }
diff --git a/pinot-query-runtime/src/test/resources/queries/Aggregates.json 
b/pinot-query-runtime/src/test/resources/queries/Aggregates.json
index c12b7a8b94d..23b2f2f8182 100644
--- a/pinot-query-runtime/src/test/resources/queries/Aggregates.json
+++ b/pinot-query-runtime/src/test/resources/queries/Aggregates.json
@@ -44,7 +44,7 @@
       {
         "psql": "4.2.7",
         "description": "aggregations on string column",
-        "sql": "SELECT count(string_col), count(distinct(string_col)), 
count(*) FROM {tbl}"
+        "sql": "SELECT min(string_col), max(string_col), count(string_col), 
count(distinct(string_col)), count(*) FROM {tbl}"
       },
       {
         "psql": "4.2.7",
@@ -153,17 +153,17 @@
       {
         "psql": "4.2.7",
         "description": "aggregations on string column with filters",
-        "sql": "SELECT count(string_col), count(distinct(string_col)), 
count(*) FROM {tbl} WHERE string_col='b'"
+        "sql": "SELECT count(string_col), count(distinct(string_col)), 
count(*), min(string_col), max(string_col) FROM {tbl} WHERE string_col='b'"
       },
       {
         "psql": "4.2.7",
         "description": "aggregations on string column with filters",
-        "sql": "SELECT count(string_col), count(distinct(string_col)), 
count(*) FROM {tbl} WHERE int_col > 100"
+        "sql": "SELECT count(string_col), count(distinct(string_col)), 
count(*), min(string_col), max(string_col) FROM {tbl} WHERE int_col > 100"
       },
       {
         "psql": "4.2.7",
         "description": "aggregations on string column with filters",
-        "sql": "SELECT count(string_col), count(distinct(string_col)), 
count(*) FROM {tbl} WHERE int_col > 100 and double_col = 1.75"
+        "sql": "SELECT count(string_col), count(distinct(string_col)), 
count(*), min(string_col), max(string_col) FROM {tbl} WHERE int_col > 100 and 
double_col = 1.75"
       }
     ]
   },
@@ -226,12 +226,12 @@
       {
         "psql": "4.2.7",
         "description": "group by with aggregations on string column",
-        "sql": "SELECT bool_col, count(string_col), 
count(distinct(string_col)), count(*) FROM {tbl} GROUP BY bool_col"
+        "sql": "SELECT bool_col, count(string_col), 
count(distinct(string_col)), count(*), min(string_col), max(string_col) FROM 
{tbl} GROUP BY bool_col"
       },
       {
         "psql": "4.2.7",
         "description": "group by with aggregations on string column and order 
by",
-        "sql": "SELECT bool_col, count(string_col), 
count(distinct(string_col)), count(*) FROM {tbl} GROUP BY bool_col ORDER BY 
bool_col"
+        "sql": "SELECT bool_col, count(string_col), 
count(distinct(string_col)), count(*), min(string_col), max(string_col) FROM 
{tbl} GROUP BY bool_col ORDER BY bool_col"
       },
       {
         "psql": "4.2.7",
@@ -324,17 +324,17 @@
       {
         "psql": "4.2.7",
         "description": "aggregations on string column with filters",
-        "sql": "SELECT double_col, count(string_col), 
count(distinct(string_col)), count(*) FROM {tbl} WHERE string_col='b' GROUP BY 
double_col"
+        "sql": "SELECT double_col, count(string_col), 
count(distinct(string_col)), count(*), min(string_col), max(string_col) FROM 
{tbl} WHERE string_col='b' GROUP BY double_col"
       },
       {
         "psql": "4.2.7",
         "description": "aggregations on string column with filters",
-        "sql": "SELECT double_col, int_col, count(string_col), 
count(distinct(string_col)), count(*) FROM {tbl} WHERE int_col > 100 GROUP BY 
double_col, int_col"
+        "sql": "SELECT double_col, int_col, count(string_col), 
count(distinct(string_col)), count(*), min(string_col), max(string_col) FROM 
{tbl} WHERE int_col > 100 GROUP BY double_col, int_col"
       },
       {
         "psql": "4.2.7",
         "description": "aggregations on string column with filters",
-        "sql": "SELECT double_col, int_col, bool_col, count(string_col), 
count(distinct(string_col)), count(*) FROM {tbl} WHERE int_col > 100 and 
double_col = 1.75 GROUP BY double_col, int_col, bool_col"
+        "sql": "SELECT double_col, int_col, bool_col, count(string_col), 
count(distinct(string_col)), count(*), min(string_col), max(string_col) FROM 
{tbl} WHERE int_col > 100 and double_col = 1.75 GROUP BY double_col, int_col, 
bool_col"
       }
     ]
   },
@@ -438,7 +438,7 @@
       {
         "psql": "9.21.0",
         "description": "JOIN with simple aggregations on string columns",
-        "sql": "SELECT count(string_col), count(string_col2), count(distinct 
string_col), count(distinct string_col2) from {tbl1} JOIN {tbl2} ON int_col = 
int_col2"
+        "sql": "SELECT count(string_col), count(string_col2), count(distinct 
string_col), count(distinct string_col2), min(string_col), max(string_col) from 
{tbl1} JOIN {tbl2} ON int_col = int_col2"
       },
       {
         "psql": "9.21.0",
@@ -463,12 +463,12 @@
       {
         "psql": "9.21.0",
         "description": "JOIN with  aggregations on string columns and group by 
on double",
-        "sql": "SELECT double_col, count(string_col), count(string_col2), 
count(distinct string_col), count(distinct string_col2) from {tbl1} JOIN {tbl2} 
ON int_col = int_col2 GROUP BY double_col"
+        "sql": "SELECT double_col, count(string_col), count(string_col2), 
count(distinct string_col), count(distinct string_col2), min(string_col2), 
max(string_col2) from {tbl1} JOIN {tbl2} ON int_col = int_col2 GROUP BY 
double_col"
       },
       {
         "psql": "9.21.0",
         "description": "JOIN with  aggregations on string columns and group by 
on double, bool and int",
-        "sql": "SELECT double_col, bool_col, int_col, count(string_col), 
count(string_col2), count(distinct string_col), count(distinct string_col2) 
from {tbl1} JOIN {tbl2} ON int_col = int_col2 GROUP BY double_col, bool_col, 
int_col"
+        "sql": "SELECT double_col, bool_col, int_col, count(string_col), 
count(string_col2), count(distinct string_col), count(distinct string_col2), 
min(string_col2), max(string_col2) from {tbl1} JOIN {tbl2} ON int_col = 
int_col2 GROUP BY double_col, bool_col, int_col"
       },
       {
         "psql": "9.21.0",
@@ -659,13 +659,6 @@
         "description": "aggregate double column followed with order by",
         "sql": "SELECT min(double_col ORDER BY int_col) FROM {tbl}"
       },
-      {
-        "psql": "4.2.7",
-        "ignored": true,
-        "comments": "NumberFormatException: For input string: \"a\"",
-        "description": "aggregate string column",
-        "sql": "SELECT min(string_col) FROM {tbl}"
-      },
       {
         "psql": "4.2.7",
         "description": "aggregate boolean column",
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java
index 820bf3a1052..00102c90a28 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java
@@ -856,6 +856,7 @@ public class CommonConstants {
       public static final String AGGREGATE_JOIN_TRANSPOSE = 
"AggregateJoinTranspose";
       public static final String AGGREGATE_UNION_AGGREGATE = 
"AggregateUnionAggregate";
       public static final String AGGREGATE_REDUCE_FUNCTIONS = 
"AggregateReduceFunctions";
+      public static final String AGGREGATE_FUNCTION_REWRITE = 
"AggregateFunctionRewrite";
       public static final String AGGREGATE_CASE_TO_FILTER = 
"AggregateCaseToFilter";
       public static final String PROJECT_FILTER_TRANSPOSE = 
"ProjectFilterTranspose";
       public static final String PROJECT_MERGE = "ProjectMerge";


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

Reply via email to