// Optimize does optimization and creates a Plan. // The node must be prepared first. func Optimize(ctx context.Context, node ast.Node) (plan.Plan, error) { // We have to infer type again because after parameter is set, the expression type may change. if err := InferType(node); err != nil { return nil, errors.Trace(err) } if err := logicOptimize(ctx, node); err != nil { return nil, errors.Trace(err) } p, err := plan.BuildPlan(node) if err != nil { return nil, errors.Trace(err) } alts, err := plan.Alternatives(p) if err != nil { return nil, errors.Trace(err) } err = plan.Refine(p) if err != nil { return nil, errors.Trace(err) } bestCost := plan.EstimateCost(p) bestPlan := p for _, alt := range alts { err = plan.Refine(alt) if err != nil { return nil, errors.Trace(err) } cost := plan.EstimateCost(alt) if cost < bestCost { bestCost = cost bestPlan = alt } } return bestPlan, nil }
// Next implements Executor Next interface. // The data in the returned row is not used by caller. // If inner executor didn't get any row for an outer executor row, // a row with 0 len Data indicates there is no inner row matched for // an outer row. func (e *JoinOuterExec) Next() (*Row, error) { for { if e.innerExec == nil { e.gotRow = false outerRow, err := e.OuterExec.Next() if err != nil { return nil, errors.Trace(err) } if outerRow == nil { return nil, nil } plan.Refine(e.InnerPlan) e.innerExec = e.builder.build(e.InnerPlan) if e.builder.err != nil { return nil, errors.Trace(e.builder.err) } } row, err := e.innerExec.Next() if err != nil { return nil, errors.Trace(err) } if row == nil { e.innerExec = nil if e.gotRow { continue } e.setInnerNull() return &Row{}, nil } if len(row.Data) != 0 { e.gotRow = true return row, nil } } }
// Next implements Executor Next interface. // The data in the returned row is not used by caller. func (e *JoinInnerExec) Next() (*Row, error) { if e.done { return nil, nil } rowKeysSlice := make([][]*RowKeyEntry, len(e.InnerPlans)) for { exec := e.innerExecs[e.cursor] if exec == nil { innerPlan := e.InnerPlans[e.cursor] plan.Refine(innerPlan) exec = e.builder.build(innerPlan) if e.builder.err != nil { return nil, errors.Trace(e.builder.err) } e.innerExecs[e.cursor] = exec } row, err := exec.Next() if err != nil { return nil, errors.Trace(err) } if row == nil { exec.Close() e.innerExecs[e.cursor] = nil if e.cursor == 0 { e.done = true return nil, nil } e.cursor-- continue } rowKeysSlice[e.cursor] = row.RowKeys if e.cursor < len(e.innerExecs)-1 { e.cursor++ continue } var match = true if e.Condition != nil { match, err = evaluator.EvalBool(e.ctx, e.Condition) if err != nil { return nil, errors.Trace(err) } } if match { row.RowKeys = joinRowKeys(rowKeysSlice) return row, nil } } }
// Optimize does optimization and creates a Plan. // The node must be prepared first. func Optimize(ctx context.Context, node ast.Node, sb plan.SubQueryBuilder) (plan.Plan, error) { // We have to infer type again because after parameter is set, the expression type may change. if err := InferType(node); err != nil { return nil, errors.Trace(err) } if err := logicOptimize(ctx, node); err != nil { return nil, errors.Trace(err) } p, err := plan.BuildPlan(node, sb) if err != nil { return nil, errors.Trace(err) } err = plan.Refine(p) if err != nil { return nil, errors.Trace(err) } return p, nil }
func (sq *subquery) EvalRows(ctx context.Context, rowCount int) ([]interface{}, error) { b := newExecutorBuilder(ctx, sq.is) plan.Refine(sq.plan) e := b.build(sq.plan) if b.err != nil { return nil, errors.Trace(b.err) } defer e.Close() if len(e.Fields()) == 0 { // No result fields means no Recordset. for { row, err := e.Next() if err != nil { return nil, errors.Trace(err) } if row == nil { return nil, nil } } } var ( err error row *Row rows = []interface{}{} ) for rowCount != 0 { row, err = e.Next() if err != nil { return rows, errors.Trace(err) } if row == nil { break } if len(row.Data) == 1 { rows = append(rows, row.Data[0]) } else { rows = append(rows, row.Data) } if rowCount > 0 { rowCount-- } } return rows, nil }
// Next implements Executor Next interface. // The data in the returned row is not used by caller. // If inner executor didn't get any row for an outer executor row, // a row with 0 len Data indicates there is no inner row matched for // an outer row. func (e *JoinOuterExec) Next() (*Row, error) { var rowKeys []*RowKeyEntry for { if e.innerExec == nil { e.gotRow = false outerRow, err := e.OuterExec.Next() if err != nil { return nil, errors.Trace(err) } if outerRow == nil { return nil, nil } rowKeys = outerRow.RowKeys plan.Refine(e.InnerPlan) e.innerExec = e.builder.build(e.InnerPlan) if e.builder.err != nil { return nil, errors.Trace(e.builder.err) } } row, err := e.innerExec.Next() if err != nil { return nil, errors.Trace(err) } if row == nil { e.innerExec.Close() e.innerExec = nil if e.gotRow { continue } e.setInnerNull() return &Row{RowKeys: rowKeys}, nil } if len(row.Data) != 0 { e.gotRow = true row.RowKeys = append(rowKeys, row.RowKeys...) return row, nil } } }