func createIndexKeyExpr(ctx *sql.Context, idx sql.Index, joinExprs []*joinColExpr, tableAliases TableAliases) []sql.Expression {
	keyExprs := make([]sql.Expression, len(idx.Expressions()))
IndexExpressions:
	for i, idxExpr := range idx.Expressions() {
		for j := range joinExprs {
			if idxExpr == normalizeExpression(ctx, tableAliases, joinExprs[j].colExpr).String() {
				keyExprs[i] = joinExprs[j].comparand
				continue IndexExpressions
			}
		}
		return nil
	}
	return keyExprs
}
createIndexKeyExpr returns a slice of expressions to be used when creating an index lookup key for the table given.
package analyzer
import (
	"strings"
	"github.com/dolthub/go-mysql-server/sql"
	"github.com/dolthub/go-mysql-server/sql/expression"
	"github.com/dolthub/go-mysql-server/sql/plan"
)
func applyIndexesFromOuterScope(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	if scope == nil {
		return n, nil
	}
	tableAliases, err := getTableAliases(n, scope)
	if err != nil {
		return nil, err
	}
	indexLookups, err := getOuterScopeIndexes(ctx, a, n, scope, tableAliases)
	if err != nil {
		return nil, err
	}
	if len(indexLookups) == 0 {
		return n, nil
	}
	childSelector := func(c plan.TransformContext) bool {
		switch c.Parent.(type) {
		case *plan.IndexedTableAccess:
			return false
		}
		return true
	}
	for _, idxLookup := range indexLookups {
		n, err = plan.TransformUpCtx(n, childSelector, func(c plan.TransformContext) (sql.Node, error) {
			switch n := c.Node.(type) {
			case *plan.IndexedTableAccess:
				return n, nil
			case *plan.TableAlias:
				if strings.ToLower(n.Name()) == idxLookup.table {
					return pushdownIndexToTable(a, n, idxLookup.index, idxLookup.keyExpr)
				}
				return n, nil
			case *plan.ResolvedTable:
				if strings.ToLower(n.Name()) == idxLookup.table {
					return pushdownIndexToTable(a, n, idxLookup.index, idxLookup.keyExpr)
				}
				return n, nil
			default:
				return n, nil
			}
		})
		if err != nil {
			return nil, err
		}
	}
	return n, nil
}
func pushdownIndexToTable(a *Analyzer, tableNode NameableNode, index sql.Index, keyExpr []sql.Expression) (sql.Node, error) {
	return plan.TransformUp(tableNode, func(n sql.Node) (sql.Node, error) {
		switch n := n.(type) {
		case *plan.ResolvedTable:
			table := getTable(tableNode)
			if table == nil {
				return n, nil
			}
			if _, ok := table.(sql.IndexAddressableTable); ok {
				a.Log("table %q transformed with pushdown of index", tableNode.Name())
				return plan.NewIndexedTableAccess(n, index, keyExpr), nil
			}
		}
		return n, nil
	})
}
type subqueryIndexLookup struct {
	table   string
	keyExpr []sql.Expression
	index   sql.Index
}
func getOuterScopeIndexes(
	ctx *sql.Context,
	a *Analyzer,
	node sql.Node,
	scope *Scope,
	tableAliases TableAliases,
) ([]subqueryIndexLookup, error) {
	indexSpan, _ := ctx.Span("getOuterScopeIndexes")
	defer indexSpan.Finish()
	var indexes map[string]sql.Index
	var exprsByTable joinExpressionsByTable
	var err error
	plan.Inspect(node, func(node sql.Node) bool {
		switch node := node.(type) {
		case *plan.Filter:
			var indexAnalyzer *indexAnalyzer
			indexAnalyzer, err = getIndexesForNode(ctx, a, node)
			if err != nil {
				return false
			}
			defer indexAnalyzer.releaseUsedIndexes()
			indexes, exprsByTable, err = getSubqueryIndexes(ctx, a, node.Expression, scope, indexAnalyzer, tableAliases)
			if err != nil {
				return false
			}
		}
		return true
	})
	if len(indexes) == 0 {
		return nil, nil
	}
	var lookups []subqueryIndexLookup
	for table, idx := range indexes {
		if exprsByTable[table] != nil {
			keyExpr := createIndexKeyExpr(ctx, idx, exprsByTable[table], tableAliases)
			if keyExpr == nil {
				continue
			}
			lookups = append(lookups, subqueryIndexLookup{
				table:   table,
				keyExpr: keyExpr,
				index:   idx,
			})
		}
	}
	return lookups, nil
}