planner: clean useless Plan Cache code of binary protocol parameters (#36887)
ref pingcap/tidb#36598
This commit is contained in:
@ -15,7 +15,6 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -206,21 +205,16 @@ type PlanCacheValue struct {
|
||||
Plan Plan
|
||||
OutPutNames []*types.FieldName
|
||||
TblInfo2UnionScan map[*model.TableInfo]bool
|
||||
TxtVarTypes FieldSlice // variable types under text protocol
|
||||
BinVarTypes []byte // variable types under binary protocol
|
||||
IsBinProto bool // whether this plan is under binary protocol
|
||||
TxtVarTypes FieldSlice
|
||||
}
|
||||
|
||||
func (v *PlanCacheValue) varTypesUnchanged(binVarTps []byte, txtVarTps []*types.FieldType) bool {
|
||||
if v.IsBinProto {
|
||||
return bytes.Equal(v.BinVarTypes, binVarTps)
|
||||
}
|
||||
func (v *PlanCacheValue) varTypesUnchanged(txtVarTps []*types.FieldType) bool {
|
||||
return v.TxtVarTypes.CheckTypesCompatibility4PC(txtVarTps)
|
||||
}
|
||||
|
||||
// NewPlanCacheValue creates a SQLCacheValue.
|
||||
func NewPlanCacheValue(plan Plan, names []*types.FieldName, srcMap map[*model.TableInfo]bool,
|
||||
isBinProto bool, binVarTypes []byte, txtVarTps []*types.FieldType) *PlanCacheValue {
|
||||
txtVarTps []*types.FieldType) *PlanCacheValue {
|
||||
dstMap := make(map[*model.TableInfo]bool)
|
||||
for k, v := range srcMap {
|
||||
dstMap[k] = v
|
||||
@ -234,8 +228,6 @@ func NewPlanCacheValue(plan Plan, names []*types.FieldName, srcMap map[*model.Ta
|
||||
OutPutNames: names,
|
||||
TblInfo2UnionScan: dstMap,
|
||||
TxtVarTypes: userVarTypes,
|
||||
BinVarTypes: binVarTypes,
|
||||
IsBinProto: isBinProto,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -189,8 +189,7 @@ type Execute struct {
|
||||
baseSchemaProducer
|
||||
|
||||
Name string
|
||||
TxtProtoVars []expression.Expression // parsed variables under text protocol
|
||||
BinProtoVars []types.Datum // parsed variables under binary protocol
|
||||
TxtProtoVars []expression.Expression
|
||||
ExecID uint32
|
||||
Stmt ast.StmtNode
|
||||
StmtType string
|
||||
@ -229,41 +228,27 @@ func (e *Execute) OptimizePreparedPlan(ctx context.Context, sctx sessionctx.Cont
|
||||
prepared := preparedObj.PreparedAst
|
||||
vars.StmtCtx.StmtType = prepared.StmtType
|
||||
|
||||
paramLen := len(e.BinProtoVars)
|
||||
if paramLen > 0 {
|
||||
// for binary protocol execute, argument is placed in vars.BinProtoVars
|
||||
if len(prepared.Params) != paramLen {
|
||||
return errors.Trace(ErrWrongParamCount)
|
||||
}
|
||||
vars.PreparedParams = e.BinProtoVars
|
||||
for i, val := range vars.PreparedParams {
|
||||
param := prepared.Params[i].(*driver.ParamMarkerExpr)
|
||||
param.Datum = val
|
||||
param.InExecute = true
|
||||
}
|
||||
} else {
|
||||
// for `execute stmt using @a, @b, @c`, using value in e.TxtProtoVars
|
||||
if len(prepared.Params) != len(e.TxtProtoVars) {
|
||||
return errors.Trace(ErrWrongParamCount)
|
||||
}
|
||||
// for `execute stmt using @a, @b, @c`, using value in e.TxtProtoVars
|
||||
if len(prepared.Params) != len(e.TxtProtoVars) {
|
||||
return errors.Trace(ErrWrongParamCount)
|
||||
}
|
||||
|
||||
for i, usingVar := range e.TxtProtoVars {
|
||||
val, err := usingVar.Eval(chunk.Row{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
param := prepared.Params[i].(*driver.ParamMarkerExpr)
|
||||
if isGetVarBinaryLiteral(sctx, usingVar) {
|
||||
binVal, convErr := val.ToBytes()
|
||||
if convErr != nil {
|
||||
return convErr
|
||||
}
|
||||
val.SetBinaryLiteral(binVal)
|
||||
}
|
||||
param.Datum = val
|
||||
param.InExecute = true
|
||||
vars.PreparedParams = append(vars.PreparedParams, val)
|
||||
for i, usingVar := range e.TxtProtoVars {
|
||||
val, err := usingVar.Eval(chunk.Row{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
param := prepared.Params[i].(*driver.ParamMarkerExpr)
|
||||
if isGetVarBinaryLiteral(sctx, usingVar) {
|
||||
binVal, convErr := val.ToBytes()
|
||||
if convErr != nil {
|
||||
return convErr
|
||||
}
|
||||
val.SetBinaryLiteral(binVal)
|
||||
}
|
||||
param.Datum = val
|
||||
param.InExecute = true
|
||||
vars.PreparedParams = append(vars.PreparedParams, val)
|
||||
}
|
||||
|
||||
if prepared.SchemaVersion != is.SchemaMetaVersion() {
|
||||
@ -297,7 +282,7 @@ func (e *Execute) OptimizePreparedPlan(ctx context.Context, sctx sessionctx.Cont
|
||||
prepared.CachedPlan = nil
|
||||
vars.LastUpdateTime4PC = expiredTimeStamp4PC
|
||||
}
|
||||
plan, names, err := GetPlanFromSessionPlanCache(ctx, sctx, is, preparedObj, e.BinProtoVars, e.TxtProtoVars)
|
||||
plan, names, err := GetPlanFromSessionPlanCache(ctx, sctx, is, preparedObj, e.TxtProtoVars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ import (
|
||||
// It tries to get a valid cached plan from this session's plan cache.
|
||||
// If there is no such a plan, it'll call the optimizer to generate a new one.
|
||||
func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt,
|
||||
binProtoVars []types.Datum, txtProtoVars []expression.Expression) (plan Plan, names []*types.FieldName, err error) {
|
||||
txtProtoVars []expression.Expression) (plan Plan, names []*types.FieldName, err error) {
|
||||
var cacheKey kvcache.Key
|
||||
sessVars := sctx.GetSessionVars()
|
||||
stmtCtx := sessVars.StmtCtx
|
||||
@ -72,8 +72,7 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i
|
||||
}
|
||||
}
|
||||
|
||||
isBinProtocol := len(binProtoVars) > 0
|
||||
varsNum, binVarTypes, txtVarTypes := parseParamTypes(sctx, isBinProtocol, binProtoVars, txtProtoVars)
|
||||
varsNum, txtVarTypes := parseParamTypes(sctx, txtProtoVars)
|
||||
|
||||
if prepared.UseCache && prepared.CachedPlan != nil && !ignorePlanCache { // for point query plan
|
||||
if plan, names, ok, err := getPointQueryPlan(prepared, sessVars, stmtCtx); ok {
|
||||
@ -83,39 +82,31 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context, i
|
||||
|
||||
if prepared.UseCache && !ignorePlanCache { // for general plans
|
||||
if plan, names, ok, err := getGeneralPlan(ctx, sctx, cacheKey, bindSQL, is, preparedStmt,
|
||||
binVarTypes, txtVarTypes); err != nil || ok {
|
||||
txtVarTypes); err != nil || ok {
|
||||
return plan, names, err
|
||||
}
|
||||
}
|
||||
|
||||
return generateNewPlan(ctx, sctx, is, preparedStmt, ignorePlanCache, cacheKey,
|
||||
latestSchemaVersion, isBinProtocol, varsNum, binVarTypes, txtVarTypes, bindSQL)
|
||||
latestSchemaVersion, varsNum, txtVarTypes, bindSQL)
|
||||
}
|
||||
|
||||
// parseParamTypes get parameters' types in PREPARE statement
|
||||
func parseParamTypes(sctx sessionctx.Context, isBinProtocol bool, binProtoVars []types.Datum,
|
||||
txtProtoVars []expression.Expression) (varsNum int, binVarTypes []byte, txtVarTypes []*types.FieldType) {
|
||||
if isBinProtocol { // binary protocol
|
||||
varsNum = len(binProtoVars)
|
||||
for _, param := range binProtoVars {
|
||||
binVarTypes = append(binVarTypes, param.Kind())
|
||||
func parseParamTypes(sctx sessionctx.Context, txtProtoVars []expression.Expression) (varsNum int, txtVarTypes []*types.FieldType) {
|
||||
varsNum = len(txtProtoVars)
|
||||
for _, param := range txtProtoVars {
|
||||
if c, ok := param.(*expression.Constant); ok { // from binary protocol
|
||||
txtVarTypes = append(txtVarTypes, c.GetType())
|
||||
continue
|
||||
}
|
||||
} else { // txt protocol
|
||||
varsNum = len(txtProtoVars)
|
||||
for _, param := range txtProtoVars {
|
||||
if c, ok := param.(*expression.Constant); ok { // from binary protocol
|
||||
txtVarTypes = append(txtVarTypes, c.GetType())
|
||||
continue
|
||||
}
|
||||
|
||||
// from text protocol, there must be a GetVar function
|
||||
name := param.(*expression.ScalarFunction).GetArgs()[0].String()
|
||||
tp := sctx.GetSessionVars().UserVarTypes[name]
|
||||
if tp == nil {
|
||||
tp = types.NewFieldType(mysql.TypeNull)
|
||||
}
|
||||
txtVarTypes = append(txtVarTypes, tp)
|
||||
// from text protocol, there must be a GetVar function
|
||||
name := param.(*expression.ScalarFunction).GetArgs()[0].String()
|
||||
tp := sctx.GetSessionVars().UserVarTypes[name]
|
||||
if tp == nil {
|
||||
tp = types.NewFieldType(mysql.TypeNull)
|
||||
}
|
||||
txtVarTypes = append(txtVarTypes, tp)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -145,7 +136,7 @@ func getPointQueryPlan(prepared *ast.Prepared, sessVars *variable.SessionVars, s
|
||||
}
|
||||
|
||||
func getGeneralPlan(ctx context.Context, sctx sessionctx.Context, cacheKey kvcache.Key, bindSQL string,
|
||||
is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt, binVarTypes []byte, txtVarTypes []*types.FieldType) (Plan,
|
||||
is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt, txtVarTypes []*types.FieldType) (Plan,
|
||||
[]*types.FieldName, bool, error) {
|
||||
sessVars := sctx.GetSessionVars()
|
||||
stmtCtx := sessVars.StmtCtx
|
||||
@ -156,7 +147,7 @@ func getGeneralPlan(ctx context.Context, sctx sessionctx.Context, cacheKey kvcac
|
||||
}
|
||||
cachedVals := cacheValue.([]*PlanCacheValue)
|
||||
for _, cachedVal := range cachedVals {
|
||||
if !cachedVal.varTypesUnchanged(binVarTypes, txtVarTypes) {
|
||||
if !cachedVal.varTypesUnchanged(txtVarTypes) {
|
||||
continue
|
||||
}
|
||||
planValid := true
|
||||
@ -198,7 +189,7 @@ func getGeneralPlan(ctx context.Context, sctx sessionctx.Context, cacheKey kvcac
|
||||
// generateNewPlan call the optimizer to generate a new plan for current statement
|
||||
// and try to add it to cache
|
||||
func generateNewPlan(ctx context.Context, sctx sessionctx.Context, is infoschema.InfoSchema, preparedStmt *CachedPrepareStmt,
|
||||
ignorePlanCache bool, cacheKey kvcache.Key, latestSchemaVersion int64, isBinProtocol bool, varsNum int, binVarTypes []byte,
|
||||
ignorePlanCache bool, cacheKey kvcache.Key, latestSchemaVersion int64, varsNum int,
|
||||
txtVarTypes []*types.FieldType, bindSQL string) (Plan, []*types.FieldName, error) {
|
||||
prepared := preparedStmt.PreparedAst
|
||||
sessVars := sctx.GetSessionVars()
|
||||
@ -229,14 +220,14 @@ func generateNewPlan(ctx context.Context, sctx sessionctx.Context, is infoschema
|
||||
}
|
||||
sessVars.IsolationReadEngines[kv.TiFlash] = struct{}{}
|
||||
}
|
||||
cached := NewPlanCacheValue(p, names, stmtCtx.TblInfo2UnionScan, isBinProtocol, binVarTypes, txtVarTypes)
|
||||
cached := NewPlanCacheValue(p, names, stmtCtx.TblInfo2UnionScan, txtVarTypes)
|
||||
preparedStmt.NormalizedPlan, preparedStmt.PlanDigest = NormalizePlan(p)
|
||||
stmtCtx.SetPlan(p)
|
||||
stmtCtx.SetPlanDigest(preparedStmt.NormalizedPlan, preparedStmt.PlanDigest)
|
||||
if cacheVals, exists := sctx.PreparedPlanCache().Get(cacheKey); exists {
|
||||
hitVal := false
|
||||
for i, cacheVal := range cacheVals.([]*PlanCacheValue) {
|
||||
if cacheVal.varTypesUnchanged(binVarTypes, txtVarTypes) {
|
||||
if cacheVal.varTypesUnchanged(txtVarTypes) {
|
||||
hitVal = true
|
||||
cacheVals.([]*PlanCacheValue)[i] = cached
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user