@Override
        public LogicalPlan apply(LogicalPlan plan) {
            return plan.resolveOperators(p -> {
                if (p instanceof Sort && ((Sort) p).child() instanceof Project) {
                    Sort sort = (Sort) p;
                    Project project = (Project) sort.child();
                    if (!sort.resolved() && sort.child().resolved()) {
                        Pair<List<SortOrder>, Set<Attribute>> pair = resolveAndFindMissing(
                                sort.order,
                                project,
                                project.child());
                        List<SortOrder> newOrdering = pair.first;
                        Set<Attribute> missing = pair.second;

                        // If this rule was not a no-op, return the transformed plan, otherwise return the original.
                        if (!missing.isEmpty()) {
                            List<NamedExpression> newProjectList = concatToList(project.projectList, missing);
                            // Add missing attributes and then project them away after the sort.
                            return new Project(project.projectList,
                                    new Sort(newOrdering, new Project(newProjectList, project.child())));
                        }
                    }
                }
                return p;
            });
        }
In many dialects of SQL it is valid to sort by attributes that are not present in the SELECT
clause.  This rule detects such queries and adds the required attributes to the original
projection, so that they will be available during sorting. Another projection is added to
remove these attributes after sorting.
indexr-query-opt/src/main/java/io/indexr/query/Analyzer.java