Esempio n. 1
0
// 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
}
Esempio n. 2
0
// 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
}
Esempio n. 3
0
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)
}