예제 #1
0
파일: compiler.go 프로젝트: lovedboy/tidb
// 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
}
예제 #2
0
파일: compiler.go 프로젝트: xudongQiu/tidb
// 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
}
예제 #3
0
파일: prepared.go 프로젝트: lovedboy/tidb
// DoPrepare prepares the statement, it can be called multiple times without
// side effect.
func (e *PrepareExec) DoPrepare() {
	vars := variable.GetSessionVars(e.Ctx)
	if e.ID != 0 {
		// Must be the case when we retry a prepare.
		// Make sure it is idempotent.
		_, ok := vars.PreparedStmts[e.ID]
		if ok {
			return
		}
	}
	charset, collation := variable.GetCharsetInfo(e.Ctx)
	stmts, err := parser.Parse(e.SQLText, charset, collation)
	if err != nil {
		e.Err = errors.Trace(err)
		return
	}
	if len(stmts) != 1 {
		e.Err = ErrPrepareMulti
		return
	}
	stmt := stmts[0]
	var extractor paramMarkerExtractor
	stmt.Accept(&extractor)

	// The parameter markers are appended in visiting order, which may not
	// be the same as the position order in the query string. We need to
	// sort it by position.
	sorter := &paramMarkerSorter{markers: extractor.markers}
	sort.Sort(sorter)
	e.ParamCount = len(sorter.markers)
	prepared := &Prepared{
		Stmt:          stmt,
		Params:        sorter.markers,
		SchemaVersion: e.IS.SchemaMetaVersion(),
	}

	if optimizer.IsSupported(stmt) {
		err := optimizer.Prepare(e.IS, e.Ctx, stmt)
		if err != nil {
			e.Err = errors.Trace(err)
			return
		}
		if resultSetNode, ok := stmt.(ast.ResultSetNode); ok {
			e.ResultFields = convertResultFields(resultSetNode.GetResultFields())
		}
	}

	if e.ID == 0 {
		e.ID = vars.GetNextPreparedStmtID()
	}
	if e.Name != "" {
		vars.PreparedStmtNameToID[e.Name] = e.ID
	}
	vars.PreparedStmts[e.ID] = prepared
}
예제 #4
0
파일: prepared.go 프로젝트: xudongQiu/tidb
// 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
}
예제 #5
0
파일: session_test.go 프로젝트: zlxy/tidb
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)
}