@@ -2013,37 +2013,35 @@ private String getAggFieldAlias(UnresolvedExpression aggregateFunction) {
20132013 public RelNode visitChart (Chart node , CalcitePlanContext context ) {
20142014 visitChildren (node , context );
20152015 ArgumentMap argMap = ArgumentMap .of (node .getArguments ());
2016- List <UnresolvedExpression > groupExprList = new ArrayList <>();
2017- UnresolvedExpression span ;
2018- if (node .getColumnSplit () instanceof Span && node .getRowSplit () instanceof Span ) {
2019- throw new UnsupportedOperationException ("It is not supported to have two span splits" );
2020- } else if (node .getRowSplit () instanceof Span ) {
2021- if (node .getColumnSplit () != null ) {
2022- groupExprList .add (node .getColumnSplit ());
2023- }
2024- span = node .getRowSplit ();
2025- } else if (node .getColumnSplit () instanceof Span ) {
2026- if (node .getRowSplit () != null ) {
2027- groupExprList .add (node .getRowSplit ());
2028- }
2029- span = node .getColumnSplit ();
2030- } else {
2031- groupExprList .addAll (
2032- Stream .of (node .getRowSplit (), node .getColumnSplit ()).filter (Objects ::nonNull ).toList ());
2033- span = null ;
2034- }
2016+ List <UnresolvedExpression > groupExprList =
2017+ Stream .of (node .getRowSplit (), node .getColumnSplit ()).filter (Objects ::nonNull ).toList ();
20352018 Boolean useNull = (Boolean ) argMap .getOrDefault ("usenull" , Chart .DEFAULT_USE_NULL ).getValue ();
20362019 Aggregation aggregation =
20372020 new Aggregation (
20382021 node .getAggregationFunctions (),
20392022 List .of (),
20402023 groupExprList ,
2041- span ,
2024+ null ,
20422025 List .of (new Argument (Argument .BUCKET_NULLABLE , AstDSL .booleanLiteral (useNull ))));
2043- visitAggregation (aggregation , context );
2026+ RelNode aggregated = visitAggregation (aggregation , context );
2027+
2028+ // If row or column split does not present or limit equals 0, this is the same as `stats agg
2029+ // [group by col]`
2030+ Integer limit = (Integer ) argMap .getOrDefault ("limit" , Chart .DEFAULT_LIMIT ).getValue ();
2031+ if (node .getRowSplit () == null || node .getColumnSplit () == null || Objects .equals (limit , 0 )) {
2032+ return aggregated ;
2033+ }
2034+
2035+ String aggFunctionName = getAggFunctionName (node .getAggregationFunctions ().getFirst ());
2036+ Optional <BuiltinFunctionName > aggFuncNameOptional = BuiltinFunctionName .of (aggFunctionName );
2037+ if (aggFuncNameOptional .isEmpty ()) {
2038+ throw new IllegalArgumentException (
2039+ StringUtils .format ("Unrecognized aggregation function: %s" , aggFunctionName ));
2040+ }
2041+ BuiltinFunctionName aggFunction = aggFuncNameOptional .get ();
20442042
20452043 // Convert the column split to string if necessary: column split was supposed to be pivoted to
2046- // column names. This guarantees that its type being compatible with useother and usenull
2044+ // column names. This guarantees that its type compatibility with useother and usenull
20472045 RelBuilder relBuilder = context .relBuilder ;
20482046 RexNode colSplit = relBuilder .field (2 );
20492047 String columSplitName = relBuilder .peek ().getRowType ().getFieldNames ().getLast ();
@@ -2055,14 +2053,7 @@ public RelNode visitChart(Chart node, CalcitePlanContext context) {
20552053 columSplitName );
20562054 }
20572055 relBuilder .project (relBuilder .field (0 ), relBuilder .field (1 ), colSplit );
2058- RelNode aggregated = relBuilder .peek ();
2059-
2060- // If row or column split does not present or limit equals 0, this is the same as `stats agg
2061- // [group by col]`
2062- Integer limit = (Integer ) argMap .getOrDefault ("limit" , Chart .DEFAULT_LIMIT ).getValue ();
2063- if (node .getRowSplit () == null || node .getColumnSplit () == null || Objects .equals (limit , 0 )) {
2064- return aggregated ;
2065- }
2056+ aggregated = relBuilder .peek ();
20662057
20672058 Boolean top = (Boolean ) argMap .getOrDefault ("top" , Chart .DEFAULT_TOP ).getValue ();
20682059 Boolean useOther =
@@ -2075,11 +2066,16 @@ public RelNode visitChart(Chart node, CalcitePlanContext context) {
20752066 // 1: column split; 0: agg
20762067 relBuilder .aggregate (
20772068 relBuilder .groupKey (relBuilder .field (1 )),
2078- relBuilder .sum (relBuilder .field (0 )).as ("__grand_total__" )); // results: group key, agg calls
2069+ buildAggCall (context .relBuilder , aggFunction , relBuilder .field (0 ))
2070+ .as ("__grand_total__" )); // results: group key, agg calls
20792071 RexNode grandTotal = relBuilder .field ("__grand_total__" );
2080- if (top ) {
2072+ // Apply sorting: for MIN/EARLIEST, reverse the top/bottom logic
2073+ boolean smallestFirst =
2074+ aggFunction == BuiltinFunctionName .MIN || aggFunction == BuiltinFunctionName .EARLIEST ;
2075+ if (top != smallestFirst ) {
20812076 grandTotal = relBuilder .desc (grandTotal );
20822077 }
2078+
20832079 // Always set it to null last so that it does not interfere with top / bottom calculation
20842080 grandTotal = relBuilder .nullsLast (grandTotal );
20852081 RexNode rowNum =
@@ -2138,7 +2134,7 @@ public RelNode visitChart(Chart node, CalcitePlanContext context) {
21382134 relBuilder .alias (columnSplitExpr , columSplitName ));
21392135 relBuilder .aggregate (
21402136 relBuilder .groupKey (relBuilder .field (1 ), relBuilder .field (2 )),
2141- relBuilder . sum ( relBuilder .field (0 )).as (aggFieldName ));
2137+ buildAggCall ( context . relBuilder , aggFunction , relBuilder .field (0 )).as (aggFieldName ));
21422138 return relBuilder .peek ();
21432139 }
21442140
0 commit comments