From d566a30fa9356ff6d3c906ddd65cd0ce4e4d10d4 Mon Sep 17 00:00:00 2001 From: Chao Wang Date: Mon, 19 Aug 2024 15:23:54 +0800 Subject: [PATCH] expression: `ParseSimpleExpr` support to build param marker --- pkg/expression/contextstatic/exprctx.go | 5 +++ pkg/expression/util.go | 9 ++-- pkg/planner/core/BUILD.bazel | 2 + pkg/planner/core/expression_rewriter.go | 28 ++++++------ pkg/planner/core/expression_test.go | 57 ++++++++++++++---------- pkg/planner/core/logical_plan_builder.go | 23 +++++----- pkg/planner/core/planbuilder.go | 2 +- pkg/planner/core/point_get_plan.go | 22 ++++----- 8 files changed, 82 insertions(+), 66 deletions(-) diff --git a/pkg/expression/contextstatic/exprctx.go b/pkg/expression/contextstatic/exprctx.go index 21a6bac5d1891..14f8b8854b390 100644 --- a/pkg/expression/contextstatic/exprctx.go +++ b/pkg/expression/contextstatic/exprctx.go @@ -205,6 +205,11 @@ func (ctx *StaticExprContext) GetEvalCtx() exprctx.EvalContext { return ctx.evalCtx } +// GetStaticEvalCtx returns the inner `StaticEvalContext`. +func (ctx *StaticExprContext) GetStaticEvalCtx() *StaticEvalContext { + return ctx.evalCtx +} + // GetCharsetInfo implements the `ExprContext.GetCharsetInfo`. func (ctx *StaticExprContext) GetCharsetInfo() (string, string) { return ctx.charset, ctx.collation diff --git a/pkg/expression/util.go b/pkg/expression/util.go index f7b51e8983a3e..2af5c19d324f9 100644 --- a/pkg/expression/util.go +++ b/pkg/expression/util.go @@ -32,7 +32,6 @@ import ( "github.com/pingcap/tidb/pkg/parser/mysql" "github.com/pingcap/tidb/pkg/parser/opcode" "github.com/pingcap/tidb/pkg/parser/terror" - "github.com/pingcap/tidb/pkg/sessionctx/variable" "github.com/pingcap/tidb/pkg/types" driver "github.com/pingcap/tidb/pkg/types/parser_driver" "github.com/pingcap/tidb/pkg/util/chunk" @@ -1196,8 +1195,8 @@ func DatumToConstant(d types.Datum, tp byte, flag uint) *Constant { } // ParamMarkerExpression generate a getparam function expression. -func ParamMarkerExpression(ctx variable.SessionVarsProvider, v *driver.ParamMarkerExpr, needParam bool) (*Constant, error) { - useCache := ctx.GetSessionVars().StmtCtx.UseCache() +func ParamMarkerExpression(ctx BuildContext, v *driver.ParamMarkerExpr, needParam bool) (*Constant, error) { + useCache := ctx.IsUseCache() tp := types.NewFieldType(mysql.TypeUnspecified) types.InferParamTypeFromDatum(&v.Datum, tp) value := &Constant{Value: v.Datum, RetType: tp} @@ -1251,11 +1250,11 @@ func ConstructPositionExpr(p *driver.ParamMarkerExpr) *ast.PositionExpr { } // PosFromPositionExpr generates a position value from PositionExpr. -func PosFromPositionExpr(ctx BuildContext, vars variable.SessionVarsProvider, v *ast.PositionExpr) (int, bool, error) { +func PosFromPositionExpr(ctx BuildContext, v *ast.PositionExpr) (int, bool, error) { if v.P == nil { return v.N, false, nil } - value, err := ParamMarkerExpression(vars, v.P.(*driver.ParamMarkerExpr), false) + value, err := ParamMarkerExpression(ctx, v.P.(*driver.ParamMarkerExpr), false) if err != nil { return 0, true, err } diff --git a/pkg/planner/core/BUILD.bazel b/pkg/planner/core/BUILD.bazel index 0be151392f4df..0a2706490b719 100644 --- a/pkg/planner/core/BUILD.bazel +++ b/pkg/planner/core/BUILD.bazel @@ -271,6 +271,8 @@ go_test( "//pkg/domain", "//pkg/expression", "//pkg/expression/aggregation", + "//pkg/expression/context", + "//pkg/expression/contextstatic", "//pkg/infoschema", "//pkg/kv", "//pkg/metrics", diff --git a/pkg/planner/core/expression_rewriter.go b/pkg/planner/core/expression_rewriter.go index c1e126b19817c..cf15a23f2791c 100644 --- a/pkg/planner/core/expression_rewriter.go +++ b/pkg/planner/core/expression_rewriter.go @@ -1445,19 +1445,7 @@ func (er *expressionRewriter) Leave(originInNode ast.Node) (retNode ast.Node, ok } er.ctxStackAppend(value, types.EmptyName) case *driver.ParamMarkerExpr: - withPlanCtx(func(planCtx *exprRewriterPlanCtx) { - var value *expression.Constant - value, er.err = expression.ParamMarkerExpression(planCtx.builder.ctx, v, false) - if er.err != nil { - return - } - initConstantRepertoire(er.sctx.GetEvalCtx(), value) - er.adjustUTF8MB4Collation(value.RetType) - if er.err != nil { - return - } - er.ctxStackAppend(value, types.EmptyName) - }) + er.toParamMarker(v) case *ast.VariableExpr: withPlanCtx(func(planCtx *exprRewriterPlanCtx) { er.rewriteVariable(planCtx, v) @@ -2407,6 +2395,20 @@ func (er *expressionRewriter) toTable(v *ast.TableName) { er.ctxStackAppend(val, types.EmptyName) } +func (er *expressionRewriter) toParamMarker(v *driver.ParamMarkerExpr) { + var value *expression.Constant + value, er.err = expression.ParamMarkerExpression(er.sctx, v, false) + if er.err != nil { + return + } + initConstantRepertoire(er.sctx.GetEvalCtx(), value) + er.adjustUTF8MB4Collation(value.RetType) + if er.err != nil { + return + } + er.ctxStackAppend(value, types.EmptyName) +} + func (er *expressionRewriter) clause() clauseCode { if er.planCtx != nil { return er.planCtx.builder.curClause diff --git a/pkg/planner/core/expression_test.go b/pkg/planner/core/expression_test.go index cedfccdf538c8..f4e81a81c2be5 100644 --- a/pkg/planner/core/expression_test.go +++ b/pkg/planner/core/expression_test.go @@ -20,11 +20,14 @@ import ( "github.com/pingcap/tidb/pkg/domain" "github.com/pingcap/tidb/pkg/expression" + "github.com/pingcap/tidb/pkg/expression/context" + "github.com/pingcap/tidb/pkg/expression/contextstatic" "github.com/pingcap/tidb/pkg/parser" "github.com/pingcap/tidb/pkg/parser/ast" "github.com/pingcap/tidb/pkg/parser/charset" "github.com/pingcap/tidb/pkg/parser/model" "github.com/pingcap/tidb/pkg/parser/mysql" + "github.com/pingcap/tidb/pkg/sessionctx/variable" "github.com/pingcap/tidb/pkg/testkit/testutil" "github.com/pingcap/tidb/pkg/types" "github.com/pingcap/tidb/pkg/util/chunk" @@ -404,39 +407,36 @@ func TestBuildExpression(t *testing.T) { }, } - ctx := MockContext() - defer func() { - domain.GetDomain(ctx).StatsHandle().Close() - }() - + ctx := contextstatic.NewStaticExprContext() + evalCtx := ctx.GetStaticEvalCtx() cols, names, err := expression.ColumnInfos2ColumnsAndNames(ctx, model.NewCIStr(""), tbl.Name, tbl.Cols(), tbl) require.NoError(t, err) schema := expression.NewSchema(cols...) // normal build - ctx.GetSessionVars().PlanColumnID.Store(0) + ctx = ctx.Apply(contextstatic.WithColumnIDAllocator(context.NewSimplePlanColumnIDAllocator(0))) expr, err := buildExpr(t, ctx, "(1+a)*(3+b)", expression.WithTableInfo("", tbl)) require.NoError(t, err) - ctx.GetSessionVars().PlanColumnID.Store(0) + ctx = ctx.Apply(contextstatic.WithColumnIDAllocator(context.NewSimplePlanColumnIDAllocator(0))) expr2, err := expression.ParseSimpleExpr(ctx, "(1+a)*(3+b)", expression.WithTableInfo("", tbl)) require.NoError(t, err) - require.True(t, expr.Equal(ctx, expr2)) - val, _, err := expr.EvalInt(ctx, chunk.MutRowFromValues("", 1, 2).ToRow()) + require.True(t, expr.Equal(evalCtx, expr2)) + val, _, err := expr.EvalInt(evalCtx, chunk.MutRowFromValues("", 1, 2).ToRow()) require.NoError(t, err) require.Equal(t, int64(10), val) - val, _, err = expr.EvalInt(ctx, chunk.MutRowFromValues("", 3, 4).ToRow()) + val, _, err = expr.EvalInt(evalCtx, chunk.MutRowFromValues("", 3, 4).ToRow()) require.NoError(t, err) require.Equal(t, int64(28), val) - val, _, err = expr2.EvalInt(ctx, chunk.MutRowFromValues("", 1, 2).ToRow()) + val, _, err = expr2.EvalInt(evalCtx, chunk.MutRowFromValues("", 1, 2).ToRow()) require.NoError(t, err) require.Equal(t, int64(10), val) - val, _, err = expr2.EvalInt(ctx, chunk.MutRowFromValues("", 3, 4).ToRow()) + val, _, err = expr2.EvalInt(evalCtx, chunk.MutRowFromValues("", 3, 4).ToRow()) require.NoError(t, err) require.Equal(t, int64(28), val) expr, err = buildExpr(t, ctx, "(1+a)*(3+b)", expression.WithInputSchemaAndNames(schema, names, nil)) require.NoError(t, err) - val, _, err = expr.EvalInt(ctx, chunk.MutRowFromValues("", 1, 2).ToRow()) + val, _, err = expr.EvalInt(evalCtx, chunk.MutRowFromValues("", 1, 2).ToRow()) require.NoError(t, err) require.Equal(t, int64(10), val) @@ -452,7 +452,7 @@ func TestBuildExpression(t *testing.T) { // use WithAllowCastArray to allow casting to array expr, err = buildExpr(t, ctx, `cast(json_extract('{"a": [1, 2, 3]}', '$.a') as signed array)`, expression.WithAllowCastArray(true)) require.NoError(t, err) - j, _, err := expr.EvalJSON(ctx, chunk.Row{}) + j, _, err := expr.EvalJSON(evalCtx, chunk.Row{}) require.NoError(t, err) require.Equal(t, types.JSONTypeCodeArray, j.TypeCode) require.Equal(t, "[1, 2, 3]", j.String()) @@ -460,35 +460,48 @@ func TestBuildExpression(t *testing.T) { // default expr expr, err = buildExpr(t, ctx, "default(id)", expression.WithTableInfo("", tbl)) require.NoError(t, err) - s, _, err := expr.EvalString(ctx, chunk.MutRowFromValues("", 1, 2).ToRow()) + s, _, err := expr.EvalString(evalCtx, chunk.MutRowFromValues("", 1, 2).ToRow()) require.NoError(t, err) require.Equal(t, 36, len(s), s) expr, err = buildExpr(t, ctx, "default(id)", expression.WithInputSchemaAndNames(schema, names, tbl)) require.NoError(t, err) - s, _, err = expr.EvalString(ctx, chunk.MutRowFromValues("", 1, 2).ToRow()) + s, _, err = expr.EvalString(evalCtx, chunk.MutRowFromValues("", 1, 2).ToRow()) require.NoError(t, err) require.Equal(t, 36, len(s), s) expr, err = buildExpr(t, ctx, "default(b)", expression.WithTableInfo("", tbl)) require.NoError(t, err) - d, err := expr.Eval(ctx, chunk.MutRowFromValues("", 1, 2).ToRow()) + d, err := expr.Eval(evalCtx, chunk.MutRowFromValues("", 1, 2).ToRow()) require.NoError(t, err) require.Equal(t, types.NewDatum(int64(123)), d) // WithCastExprTo expr, err = buildExpr(t, ctx, "1+2+3") require.NoError(t, err) - require.Equal(t, mysql.TypeLonglong, expr.GetType(ctx).GetType()) + require.Equal(t, mysql.TypeLonglong, expr.GetType(evalCtx).GetType()) castTo := types.NewFieldType(mysql.TypeVarchar) expr, err = buildExpr(t, ctx, "1+2+3", expression.WithCastExprTo(castTo)) require.NoError(t, err) - require.Equal(t, mysql.TypeVarchar, expr.GetType(ctx).GetType()) - v, err := expr.Eval(ctx, chunk.Row{}) + require.Equal(t, mysql.TypeVarchar, expr.GetType(evalCtx).GetType()) + v, err := expr.Eval(evalCtx, chunk.Row{}) require.NoError(t, err) require.Equal(t, types.KindString, v.Kind()) require.Equal(t, "6", v.GetString()) + // param marker + params := variable.NewPlanCacheParamList() + params.Append(types.NewIntDatum(5)) + evalCtx = evalCtx.Apply(contextstatic.WithParamList(params)) + ctx = ctx.Apply(contextstatic.WithEvalCtx(evalCtx)) + expr, err = buildExpr(t, ctx, "a + ?", expression.WithTableInfo("", tbl)) + require.NoError(t, err) + require.Equal(t, mysql.TypeLonglong, expr.GetType(evalCtx).GetType()) + v, err = expr.Eval(evalCtx, chunk.MutRowFromValues(1, 2, 3).ToRow()) + require.NoError(t, err) + require.Equal(t, types.KindInt64, v.Kind()) + require.Equal(t, int64(7), v.GetInt64()) + // should report error for default expr when source table not provided _, err = buildExpr(t, ctx, "default(b)", expression.WithInputSchemaAndNames(schema, names, nil)) require.EqualError(t, err, "Unsupported expr *ast.DefaultExpr when source table not provided") @@ -496,8 +509,4 @@ func TestBuildExpression(t *testing.T) { // subquery not supported _, err = buildExpr(t, ctx, "a + (select b from t)", expression.WithTableInfo("", tbl)) require.EqualError(t, err, "node '*ast.SubqueryExpr' is not allowed when building an expression without planner") - - // param marker not supported - _, err = buildExpr(t, ctx, "a + ?", expression.WithTableInfo("", tbl)) - require.EqualError(t, err, "node '*driver.ParamMarkerExpr' is not allowed when building an expression without planner") } diff --git a/pkg/planner/core/logical_plan_builder.go b/pkg/planner/core/logical_plan_builder.go index d6628099b10db..4e27e7119599a 100644 --- a/pkg/planner/core/logical_plan_builder.go +++ b/pkg/planner/core/logical_plan_builder.go @@ -97,7 +97,7 @@ func (a *aggOrderByResolver) Enter(inNode ast.Node) (ast.Node, bool) { a.exprDepth++ if n, ok := inNode.(*driver.ParamMarkerExpr); ok { if a.exprDepth == 1 { - _, isNull, isExpectedType := getUintFromNode(a.ctx, n, false) + _, isNull, isExpectedType := getUintFromNode(a.ctx.GetExprCtx(), n, false) // For constant uint expression in top level, it should be treated as position expression. if !isNull && isExpectedType { return expression.ConstructPositionExpr(n), true @@ -109,7 +109,7 @@ func (a *aggOrderByResolver) Enter(inNode ast.Node) (ast.Node, bool) { func (a *aggOrderByResolver) Leave(inNode ast.Node) (ast.Node, bool) { if v, ok := inNode.(*ast.PositionExpr); ok { - pos, isNull, err := expression.PosFromPositionExpr(a.ctx.GetExprCtx(), a.ctx, v) + pos, isNull, err := expression.PosFromPositionExpr(a.ctx.GetExprCtx(), v) if err != nil { a.err = err } @@ -2006,7 +2006,7 @@ CheckReferenced: // getUintFromNode gets uint64 value from ast.Node. // For ordinary statement, node should be uint64 constant value. // For prepared statement, node is string. We should convert it to uint64. -func getUintFromNode(ctx base.PlanContext, n ast.Node, mustInt64orUint64 bool) (uVal uint64, isNull bool, isExpectedType bool) { +func getUintFromNode(ctx expression.BuildContext, n ast.Node, mustInt64orUint64 bool) (uVal uint64, isNull bool, isExpectedType bool) { var val any switch v := n.(type) { case *driver.ValueExpr: @@ -2024,7 +2024,7 @@ func getUintFromNode(ctx base.PlanContext, n ast.Node, mustInt64orUint64 bool) ( if err != nil { return 0, false, false } - str, isNull, err := expression.GetStringFromConstant(ctx.GetExprCtx().GetEvalCtx(), param) + str, isNull, err := expression.GetStringFromConstant(ctx.GetEvalCtx(), param) if err != nil { return 0, false, false } @@ -2043,8 +2043,7 @@ func getUintFromNode(ctx base.PlanContext, n ast.Node, mustInt64orUint64 bool) ( return uint64(v), false, true } case string: - ctx := ctx.GetSessionVars().StmtCtx.TypeCtx() - uVal, err := types.StrToUint(ctx, v, false) + uVal, err := types.StrToUint(ctx.GetEvalCtx().TypeCtx(), v, false) if err != nil { return 0, false, false } @@ -2068,7 +2067,7 @@ func CheckParamTypeInt64orUint64(param *driver.ParamMarkerExpr) (bool, uint64) { return false, 0 } -func extractLimitCountOffset(ctx base.PlanContext, limit *ast.Limit) (count uint64, +func extractLimitCountOffset(ctx expression.BuildContext, limit *ast.Limit) (count uint64, offset uint64, err error) { var isExpectedType bool if limit.Count != nil { @@ -2092,7 +2091,7 @@ func (b *PlanBuilder) buildLimit(src base.LogicalPlan, limit *ast.Limit) (base.L offset, count uint64 err error ) - if count, offset, err = extractLimitCountOffset(b.ctx, limit); err != nil { + if count, offset, err = extractLimitCountOffset(b.ctx.GetExprCtx(), limit); err != nil { return nil, err } @@ -2845,7 +2844,7 @@ func (g *gbyResolver) Enter(inNode ast.Node) (ast.Node, bool) { case *driver.ParamMarkerExpr: g.isParam = true if g.exprDepth == 1 && !n.UseAsValueInGbyByClause { - _, isNull, isExpectedType := getUintFromNode(g.ctx, n, false) + _, isNull, isExpectedType := getUintFromNode(g.ctx.GetExprCtx(), n, false) // For constant uint expression in top level, it should be treated as position expression. if !isNull && isExpectedType { return expression.ConstructPositionExpr(n), true @@ -2892,7 +2891,7 @@ func (g *gbyResolver) Leave(inNode ast.Node) (ast.Node, bool) { return inNode, false } case *ast.PositionExpr: - pos, isNull, err := expression.PosFromPositionExpr(g.ctx.GetExprCtx(), g.ctx, v) + pos, isNull, err := expression.PosFromPositionExpr(g.ctx.GetExprCtx(), v) if err != nil { g.err = plannererrors.ErrUnknown.GenWithStackByArgs() } @@ -6069,7 +6068,7 @@ func (b *PlanBuilder) buildWindowFunctionFrameBound(_ context.Context, spec *ast if bound.Type == ast.CurrentRow { return bound, nil } - numRows, _, _ := getUintFromNode(b.ctx, boundClause.Expr, false) + numRows, _, _ := getUintFromNode(b.ctx.GetExprCtx(), boundClause.Expr, false) bound.Num = numRows return bound, nil } @@ -6391,7 +6390,7 @@ func (b *PlanBuilder) checkOriginWindowFrameBound(bound *ast.FrameBound, spec *a if bound.Unit != ast.TimeUnitInvalid { return plannererrors.ErrWindowRowsIntervalUse.GenWithStackByArgs(getWindowName(spec.Name.O)) } - _, isNull, isExpectedType := getUintFromNode(b.ctx, bound.Expr, false) + _, isNull, isExpectedType := getUintFromNode(b.ctx.GetExprCtx(), bound.Expr, false) if isNull || !isExpectedType { return plannererrors.ErrWindowFrameIllegal.GenWithStackByArgs(getWindowName(spec.Name.O)) } diff --git a/pkg/planner/core/planbuilder.go b/pkg/planner/core/planbuilder.go index 16c30a1f02d4c..5ff623e2e42e1 100644 --- a/pkg/planner/core/planbuilder.go +++ b/pkg/planner/core/planbuilder.go @@ -4011,7 +4011,7 @@ func (b PlanBuilder) getInsertColExpr(ctx context.Context, insertPlan *Insert, m RetType: &x.Type, } case *driver.ParamMarkerExpr: - outExpr, err = expression.ParamMarkerExpression(b.ctx, x, false) + outExpr, err = expression.ParamMarkerExpression(b.ctx.GetExprCtx(), x, false) default: b.curClause = fieldList // subquery in insert values should not reference upper scope diff --git a/pkg/planner/core/point_get_plan.go b/pkg/planner/core/point_get_plan.go index 579377c65c4dc..fc1b92282d8cb 100644 --- a/pkg/planner/core/point_get_plan.go +++ b/pkg/planner/core/point_get_plan.go @@ -1015,7 +1015,7 @@ func newBatchPointGetPlan( d = x.Datum case *driver.ParamMarkerExpr: var err error - con, err = expression.ParamMarkerExpression(ctx, x, true) + con, err = expression.ParamMarkerExpression(ctx.GetExprCtx(), x, true) if err != nil { return nil } @@ -1130,7 +1130,7 @@ func newBatchPointGetPlan( values[permIndex] = innerX.Datum pairs = append(pairs, nameValuePair{colName: whereColNames[index], value: innerX.Datum}) case *driver.ParamMarkerExpr: - con, err := expression.ParamMarkerExpression(ctx, innerX, true) + con, err := expression.ParamMarkerExpression(ctx.GetExprCtx(), innerX, true) if err != nil { return nil } @@ -1169,7 +1169,7 @@ func newBatchPointGetPlan( if len(whereColNames) != 1 { return nil } - con, err := expression.ParamMarkerExpression(ctx, x, true) + con, err := expression.ParamMarkerExpression(ctx.GetExprCtx(), x, true) if err != nil { return nil } @@ -1311,7 +1311,7 @@ func tryPointGetPlan(ctx base.PlanContext, selStmt *ast.SelectStmt, check bool) if selStmt.Having != nil || selStmt.OrderBy != nil { return nil } else if selStmt.Limit != nil { - count, offset, err := extractLimitCountOffset(ctx, selStmt.Limit) + count, offset, err := extractLimitCountOffset(ctx.GetExprCtx(), selStmt.Limit) if err != nil || count == 0 || offset > 0 { return nil } @@ -1349,7 +1349,7 @@ func tryPointGetPlan(ctx base.PlanContext, selStmt *ast.SelectStmt, check bool) } pairs := make([]nameValuePair, 0, 4) - pairs, isTableDual := getNameValuePairs(ctx, tbl, tblAlias, pairs, selStmt.Where) + pairs, isTableDual := getNameValuePairs(ctx.GetExprCtx(), tbl, tblAlias, pairs, selStmt.Where) if pairs == nil && !isTableDual { return nil } @@ -1648,9 +1648,9 @@ func getSingleTableNameAndAlias(tableRefs *ast.TableRefsClause) (tblName *ast.Ta } // getNameValuePairs extracts `column = constant/paramMarker` conditions from expr as name value pairs. -func getNameValuePairs(ctx base.PlanContext, tbl *model.TableInfo, tblName model.CIStr, nvPairs []nameValuePair, expr ast.ExprNode) ( +func getNameValuePairs(ctx expression.BuildContext, tbl *model.TableInfo, tblName model.CIStr, nvPairs []nameValuePair, expr ast.ExprNode) ( pairs []nameValuePair, isTableDual bool) { - stmtCtx := ctx.GetSessionVars().StmtCtx + evalCtx := ctx.GetEvalCtx() binOp, ok := expr.(*ast.BinaryOperationExpr) if !ok { return nil, false @@ -1682,7 +1682,7 @@ func getNameValuePairs(ctx base.PlanContext, tbl *model.TableInfo, tblName model if err != nil { return nil, false } - d, err = con.Eval(ctx.GetExprCtx().GetEvalCtx(), chunk.Row{}) + d, err = con.Eval(evalCtx, chunk.Row{}) if err != nil { return nil, false } @@ -1696,7 +1696,7 @@ func getNameValuePairs(ctx base.PlanContext, tbl *model.TableInfo, tblName model if err != nil { return nil, false } - d, err = con.Eval(ctx.GetExprCtx().GetEvalCtx(), chunk.Row{}) + d, err = con.Eval(evalCtx, chunk.Row{}) if err != nil { return nil, false } @@ -1735,7 +1735,7 @@ func getNameValuePairs(ctx base.PlanContext, tbl *model.TableInfo, tblName model if col.GetType() == mysql.TypeString && col.GetCollate() == charset.CollationBin { // This type we needn't to pad `\0` in here. return append(nvPairs, nameValuePair{colName: colName.Name.Name.L, colFieldType: &col.FieldType, value: d, con: con}), false } - dVal, err := d.ConvertTo(stmtCtx.TypeCtx(), &col.FieldType) + dVal, err := d.ConvertTo(evalCtx.TypeCtx(), &col.FieldType) if err != nil { if terror.ErrorEqual(types.ErrOverflow, err) { return append(nvPairs, nameValuePair{colName: colName.Name.Name.L, colFieldType: &col.FieldType, value: d, con: con}), true @@ -1746,7 +1746,7 @@ func getNameValuePairs(ctx base.PlanContext, tbl *model.TableInfo, tblName model } } // The converted result must be same as original datum. - cmp, err := dVal.Compare(stmtCtx.TypeCtx(), &d, collate.GetCollator(col.GetCollate())) + cmp, err := dVal.Compare(evalCtx.TypeCtx(), &d, collate.GetCollator(col.GetCollate())) if err != nil || cmp != 0 { return nil, false }