protected LogicalPlan applySort(Sort sort) {
            if (!(sort.child() instanceof Aggregate) || !sort.child().resolved()) {
                return null;
            }
            if (true) {
                // TODO produce bug
                return null;
            }
            List<SortOrder> sortOrder = sort.order;
            Aggregate aggregate = (Aggregate) sort.child();
            List<SortOrder> unresolvedSortOrders = filterToList(sortOrder, s -> !s.resolved() || containsAggregate(s));
            // List<Alias>
            List<NamedExpression> aliasedOrdering = mapToList(unresolvedSortOrders, o -> new Alias(o.child, "aggOrder"));
            Aggregate aggregatedOrdering = new Aggregate(
                    aggregate.groupingExpressions,
                    aliasedOrdering/*aggregateExpressions*/,
                    aggregate.child());
            Aggregate resolvedAggregate = (Aggregate) execute(aggregatedOrdering);
            List<NamedExpression> resolvedAliasedOrdering = resolvedAggregate.aggregateExpressions;

            assert resolvedAliasedOrdering.size() == unresolvedSortOrders.size();

            // If we pass the analysis check, then the ordering expressions should only reference to
            // aggregate expressions or grouping expressions, and it's safe to push them down to
            // Aggregate.
            if (!resolvedAggregate.resolved()) {
                return null;
            }

            List<NamedExpression> originalAggExprs = mapToList(
                    aggregate.aggregateExpressions,
                    e -> (NamedExpression) trimNonTopLevelAliases(e));

            // If the ordering expression is same with original aggregate expression, we don't need
            // to push down this ordering expression and can reference the original aggregate
            // expression instead.

            List<NamedExpression> needsPushDown = new ArrayList<>();
            Map<SortOrder, SortOrder> sortOrdersMap = new HashMap<>();

            for (int i = 0; i < resolvedAliasedOrdering.size(); i++) {
                Alias evaluated = (Alias) resolvedAliasedOrdering.get(i);
                SortOrder order = unresolvedSortOrders.get(i);
                int index = indexWhere(originalAggExprs, e -> {
                    if (e instanceof Alias) {
                        return ((Alias) e).child.semanticEquals(evaluated.child);
                    } else {
                        return e.semanticEquals(evaluated.child);
                    }
                });
                if (index < 0) {
                    needsPushDown.add(evaluated);
                    sortOrdersMap.put(order, new SortOrder(evaluated.toAttribute(), order.direction));
                } else {
                    //evaluatedOrderings.add(new SortOrder(originalAggExprs.get(index).toAttribute(), order.direction));
                    sortOrdersMap.put(order, new SortOrder(originalAggExprs.get(index).toAttribute(), order.direction));
                }
            }

            List<SortOrder> finalSortOrders = mapToList(sortOrder, o -> {
                return sortOrdersMap.getOrDefault(o, o);
            });

            // Since we don't rely on sort.resolved as the stop condition for this rule,
            // we need to check this and prevent applying this rule multiple times
            if (sortOrder.equals(finalSortOrders)) {
                return sort;
            } else {
                Sort newSort = new Sort(finalSortOrders,
                        new Aggregate(aggregate.groupingExpressions, concatToList(originalAggExprs, needsPushDown), aggregate.child));
                return new Project(up(aggregate.output()), newSort);
            }
        }
This rule finds aggregate expressions that are not in an aggregate operator.  For example,
those in a HAVING clause or ORDER BY clause.  These expressions are pushed down to the
underlying aggregate operator and then projected away after the original operator.
indexr-query-opt/src/main/java/io/indexr/query/Analyzer.java