github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/executor/prepared.go (about)

     1  // Copyright 2015 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package executor
    15  
    16  import (
    17  	"sort"
    18  
    19  	"github.com/insionng/yougam/libraries/juju/errors"
    20  	"github.com/insionng/yougam/libraries/pingcap/tidb/ast"
    21  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/evaluator"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/infoschema"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/optimizer"
    25  	"github.com/insionng/yougam/libraries/pingcap/tidb/optimizer/plan"
    26  	"github.com/insionng/yougam/libraries/pingcap/tidb/parser"
    27  	"github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx"
    28  	"github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx/variable"
    29  )
    30  
    31  var (
    32  	_ Executor = &DeallocateExec{}
    33  	_ Executor = &ExecuteExec{}
    34  	_ Executor = &PrepareExec{}
    35  )
    36  
    37  type paramMarkerSorter struct {
    38  	markers []*ast.ParamMarkerExpr
    39  }
    40  
    41  func (p *paramMarkerSorter) Len() int {
    42  	return len(p.markers)
    43  }
    44  
    45  func (p *paramMarkerSorter) Less(i, j int) bool {
    46  	return p.markers[i].Offset < p.markers[j].Offset
    47  }
    48  
    49  func (p *paramMarkerSorter) Swap(i, j int) {
    50  	p.markers[i], p.markers[j] = p.markers[j], p.markers[i]
    51  }
    52  
    53  type paramMarkerExtractor struct {
    54  	markers []*ast.ParamMarkerExpr
    55  }
    56  
    57  func (e *paramMarkerExtractor) Enter(in ast.Node) (ast.Node, bool) {
    58  	return in, false
    59  }
    60  
    61  func (e *paramMarkerExtractor) Leave(in ast.Node) (ast.Node, bool) {
    62  	if x, ok := in.(*ast.ParamMarkerExpr); ok {
    63  		e.markers = append(e.markers, x)
    64  	}
    65  	return in, true
    66  }
    67  
    68  // Prepared represents a prepared statement.
    69  type Prepared struct {
    70  	Stmt          ast.StmtNode
    71  	Params        []*ast.ParamMarkerExpr
    72  	SchemaVersion int64
    73  }
    74  
    75  // PrepareExec represents a PREPARE executor.
    76  type PrepareExec struct {
    77  	IS      infoschema.InfoSchema
    78  	Ctx     context.Context
    79  	Name    string
    80  	SQLText string
    81  
    82  	ID           uint32
    83  	ResultFields []*ast.ResultField
    84  	ParamCount   int
    85  	Err          error
    86  }
    87  
    88  // Fields implements Executor Fields interface.
    89  func (e *PrepareExec) Fields() []*ast.ResultField {
    90  	// returns nil to indicate prepare will not return Recordset.
    91  	return nil
    92  }
    93  
    94  // Next implements Executor Next interface.
    95  func (e *PrepareExec) Next() (*Row, error) {
    96  	e.DoPrepare()
    97  	return nil, e.Err
    98  }
    99  
   100  // Close implements plan.Plan Close interface.
   101  func (e *PrepareExec) Close() error {
   102  	return nil
   103  }
   104  
   105  // DoPrepare prepares the statement, it can be called multiple times without
   106  // side effect.
   107  func (e *PrepareExec) DoPrepare() {
   108  	vars := variable.GetSessionVars(e.Ctx)
   109  	if e.ID != 0 {
   110  		// Must be the case when we retry a prepare.
   111  		// Make sure it is idempotent.
   112  		_, ok := vars.PreparedStmts[e.ID]
   113  		if ok {
   114  			return
   115  		}
   116  	}
   117  	charset, collation := variable.GetCharsetInfo(e.Ctx)
   118  	stmts, err := parser.Parse(e.SQLText, charset, collation)
   119  	if err != nil {
   120  		e.Err = errors.Trace(err)
   121  		return
   122  	}
   123  	if len(stmts) != 1 {
   124  		e.Err = ErrPrepareMulti
   125  		return
   126  	}
   127  	stmt := stmts[0]
   128  	var extractor paramMarkerExtractor
   129  	stmt.Accept(&extractor)
   130  
   131  	// The parameter markers are appended in visiting order, which may not
   132  	// be the same as the position order in the query string. We need to
   133  	// sort it by position.
   134  	sorter := &paramMarkerSorter{markers: extractor.markers}
   135  	sort.Sort(sorter)
   136  	e.ParamCount = len(sorter.markers)
   137  	prepared := &Prepared{
   138  		Stmt:          stmt,
   139  		Params:        sorter.markers,
   140  		SchemaVersion: e.IS.SchemaMetaVersion(),
   141  	}
   142  
   143  	err = optimizer.Prepare(e.IS, e.Ctx, stmt)
   144  	if err != nil {
   145  		e.Err = errors.Trace(err)
   146  		return
   147  	}
   148  	if resultSetNode, ok := stmt.(ast.ResultSetNode); ok {
   149  		e.ResultFields = resultSetNode.GetResultFields()
   150  	}
   151  
   152  	if e.ID == 0 {
   153  		e.ID = vars.GetNextPreparedStmtID()
   154  	}
   155  	if e.Name != "" {
   156  		vars.PreparedStmtNameToID[e.Name] = e.ID
   157  	}
   158  	vars.PreparedStmts[e.ID] = prepared
   159  }
   160  
   161  // ExecuteExec represents an EXECUTE executor.
   162  // It executes a prepared statement.
   163  type ExecuteExec struct {
   164  	IS        infoschema.InfoSchema
   165  	Ctx       context.Context
   166  	Name      string
   167  	UsingVars []ast.ExprNode
   168  	ID        uint32
   169  	StmtExec  Executor
   170  	Stmt      ast.StmtNode
   171  }
   172  
   173  // Fields implements Executor Fields interface.
   174  func (e *ExecuteExec) Fields() []*ast.ResultField {
   175  	// Will never be called.
   176  	return nil
   177  }
   178  
   179  // Next implements Executor Next interface.
   180  func (e *ExecuteExec) Next() (*Row, error) {
   181  	// Will never be called.
   182  	return nil, nil
   183  }
   184  
   185  // Close implements plan.Plan Close interface.
   186  func (e *ExecuteExec) Close() error {
   187  	// Will never be called.
   188  	return nil
   189  }
   190  
   191  // Build builds a prepared statement into an executor.
   192  func (e *ExecuteExec) Build() error {
   193  	vars := variable.GetSessionVars(e.Ctx)
   194  	if e.Name != "" {
   195  		e.ID = vars.PreparedStmtNameToID[e.Name]
   196  	}
   197  	v := vars.PreparedStmts[e.ID]
   198  	if v == nil {
   199  		return ErrStmtNotFound
   200  	}
   201  	prepared := v.(*Prepared)
   202  
   203  	if len(prepared.Params) != len(e.UsingVars) {
   204  		return ErrWrongParamCount
   205  	}
   206  
   207  	for i, usingVar := range e.UsingVars {
   208  		val, err := evaluator.Eval(e.Ctx, usingVar)
   209  		if err != nil {
   210  			return errors.Trace(err)
   211  		}
   212  		prepared.Params[i].SetDatum(val)
   213  	}
   214  
   215  	ast.ResetEvaluatedFlag(prepared.Stmt)
   216  	if prepared.SchemaVersion != e.IS.SchemaMetaVersion() {
   217  		// If the schema version has changed we need to prepare it again,
   218  		// if this time it failed, the real reason for the error is schema changed.
   219  		err := optimizer.Prepare(e.IS, e.Ctx, prepared.Stmt)
   220  		if err != nil {
   221  			return ErrSchemaChanged.Gen("Schema change casued error: %s", err.Error())
   222  		}
   223  		prepared.SchemaVersion = e.IS.SchemaMetaVersion()
   224  	}
   225  	sb := &subqueryBuilder{is: e.IS}
   226  	plan, err := optimizer.Optimize(e.Ctx, prepared.Stmt, sb)
   227  	if err != nil {
   228  		return errors.Trace(err)
   229  	}
   230  	b := newExecutorBuilder(e.Ctx, e.IS)
   231  	stmtExec := b.build(plan)
   232  	if b.err != nil {
   233  		return errors.Trace(b.err)
   234  	}
   235  	e.StmtExec = stmtExec
   236  	e.Stmt = prepared.Stmt
   237  	return nil
   238  }
   239  
   240  // DeallocateExec represent a DEALLOCATE executor.
   241  type DeallocateExec struct {
   242  	Name string
   243  	ctx  context.Context
   244  }
   245  
   246  // Fields implements Executor Fields interface.
   247  func (e *DeallocateExec) Fields() []*ast.ResultField {
   248  	return nil
   249  }
   250  
   251  // Next implements Executor Next interface.
   252  func (e *DeallocateExec) Next() (*Row, error) {
   253  	vars := variable.GetSessionVars(e.ctx)
   254  	id, ok := vars.PreparedStmtNameToID[e.Name]
   255  	if !ok {
   256  		return nil, ErrStmtNotFound
   257  	}
   258  	delete(vars.PreparedStmtNameToID, e.Name)
   259  	delete(vars.PreparedStmts, id)
   260  	return nil, nil
   261  }
   262  
   263  // Close implements plan.Plan Close interface.
   264  func (e *DeallocateExec) Close() error {
   265  	return nil
   266  }
   267  
   268  // CompileExecutePreparedStmt compiles a session Execute command to a stmt.Statement.
   269  func CompileExecutePreparedStmt(ctx context.Context, ID uint32, args ...interface{}) ast.Statement {
   270  	execPlan := &plan.Execute{ID: ID}
   271  	execPlan.UsingVars = make([]ast.ExprNode, len(args))
   272  	for i, val := range args {
   273  		execPlan.UsingVars[i] = ast.NewValueExpr(val)
   274  	}
   275  	sa := &statement{
   276  		is:   sessionctx.GetDomain(ctx).InfoSchema(),
   277  		plan: execPlan,
   278  	}
   279  	return sa
   280  }