// Compile compiles an ast.StmtNode to a stmt.Statement. // If it is supported to use new plan and executer, it optimizes the node to // a plan, and we wrap the plan in an adapter as stmt.Statement. // If it is not supported, the node will be converted to old statement. func (c *Compiler) Compile(ctx context.Context, node ast.StmtNode) (stmt.Statement, error) { if optimizer.IsSupported(node) { ast.SetFlag(node) is := sessionctx.GetDomain(ctx).InfoSchema() if err := optimizer.Preprocess(node, is, ctx); err != nil { return nil, errors.Trace(err) } // Validate should be after NameResolve. if err := optimizer.Validate(node, false); err != nil { return nil, errors.Trace(err) } sb := NewSubQueryBuilder(is) p, err := optimizer.Optimize(ctx, node, sb) if err != nil { return nil, errors.Trace(err) } sa := &statementAdapter{ is: is, plan: p, } return sa, nil } c.converter = &converter.Converter{} s, err := c.converter.Convert(node) if err != nil { return nil, errors.Trace(err) } return s, nil }
// Compile compiles an ast.StmtNode to a stmt.Statement. // If it is supported to use new plan and executer, it optimizes the node to // a plan, and we wrap the plan in an adapter as stmt.Statement. // If it is not supported, the node will be converted to old statement. func (c *Compiler) Compile(ctx context.Context, node ast.StmtNode) (stmt.Statement, error) { if optimizer.IsSupported(node) { ast.SetFlag(node) if err := optimizer.Validate(node, false); err != nil { return nil, errors.Trace(err) } is := sessionctx.GetDomain(ctx).InfoSchema() if err := optimizer.ResolveName(node, is, ctx); err != nil { return nil, errors.Trace(err) } p, err := optimizer.Optimize(ctx, node) if err != nil { return nil, errors.Trace(err) } sa := &statementAdapter{ is: is, plan: p, } return sa, nil } c.converter = &converter.Converter{} s, err := c.converter.Convert(node) if err != nil { return nil, errors.Trace(err) } return s, nil }
// Build builds a prepared statement into an executor. func (e *ExecuteExec) Build() error { vars := variable.GetSessionVars(e.Ctx) if e.Name != "" { e.ID = vars.PreparedStmtNameToID[e.Name] } v := vars.PreparedStmts[e.ID] if v == nil { return ErrStmtNotFound } prepared := v.(*Prepared) if len(prepared.Params) != len(e.UsingVars) { return ErrWrongParamCount } for i, usingVar := range e.UsingVars { val, err := evaluator.Eval(e.Ctx, usingVar) if err != nil { return errors.Trace(err) } prepared.Params[i].SetValue(val) } if optimizer.IsSupported(prepared.Stmt) { if prepared.SchemaVersion != e.IS.SchemaMetaVersion() { // If the schema version has changed we need to prepare it again, // if this time it failed, the real reason for the error is schema changed. err := optimizer.Prepare(e.IS, e.Ctx, prepared.Stmt) if err != nil { return ErrSchemaChanged.Gen("Schema change casued error: %s", err.Error()) } prepared.SchemaVersion = e.IS.SchemaMetaVersion() } sb := &subqueryBuilder{is: e.IS} plan, err := optimizer.Optimize(e.Ctx, prepared.Stmt, sb) if err != nil { return errors.Trace(err) } b := newExecutorBuilder(e.Ctx, e.IS) stmtExec := b.build(plan) if b.err != nil { return errors.Trace(b.err) } e.StmtExec = stmtExec } else { conv := converter.Converter{} oStmt, err := conv.Convert(prepared.Stmt) if err != nil { return errors.Trace(err) } e.OldStmt = oStmt } return nil }
func checkPlan(c *C, se Session, sql, explain string) { ctx := se.(context.Context) stmts, err := Parse(ctx, sql) c.Assert(err, IsNil) stmt := stmts[0] c.Assert(optimizer.IsSupported(stmt), IsTrue) is := sessionctx.GetDomain(ctx).InfoSchema() err = optimizer.Prepare(is, ctx, stmt) c.Assert(err, IsNil) p, err := optimizer.Optimize(ctx, stmt) c.Assert(err, IsNil) planStr, err := plan.Explain(p) c.Assert(err, IsNil) c.Assert(planStr, Equals, explain) }