5656import com .facebook .presto .sql .tree .Join ;
5757import com .facebook .presto .sql .tree .Lateral ;
5858import com .facebook .presto .sql .tree .LogicalBinaryExpression ;
59+ import com .facebook .presto .sql .tree .LongLiteral ;
5960import com .facebook .presto .sql .tree .Node ;
6061import com .facebook .presto .sql .tree .OrderBy ;
6162import com .facebook .presto .sql .tree .QualifiedName ;
107108import static com .facebook .presto .sql .analyzer .SemanticErrorCode .NOT_SUPPORTED ;
108109import static com .facebook .presto .sql .relational .Expressions .call ;
109110import static com .facebook .presto .util .AnalyzerUtil .createParsingOptions ;
111+ import static java .lang .Math .toIntExact ;
110112import static java .lang .String .format ;
111113import static java .util .Objects .requireNonNull ;
112114
@@ -463,18 +465,35 @@ protected Node visitQuerySpecification(QuerySpecification node, Void context)
463465 removablePrefix = Optional .of (new Identifier (baseTable .getName ().toString ()));
464466 }
465467 if (node .getGroupBy ().isPresent ()) {
468+ List <SelectItem > selectItems = node .getSelect ().getSelectItems ();
466469 ImmutableSet .Builder <Expression > expressionsInGroupByBuilder = ImmutableSet .builder ();
467470 for (GroupingElement element : node .getGroupBy ().get ().getGroupingElements ()) {
468471 element = removeGroupingElementPrefix (element , removablePrefix );
469472 Optional <Set <Expression >> groupByOfMaterializedView = materializedViewInfo .getGroupBy ();
470473 if (groupByOfMaterializedView .isPresent ()) {
471474 for (Expression expression : element .getExpressions ()) {
472- if (!groupByOfMaterializedView .get ().contains (expression ) || !materializedViewInfo .getBaseToViewColumnMap ().containsKey (expression )) {
475+ // Resolve ordinal references (e.g. GROUP BY 1) to the corresponding SELECT expression
476+ Expression resolved = expression ;
477+ if (expression instanceof LongLiteral ) {
478+ int ordinal = toIntExact (((LongLiteral ) expression ).getValue ());
479+ SelectItem selectItem = selectItems .get (ordinal - 1 );
480+ if (selectItem instanceof SingleColumn ) {
481+ resolved = removeExpressionPrefix (((SingleColumn ) selectItem ).getExpression (), removablePrefix );
482+ }
483+ else {
484+ throw new IllegalStateException ("GROUP BY ordinal references non-single-column select item" );
485+ }
486+ }
487+ if (!groupByOfMaterializedView .get ().contains (resolved ) || !materializedViewInfo .getBaseToViewColumnMap ().containsKey (resolved )) {
473488 throw new IllegalStateException (format ("Grouping element %s is not present in materialized view groupBy field" , element ));
474489 }
490+ // Store the resolved expression so visitSingleColumn can match against it
491+ expressionsInGroupByBuilder .add (resolved );
475492 }
476493 }
477- expressionsInGroupByBuilder .addAll (element .getExpressions ());
494+ else {
495+ expressionsInGroupByBuilder .addAll (element .getExpressions ());
496+ }
478497 }
479498 expressionsInGroupBy = Optional .of (expressionsInGroupByBuilder .build ());
480499 }
@@ -683,8 +702,11 @@ protected Node visitOrderBy(OrderBy node, Void context)
683702 ImmutableList .Builder <SortItem > rewrittenOrderBy = ImmutableList .builder ();
684703 for (SortItem sortItem : node .getSortItems ()) {
685704 sortItem = removeSortItemPrefix (sortItem , removablePrefix );
686- if (!materializedViewInfo .getBaseToViewColumnMap ().containsKey (sortItem .getSortKey ())) {
687- throw new IllegalStateException (format ("Sort key %s is not present in materialized view select fields" , sortItem .getSortKey ()));
705+ // Ordinal references (e.g. ORDER BY 3) refer to SELECT items which are already validated
706+ Expression sortKey = sortItem .getSortKey ();
707+ if (!(sortKey instanceof LongLiteral )
708+ && !materializedViewInfo .getBaseToViewColumnMap ().containsKey (sortKey )) {
709+ throw new IllegalStateException (format ("Sort key %s is not present in materialized view select fields" , sortKey ));
688710 }
689711 rewrittenOrderBy .add ((SortItem ) process (sortItem , context ));
690712 }
@@ -694,15 +716,26 @@ protected Node visitOrderBy(OrderBy node, Void context)
694716 @ Override
695717 protected Node visitSortItem (SortItem node , Void context )
696718 {
697- return new SortItem ((Expression ) process (node .getSortKey (), context ), node .getOrdering (), node .getNullOrdering ());
719+ Expression sortKey = node .getSortKey ();
720+ // Ordinal references (e.g. ORDER BY 1) refer to SELECT positions which are already rewritten; pass through unchanged
721+ if (sortKey instanceof LongLiteral ) {
722+ return node ;
723+ }
724+ return new SortItem ((Expression ) process (sortKey , context ), node .getOrdering (), node .getNullOrdering ());
698725 }
699726
700727 @ Override
701728 protected Node visitSimpleGroupBy (SimpleGroupBy node , Void context )
702729 {
703730 ImmutableList .Builder <Expression > rewrittenSimpleGroupBy = ImmutableList .builder ();
704731 for (Expression column : node .getExpressions ()) {
705- rewrittenSimpleGroupBy .add ((Expression ) process (removeExpressionPrefix (column , removablePrefix ), context ));
732+ // Ordinal references (e.g. GROUP BY 1) refer to SELECT positions which are already rewritten; pass through unchanged
733+ if (column instanceof LongLiteral ) {
734+ rewrittenSimpleGroupBy .add (column );
735+ }
736+ else {
737+ rewrittenSimpleGroupBy .add ((Expression ) process (removeExpressionPrefix (column , removablePrefix ), context ));
738+ }
706739 }
707740 return new SimpleGroupBy (rewrittenSimpleGroupBy .build ());
708741 }
0 commit comments