func findDeferredColumns(n sql.Node) []*deferredColumn {
	var cols []*deferredColumn
	plan.InspectExpressions(n, func(e sql.Expression) bool {
		if dc, ok := e.(*deferredColumn); ok {
			cols = append(cols, dc)
		}
		return true
	})
	return cols
}
findDeferredColumns returns all the deferredColumn expressions in the node given
package analyzer
import (
	"github.com/dolthub/go-mysql-server/sql"
	"github.com/dolthub/go-mysql-server/sql/expression"
	"github.com/dolthub/go-mysql-server/sql/plan"
)
func reorderProjection(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	span, ctx := ctx.Span("reorder_projection")
	defer span.Finish()
	if n.Resolved() {
		return n, nil
	}
	return plan.TransformUp(n, func(node sql.Node) (sql.Node, error) {
		project, ok := node.(*plan.Project)
		if !ok || hasNaturalJoin(project.Child) {
			return node, nil
		}
		var projectedAliases = make(map[string]sql.Expression)
		for _, col := range project.Projections {
			alias, ok := col.(*expression.Alias)
			if ok {
				projectedAliases[alias.Name()] = col
			}
		}
		neededReorder, child, err := addIntermediateProjections(project, projectedAliases)
		if err != nil {
			return nil, err
		}
		if !neededReorder {
			return node, nil
		}
		child, err = resolveColumns(ctx, a, child, scope)
		if err != nil {
			return nil, err
		}
		child, err = resolveSubqueryExpressions(ctx, a, child, scope)
		if err != nil {
			return nil, err
		}
		if !child.Resolved() {
			return node, nil
		}
		childSchema := child.Schema()
		var projections = make([]sql.Expression, len(project.Projections))
		for i, p := range project.Projections {
			if alias, ok := p.(*expression.Alias); ok {
				var found bool
				for idx, col := range childSchema {
					if col.Name == alias.Name() {
						projections[i] = expression.NewGetField(
							idx, col.Type, col.Name, col.Nullable,
						)
						found = true
						break
					}
				}
				if !found {
					projections[i] = p
				}
			} else {
				projections[i] = p
			}
		}
		return plan.NewProject(projections, child), nil
	})
}
func addIntermediateProjections(project *plan.Project, projectedAliases map[string]sql.Expression) (neededReorder bool, child sql.Node, err error) {
	appliedProjections := make(map[string]bool)
	child, err = plan.TransformUp(project.Child, func(node sql.Node) (sql.Node, error) {
		var missingColumns []string
		switch node := node.(type) {
		case *plan.Sort, *plan.Filter:
			for _, expr := range node.(sql.Expressioner).Expressions() {
				sql.Inspect(expr, func(e sql.Expression) bool {
					if e != nil && e.Resolved() {
						return true
					}
					uc, ok := e.(column)
					if ok && uc.Table() == "" {
						if _, ok := projectedAliases[uc.Name()]; ok && !appliedProjections[uc.Name()] {
							missingColumns = append(missingColumns, uc.Name())
						}
					}
					return true
				})
			}
		default:
			return node, nil
		}
		if len(missingColumns) == 0 {
			return node, nil
		}
		neededReorder = true
		child := node.Children()[0]
		schema := child.Schema()
		var projections = make([]sql.Expression, 0, len(schema)+len(missingColumns))
		for i, col := range schema {
			projections = append(projections, expression.NewGetFieldWithTable(
				i, col.Type, col.Source, col.Name, col.Nullable,
			))
		}
		for _, col := range missingColumns {
			if c, ok := projectedAliases[col]; ok && !appliedProjections[col] {
				projections = append(projections, c)
				appliedProjections[col] = true
			}
		}
		child = plan.NewProject(projections, child)
		switch node := node.(type) {
		case *plan.Filter:
			return plan.NewFilter(node.Expression, child), nil
		case *plan.Sort:
			return plan.NewSort(node.SortFields, child), nil
		default:
			return nil, ErrInvalidNodeType.New("reorderProjection", node)
		}
	})
	var deferredColumns []*deferredColumn
	for _, e := range project.Projections {
		if a, ok := e.(*expression.Alias); ok {
			e = a.Child
		}
		s, ok := e.(*plan.Subquery)
		if !ok {
			continue
		}
		deferredColumns = append(deferredColumns, findDeferredColumns(s.Query)...)
	}
	if len(deferredColumns) > 0 {
		schema := child.Schema()
		var projections = make([]sql.Expression, 0, len(schema)+len(deferredColumns))
		for i, col := range schema {
			projections = append(projections, expression.NewGetFieldWithTable(
				i, col.Type, col.Source, col.Name, col.Nullable,
			))
		}
		for _, dc := range deferredColumns {
			if c, ok := projectedAliases[dc.Name()]; ok && dc.Table() == "" {
				projections = append(projections, c)
				neededReorder = true
			}
		}
		child = plan.NewProject(projections, child)
	}
	return neededReorder, child, err
}