func filterPushdownAboveTablesChildSelector(c plan.TransformContext) bool {
	if !filterPushdownChildSelector(c) {
		return false
	}
	switch c.Parent.(type) {
	case *plan.Filter:
		switch c.Node.(type) {
		case *plan.TableAlias, *plan.ResolvedTable, *plan.IndexedTableAccess, *plan.ValueDerivedTable:
			return false
		}
	}
	return true
}
Like filterPushdownChildSelector, but for pushing filters down via the introduction of additional Filter nodes
(for tables that can't treat the filter as an index lookup or accept it directly). In this case, we want to avoid
introducing additional Filter nodes unnecessarily. This means only introducing new filter nodes when they are being
pushed below a join or other structure.
package analyzer
import (
	"fmt"
	"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 pushdownFilters(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	span, ctx := ctx.Span("pushdown_filters")
	defer span.Finish()
	if !canDoPushdown(n) {
		return n, nil
	}
	return pushdownFiltersAtNode(ctx, a, n, scope)
}
func pushdownFiltersAtNode(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	indexes, err := getIndexesByTable(ctx, a, n, scope)
	if err != nil {
		return nil, err
	}
	tableAliases, err := getTableAliases(n, scope)
	if err != nil {
		return nil, err
	}
	n, err = convertFiltersToIndexedAccess(ctx, a, n, scope, indexes)
	if err != nil {
		return nil, err
	}
	return transformPushdownFilters(ctx, a, n, scope, tableAliases)
}
func pushdownSubqueryAliasFilters(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	span, ctx := ctx.Span("pushdown_subquery_alias_filters")
	defer span.Finish()
	if !canDoPushdown(n) {
		return n, nil
	}
	tableAliases, err := getTableAliases(n, scope)
	if err != nil {
		return nil, err
	}
	return transformPushdownSubqueryAliasFilters(ctx, a, n, scope, tableAliases)
}
func pushdownProjections(ctx *sql.Context, a *Analyzer, n sql.Node, scope *Scope) (sql.Node, error) {
	span, ctx := ctx.Span("pushdown_projections")
	defer span.Finish()
	if !canDoPushdown(n) {
		return n, nil
	}
	if !canProject(n, a) {
		return n, nil
	}
	return transformPushdownProjections(ctx, a, n, scope)
}
func canProject(n sql.Node, a *Analyzer) bool {
	switch n.(type) {
	case *plan.Update, *plan.RowUpdateAccumulator, *plan.DeleteFrom, *plan.Block, *plan.BeginEndBlock, *plan.TriggerBeginEndBlock:
		return false
	}
	containsSubquery := false
	plan.InspectExpressions(n, func(e sql.Expression) bool {
		if _, ok := e.(*plan.Subquery); ok {
			containsSubquery = true
			return false
		}
		return true
	})
	if containsSubquery {
		a.Log("skipping pushdown of projection for query with subquery")
		return false
	}
	containsIndexedJoin := false
	plan.Inspect(n, func(node sql.Node) bool {
		if _, ok := node.(*plan.IndexedJoin); ok {
			containsIndexedJoin = true
			return false
		}
		return true
	})
	if containsIndexedJoin {
		a.Log("skipping pushdown of projection for query with an indexed join")
		return false
	}
	alreadyPushedDown := false
	plan.Inspect(n, func(n sql.Node) bool {
		if n, ok := n.(*plan.DecoratedNode); ok && strings.Contains(n.String(), "Projected table access on") {
			alreadyPushedDown = true
			return false
		}
		return true
	})
	return !alreadyPushedDown
}
func canDoPushdown(n sql.Node) bool {
	if !n.Resolved() {
		return false
	}
	if plan.IsNoRowNode(n) {
		return false
	}
	switch n.(type) {
	case *plan.InsertInto:
		return false
	}
	return true
}
func filterPushdownChildSelector(c plan.TransformContext) bool {
	switch n := c.Parent.(type) {
	case *plan.TableAlias:
		return false
	case *plan.Window:
		return false
	case *plan.IndexedJoin:
		if n.JoinType() == plan.JoinTypeLeft || n.JoinType() == plan.JoinTypeRight {
			return c.ChildNum == 0
		}
		return true
	case *plan.LeftJoin:
		return c.ChildNum == 0
	case *plan.RightJoin:
		return c.ChildNum == 1
	}
	return true
}