func handleBinaryOperationExpr(p *TableAliasStmtInfo, expr *ast.BinaryOperationExpr) (bool, []int, ast.ExprNode, error) {
	_, ok := opcode.Ops[expr.Op]
	if !ok {
		return false, nil, nil, fmt.Errorf("unknown BinaryOperationExpr.Op: %v", expr.Op)
	}
	switch expr.Op {
	case opcode.LogicAnd, opcode.LogicOr:
		return handleBinaryOperationExprLogic(p, expr)
	case opcode.EQ, opcode.NE, opcode.GT, opcode.GE, opcode.LT, opcode.LE:
		return handleBinaryOperationExprMathCompare(p, expr)
	default:
		return handleBinaryOperationExprOther(p, expr)
	}
}
return value: hasRoutingResult, RouteResult, Decorator, error
the Decorator must not be nil. If no modification to the input expr, just return it.
package plan
import (
	"fmt"
	"github.com/nooncall/shazam/mysql"
	"github.com/nooncall/shazam/parser/ast"
	"github.com/nooncall/shazam/parser/opcode"
	driver "github.com/nooncall/shazam/parser/tidb-types/parser_driver"
	"github.com/nooncall/shazam/proxy/router"
	"github.com/nooncall/shazam/util"
)
type SelectPlan struct {
	basePlan
	*TableAliasStmtInfo
	stmt *ast.SelectStmt
	distinct           bool  
	groupByColumnStart int
	groupByColumnCount int
	orderByColumnStart int     
	orderByDirections  []bool  
	originColumnCount  int     
	columnCount        int     
	aggregateFuncs map[int]AggregateFuncMerger  
	offset int64  
	count  int64  
	sqls map[string]map[string][]string
}
func NewSelectPlan(db string, sql string, r *router.Router) *SelectPlan {
	return &SelectPlan{
		TableAliasStmtInfo: NewTableAliasStmtInfo(db, sql, r),
		groupByColumnStart: 0,
		groupByColumnCount: 0,
		orderByColumnStart: 0,
		aggregateFuncs:     make(map[int]AggregateFuncMerger),
		offset:             -1,
		count:              -1,
	}
}
func (s *SelectPlan) ExecuteIn(reqCtx *util.RequestContext, sess Executor) (*mysql.Result, error) {
	sqls := s.GetSQLs()
	if sqls == nil {
		return nil, fmt.Errorf("SQL has not generated")
	}
	if len(sqls) == 0 {
		r := newEmptyResultset(s, s.GetStmt())
		ret := &mysql.Result{
			Resultset: r,
		}
		return ret, nil
	}
	rs, err := sess.ExecuteSQLs(reqCtx, sqls)
	if err != nil {
		return nil, fmt.Errorf("execute in SelectPlan error: %v", err)
	}
	r, err := MergeSelectResult(s, s.stmt, rs)
	if err != nil {
		return nil, fmt.Errorf("merge select result error: %v", err)
	}
	return r, nil
}
func (s *SelectPlan) GetStmt() *ast.SelectStmt {
	return s.stmt
}
func (s *SelectPlan) setAggregateFuncMerger(idx int, merger AggregateFuncMerger) error {
	if _, ok := s.aggregateFuncs[idx]; ok {
		return fmt.Errorf("column %d already set", idx)
	}
	s.aggregateFuncs[idx] = merger
	return nil
}
func (s *SelectPlan) HasLimit() bool {
	return s.count != -1
}
func (s *SelectPlan) GetLimitValue() (int64, int64) {
	return s.offset, s.count
}
func (s *SelectPlan) HasGroupBy() bool {
	return s.groupByColumnCount != 0
}
func (s *SelectPlan) GetOriginColumnCount() int {
	return s.originColumnCount
}
func (s *SelectPlan) GetColumnCount() int {
	return s.columnCount
}
func (s *SelectPlan) GetGroupByColumnInfo() (int, int) {
	return s.groupByColumnStart, s.groupByColumnCount
}
func (s *SelectPlan) HasOrderBy() bool {
	return len(s.orderByDirections) != 0
}
func (s *SelectPlan) GetOrderByColumnInfo() (int, []bool) {
	return s.orderByColumnStart, s.orderByDirections
}
func (s *SelectPlan) GetSQLs() map[string]map[string][]string {
	return s.sqls
}
func HandleSelectStmt(p *SelectPlan, stmt *ast.SelectStmt) error {
	p.stmt = stmt  
	p.distinct = stmt.Distinct
	if err := handleTableRefs(p, stmt); err != nil {
		return fmt.Errorf("handle From error: %v", err)
	}
	if stmt.Fields != nil {
		if err := handleFieldList(p, stmt); err != nil {
			return fmt.Errorf("handle Fields error: %v", err)
		}
		p.originColumnCount = len(stmt.Fields.Fields)
	}
	if err := handleGroupBy(p, stmt); err != nil {
		return fmt.Errorf("handle GroupBy error: %v", err)
	}
	if err := handleOrderBy(p, stmt); err != nil {
		return fmt.Errorf("handle OrderBy error: %v", err)
	}
	if stmt.Fields != nil {
		p.columnCount = len(stmt.Fields.Fields)
	}
	if err := handleWhere(p, stmt); err != nil {
		return fmt.Errorf("handle Where error: %v", err)
	}
	if err := handleHaving(p, stmt); err != nil {
		return fmt.Errorf("handle Having error: %v", err)
	}
	if err := handleLimit(p, stmt); err != nil {
		return fmt.Errorf("handle Limit error: %v", err)
	}
	if err := postHandleGlobalTableRouteResultInQuery(p.StmtInfo); err != nil {
		return fmt.Errorf("post handle global table error: %v", err)
	}
	if err := postHandleHintDatabaseFunction(p); err != nil {
		return fmt.Errorf("handle Hint error: %v", err)
	}
	sqls, err := generateShardingSQLs(p.stmt, p.result, p.router)
	if err != nil {
		return fmt.Errorf("generate select SQL error: %v", err)
	}
	p.sqls = sqls
	return nil
}
func handleGroupBy(p *SelectPlan, stmt *ast.SelectStmt) error {
	if stmt.GroupBy == nil {
		return nil
	}
	groupByFields, err := createSelectFieldsFromByItems(p, stmt.GroupBy.Items)
	if err != nil {
		return fmt.Errorf("get group by fields error: %v", err)
	}
	p.groupByColumnStart = len(stmt.Fields.Fields)
	p.groupByColumnCount = len(groupByFields)
	stmt.Fields.Fields = append(stmt.Fields.Fields, groupByFields...)
	return nil
}
func handleOrderBy(p *SelectPlan, stmt *ast.SelectStmt) error {
	if stmt.OrderBy == nil {
		return nil
	}
	orderByFields, err := createSelectFieldsFromByItems(p, stmt.OrderBy.Items)
	if err != nil {
		return fmt.Errorf("get order by fields error: %v", err)
	}
	p.orderByColumnStart = len(stmt.Fields.Fields)
	for _, f := range stmt.OrderBy.Items {
		p.orderByDirections = append(p.orderByDirections, f.Desc)
	}
	stmt.Fields.Fields = append(stmt.Fields.Fields, orderByFields...)
	return nil
}
func createSelectFieldsFromByItems(p *SelectPlan, items []*ast.ByItem) ([]*ast.SelectField, error) {
	var ret []*ast.SelectField
	for _, item := range items {
		selectField, err := createSelectFieldFromByItem(p, item)
		if err != nil {
			return nil, err
		}
		ret = append(ret, selectField)
	}
	return ret, nil
}
func createSelectFieldFromByItem(p *SelectPlan, item *ast.ByItem) (*ast.SelectField, error) {
	if funcExpr, ok := item.Expr.(*ast.FuncCallExpr); ok {
		if funcExpr.FnName.L == "database" {
			ret := &ast.SelectField{
				Expr: item.Expr,
			}
			return ret, nil
		}
		return nil, fmt.Errorf("ByItem.Expr is a FuncCallExpr but not DATABASE()")
	}
	columnExpr, ok := item.Expr.(*ast.ColumnNameExpr)
	if !ok {
		return nil, fmt.Errorf("ByItem.Expr is not a ColumnNameExpr")
	}
	rule, need, isAlias, err := NeedCreateColumnNameExprDecoratorInField(p.TableAliasStmtInfo, columnExpr)
	if err != nil {
		return nil, err
	}
	if need {
		decorator := CreateColumnNameExprDecorator(columnExpr, rule, isAlias, p.GetRouteResult())
		item.Expr = decorator
	}
	ret := &ast.SelectField{
		Expr: item.Expr,
	}
	return ret, nil
}
func handleTableRefs(p *SelectPlan, stmt *ast.SelectStmt) error {
	tableRefs := stmt.From
	if tableRefs == nil {
		return nil
	}
	join := tableRefs.TableRefs
	if join == nil {
		return nil
	}
	return handleJoin(p.TableAliasStmtInfo, join)
}
func handleJoin(p *TableAliasStmtInfo, join *ast.Join) error {
	if err := precheckJoinClause(join); err != nil {
		return fmt.Errorf("precheck Join error: %v", err)
	}
	if join.Left != nil {
		switch left := join.Left.(type) {
		case *ast.TableSource:
			if err := rewriteTableSource(p, left); err != nil {
				return fmt.Errorf("rewrite left TableSource error: %v", err)
			}
		case *ast.Join:
			if err := handleJoin(p, left); err != nil {
				return fmt.Errorf("handle nested left Join error: %v", err)
			}
		default:
			return fmt.Errorf("invalid left Join type: %T", join.Left)
		}
	}
	if join.Right != nil {
		right, ok := join.Right.(*ast.TableSource)
		if !ok {
			return fmt.Errorf("right is not TableSource, type: %T", join.Right)
		}
		if err := rewriteTableSource(p, right); err != nil {
			return fmt.Errorf("rewrite right TableSource error: %v", err)
		}
	}
	if join.On != nil {
		err := rewriteOnCondition(p, join.On)
		if err != nil {
			return fmt.Errorf("rewrite on condition error: %v", err)
		}
	}
	return nil
}
func handleWhere(p *SelectPlan, stmt *ast.SelectStmt) (err error) {
	if stmt.Where == nil {
		return nil
	}
	has, result, decorator, err := handleComparisonExpr(p.TableAliasStmtInfo, stmt.Where)
	if err != nil {
		return fmt.Errorf("rewrite Where error: %v", err)
	}
	if has {
		p.GetRouteResult().Inter(result)
	}
	stmt.Where = decorator
	return nil
}
func precheckJoinClause(join *ast.Join) error {
	for _, c := range join.Using {
		if c.Schema.String() != "" {
			return fmt.Errorf("JOIN does not support USING column with schema")
		}
		if c.Table.String() != "" {
			return fmt.Errorf("JOIN does not support USING column with table")
		}
	}
	return nil
}
func rewriteTableSource(p *TableAliasStmtInfo, tableSource *ast.TableSource) error {
	switch ss := tableSource.Source.(type) {
	case *ast.TableName:
		return rewriteTableNameInTableSource(p, tableSource)
	case *ast.SelectStmt:
		if err := handleSubquerySelectStmt(p, ss); err != nil {
			return fmt.Errorf("handleSubquerySelectStmt error: %v", err)
		}
		alias := tableSource.AsName.String()
		if alias != "" {
			if _, err := p.RecordSubqueryTableAlias(alias); err != nil {
				return fmt.Errorf("record subquery alias error: %v", err)
			}
		}
		return nil
	default:
		return fmt.Errorf("field Source cannot handle, type: %T", tableSource.Source)
	}
}
func rewriteTableNameInTableSource(p *TableAliasStmtInfo, tableSource *ast.TableSource) error {
	tableName, ok := tableSource.Source.(*ast.TableName)
	if !ok {
		return fmt.Errorf("field Source is not type of TableName, type: %T", tableSource.Source)
	}
	alias := tableSource.AsName.String()
	rule, need, err := NeedCreateTableNameDecorator(p, tableName, alias)
	if err != nil {
		return fmt.Errorf("check NeedCreateTableNameDecorator error: %v", err)
	}
	if !need {
		return nil
	}
	d, err := CreateTableNameDecorator(tableName, rule, p.GetRouteResult())
	if err != nil {
		return fmt.Errorf("create TableNameDecorator error: %v", err)
	}
	tableSource.Source = d
	return nil
}
func rewriteOnCondition(p *TableAliasStmtInfo, on *ast.OnCondition) error {
	has, result, decorator, err := handleComparisonExpr(p, on.Expr)
	if err != nil {
		return fmt.Errorf("rewrite Expr in OnCondition error: %v", err)
	}
	if has {
		p.GetRouteResult().Inter(result)
	}
	on.Expr = decorator
	return nil
}
func postHandleHintDatabaseFunction(p *SelectPlan) error {
	if p.hintPhyDB == "" {
		return nil
	}
	rule, ok := p.router.GetShardRule(p.result.db, p.result.table)
	if !ok {
		return fmt.Errorf("sharding rule of route result not found, result: %v", p.result)
	}
	mr, ok := rule.(router.MycatRule)
	if !ok {
		return fmt.Errorf("sharding rule is not mycat mode, result: %v", p.result)
	}
	if !router.IsMycatShardingRule(mr.GetType()) {  
		return fmt.Errorf("only mycat rule supports database function hint")
	}
	idx, ok := mr.GetTableIndexByDatabaseName(p.hintPhyDB)
	if !ok {
		return fmt.Errorf("hint db not found: %s", p.hintPhyDB)
	}
	p.result.indexes = []int{idx}
	return nil
}
type ColumnNameRewriteVisitor struct {
	info *TableAliasStmtInfo
}
func NewColumnNameRewriteVisitor(p *TableAliasStmtInfo) *ColumnNameRewriteVisitor {
	return &ColumnNameRewriteVisitor{
		info: p,
	}
}
func (s *ColumnNameRewriteVisitor) Enter(n ast.Node) (node ast.Node, skipChildren bool) {
	return n, false
}
func (s *ColumnNameRewriteVisitor) Leave(n ast.Node) (node ast.Node, ok bool) {
	field, ok := n.(*ast.ColumnNameExpr)
	if !ok {
		return n, true
	}
	rule, need, isAlias, err := NeedCreateColumnNameExprDecoratorInField(s.info, field)
	if err != nil {
		panic(fmt.Errorf("check NeedCreateColumnNameExprDecoratorInField in ColumnNameExpr error: %v", err))
	}
	if need {
		decorator := CreateColumnNameExprDecorator(field, rule, isAlias, s.info.GetRouteResult())
		return decorator, true
	}
	return n, true
}
func handleFieldList(p *SelectPlan, stmt *ast.SelectStmt) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("handleFieldList panic: %v", e)
		}
	}()
	fields := stmt.Fields
	if fields == nil {
		return nil
	}
	columnNameRewriter := NewColumnNameRewriteVisitor(p.TableAliasStmtInfo)
	fields.Accept(columnNameRewriter)
	for i, f := range fields.Fields {
		switch field := f.Expr.(type) {
		case *ast.AggregateFuncExpr:
			merger, err := CreateAggregateFunctionMerger(field.F, i)
			if err != nil {
				return fmt.Errorf("create aggregate function merger error, column index: %d, err: %v", i, err)
			}
			if err := p.setAggregateFuncMerger(i, merger); err != nil {
				return fmt.Errorf("set aggregate function merger error, column index: %d, err: %v", i, err)
			}
		default:
		}
	}
	return nil
}
func handleHaving(p *SelectPlan, stmt *ast.SelectStmt) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("handleHaving panic: %v", e)
		}
	}()
	having := stmt.Having
	if having == nil {
		return nil
	}
	columnNameRewriter := NewColumnNameRewriteVisitor(p.TableAliasStmtInfo)
	having.Accept(columnNameRewriter)
	return nil
}
func handleComparisonExpr(p *TableAliasStmtInfo, comp ast.ExprNode) (bool, []int, ast.ExprNode, error) {
	switch expr := comp.(type) {
	case *ast.BinaryOperationExpr:
		return handleBinaryOperationExpr(p, expr)
	case *ast.PatternInExpr:
		return handlePatternInExpr(p, expr)
	case *ast.BetweenExpr:
		return handleBetweenExpr(p, expr)
	case *ast.ParenthesesExpr:
		has, routeResult, newExpr, err := handleComparisonExpr(p, expr.Expr)
		expr.Expr = newExpr
		return has, routeResult, expr, err
	default:
		columnNameRewriter := NewColumnNameRewriteVisitor(p)
		expr.Accept(columnNameRewriter)
		return false, p.GetRouteResult().GetShardIndexes(), comp, nil
	}
}
func handlePatternInExpr(p *TableAliasStmtInfo, expr *ast.PatternInExpr) (bool, []int, ast.ExprNode, error) {
	rule, need, isAlias, err := NeedCreatePatternInExprDecorator(p, expr)
	if err != nil {
		return false, nil, nil, fmt.Errorf("check PatternInExpr error: %v", err)
	}
	if !need {
		return false, nil, expr, nil
	}
	decorator, err := CreatePatternInExprDecorator(expr, rule, isAlias, p.GetRouteResult())
	if err != nil {
		return false, nil, nil, fmt.Errorf("create PatternInExprDecorator error: %v", err)
	}
	return true, decorator.GetCurrentRouteResult(), decorator, nil
}
func handleBetweenExpr(p *TableAliasStmtInfo, expr *ast.BetweenExpr) (bool, []int, ast.ExprNode, error) {
	rule, need, isAlias, err := NeedCreateBetweenExprDecorator(p, expr)
	if err != nil {
		return false, nil, nil, fmt.Errorf("check BetweenExpr error: %v", err)
	}
	if !need {
		return false, nil, expr, nil
	}
	decorator, err := CreateBetweenExprDecorator(expr, rule, isAlias, p.GetRouteResult())
	if err != nil {
		return false, nil, nil, fmt.Errorf("create CreateBetweenExprDecorator error: %v", err)
	}
	return true, decorator.GetCurrentRouteResult(), decorator, nil
}