func columnAliasRepeated(cols sql.Schema, idx int) bool {
	target := cols[idx]
	if len(target.Source) > 0 {
		return false
	}
	for i, col := range cols {
		if i == idx {
			continue
		}
		if len(col.Source) > 0 {
			continue
		}
		if strings.ToLower(target.Name) == strings.ToLower(col.Name) {
			return true
		}
	}
	return false
}
columnAliasRepeated returns whether the column in the schema given with the index given is an alias that is repeated
elsewhere in the schema, making it ambiguous
package analyzer
import (
	"strings"
	errors "gopkg.in/src-d/go-errors.v1"
	"github.com/dolthub/go-mysql-server/sql"
	"github.com/dolthub/go-mysql-server/sql/expression"
	"github.com/dolthub/go-mysql-server/sql/plan"
)
func pushdownSort(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	span, _ := ctx.Span("pushdownSort")
	defer span.Finish()
	return plan.TransformUp(n, func(n sql.Node) (sql.Node, error) {
		sort, ok := n.(*plan.Sort)
		if !ok {
			return n, nil
		}
		if !sort.Child.Resolved() {
			return n, nil
		}
		childAliases := aliasesDefinedInNode(sort.Child)
		var schemaCols []tableCol
		for _, col := range sort.Child.Schema() {
			schemaCols = append(schemaCols, tableCol{
				table: strings.ToLower(col.Source),
				col:   strings.ToLower(col.Name),
			})
		}
		var colsFromChild []string
		var missingCols []string
		for _, f := range sort.SortFields {
			ns := findExprNameables(f.Column)
			for _, n := range ns {
				name := strings.ToLower(n.Name())
				if stringContains(childAliases, name) {
					colsFromChild = append(colsFromChild, n.Name())
				} else if !tableColsContains(schemaCols, tableColFromNameable(n)) {
					missingCols = append(missingCols, n.Name())
				}
			}
		}
		if len(missingCols) == 0 {
			a.Log("no missing columns, skipping")
			return n, nil
		}
		if len(colsFromChild) == 0 {
			a.Log("pushing down sort, missing columns: %s", strings.Join(missingCols, ", "))
			return pushSortDown(sort)
		}
		a.Log("fixing sort dependencies, missing columns: %s", strings.Join(missingCols, ", "))
		return reorderSort(sort, missingCols)
	})
}
func reorderSort(sort *plan.Sort, missingCols []string) (sql.Node, error) {
	var expressions []sql.Expression
	switch child := sort.Child.(type) {
	case *plan.Project:
		expressions = child.Projections
	case *plan.GroupBy:
		expressions = child.SelectedExprs
	case *plan.Window:
		expressions = child.SelectExprs
	default:
		return nil, errSortPushdown.New(child)
	}
	var newExpressions = append([]sql.Expression{}, expressions...)
	for _, col := range missingCols {
		newExpressions = append(newExpressions, expression.NewUnresolvedColumn(col))
	}
	for i, e := range expressions {
		var name string
		if n, ok := e.(sql.Nameable); ok {
			name = n.Name()
		} else {
			name = e.String()
		}
		var table string
		if t, ok := e.(sql.Tableable); ok {
			table = t.Table()
		}
		expressions[i] = expression.NewGetFieldWithTable(
			i, e.Type(), table, name, e.IsNullable(),
		)
	}
	switch child := sort.Child.(type) {
	case *plan.Project:
		return plan.NewProject(
			expressions,
			plan.NewSort(
				sort.SortFields,
				plan.NewProject(newExpressions, child.Child),
			),
		), nil
	case *plan.GroupBy:
		return plan.NewProject(
			expressions,
			plan.NewSort(
				sort.SortFields,
				plan.NewGroupBy(newExpressions, child.GroupByExprs, child.Child),
			),
		), nil
	case *plan.Window:
		return plan.NewProject(
			expressions,
			plan.NewSort(
				sort.SortFields,
				plan.NewWindow(newExpressions, child.Child),
			),
		), nil
	default:
		return nil, errSortPushdown.New(child)
	}
}
var errSortPushdown = errors.NewKind("unable to push plan.Sort node below %T")
func pushSortDown(sort *plan.Sort) (sql.Node, error) {
	switch child := sort.Child.(type) {
	case *plan.Project:
		return plan.NewProject(
			child.Projections,
			plan.NewSort(sort.SortFields, child.Child),
		), nil
	case *plan.GroupBy:
		return plan.NewGroupBy(
			child.SelectedExprs,
			child.GroupByExprs,
			plan.NewSort(sort.SortFields, child.Child),
		), nil
	case *plan.Window:
		return plan.NewWindow(
			child.SelectExprs,
			plan.NewSort(sort.SortFields, child.Child),
		), nil
	case *plan.ResolvedTable:
		return sort, nil
	default:
		children := child.Children()
		if len(children) == 1 {
			newChild, err := pushSortDown(plan.NewSort(sort.SortFields, children[0]))
			if err != nil {
				return nil, err
			}
			return child.WithChildren(newChild)
		}
		return nil, errSortPushdown.New(child)
	}
}
func resolveOrderByLiterals(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	return plan.TransformUp(n, func(n sql.Node) (sql.Node, error) {
		sort, ok := n.(*plan.Sort)
		if !ok {
			return n, nil
		}
		if !sort.Child.Resolved() {
			return n, nil
		}
		schema := sort.Child.Schema()
		var (
			fields = make([]sql.SortField, len(sort.SortFields))
		)
		for i, f := range sort.SortFields {
			if lit, ok := f.Column.(*expression.Literal); ok && sql.IsNumber(f.Column.Type()) {
				v, err := lit.Eval(nil, nil)
				if err != nil {
					return nil, err
				}
				v, err = sql.Int64.Convert(v)
				if err != nil {
					return nil, err
				}
				idx := int(v.(int64)) - 1
				if idx >= len(schema) || idx < 0 {
					return nil, ErrOrderByColumnIndex.New(idx + 1)
				}
				if columnAliasRepeated(schema, idx) {
					return nil, sql.ErrAmbiguousColumnInOrderBy.New(schema[idx].Name)
				}
				fields[i] = sql.SortField{
					Column:       expression.NewUnresolvedQualifiedColumn(schema[idx].Source, schema[idx].Name),
					Order:        f.Order,
					NullOrdering: f.NullOrdering,
				}
				a.Log("replaced order by column %d with %v", idx+1, schema[idx])
			} else {
				if agg, ok := f.Column.(sql.Aggregation); ok {
					name := agg.String()
					if nameable, ok := f.Column.(sql.Nameable); ok {
						name = nameable.Name()
					}
					fields[i] = sql.SortField{
						Column:       expression.NewUnresolvedColumn(name),
						Order:        f.Order,
						NullOrdering: f.NullOrdering,
					}
				} else {
					fields[i] = f
				}
			}
		}
		return plan.NewSort(fields, sort.Child), nil
	})
}