diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index c9beca4d054ec..fbf6ff47200a7 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -556,6 +556,7 @@ func newBatchPointGetPlan( handleCol *model.ColumnInfo, tbl *model.TableInfo, schema *expression.Schema, names []*types.FieldName, whereColNames []string, indexHints []*ast.IndexHint, ) *BatchPointGetPlan { + stmtCtx := ctx.GetSessionVars().StmtCtx statsInfo := &property.StatsInfo{RowCount: float64(len(patternInExpr.List))} var partitionExpr *tables.PartitionExpr if tbl.GetPartitionInfo() != nil { @@ -593,16 +594,8 @@ func newBatchPointGetPlan( if d.IsNull() { return nil } - if !checkCanConvertInPointGet(handleCol, d) { - return nil - } - intDatum, err := d.ConvertTo(ctx.GetSessionVars().StmtCtx, &handleCol.FieldType) - if err != nil { - return nil - } - // The converted result must be same as original datum - cmp, err := intDatum.CompareDatum(ctx.GetSessionVars().StmtCtx, &d) - if err != nil || cmp != 0 { + intDatum := getPointGetValue(stmtCtx, handleCol, &d) + if intDatum == nil { return nil } handles[i] = kv.IntHandle(intDatum.GetInt64()) @@ -686,12 +679,14 @@ func newBatchPointGetPlan( permIndex := permutations[index] switch innerX := inner.(type) { case *driver.ValueExpr: - if !checkCanConvertInPointGet(colInfos[index], innerX.Datum) { + dval := getPointGetValue(stmtCtx, colInfos[index], &innerX.Datum) + if dval == nil { return nil } values[permIndex] = innerX.Datum case *driver.ParamMarkerExpr: - if !checkCanConvertInPointGet(colInfos[index], innerX.Datum) { + dval := getPointGetValue(stmtCtx, colInfos[index], &innerX.Datum) + if dval == nil { return nil } values[permIndex] = innerX.Datum @@ -706,18 +701,20 @@ func newBatchPointGetPlan( if len(whereColNames) != 1 { return nil } - if !checkCanConvertInPointGet(colInfos[0], x.Datum) { + dval := getPointGetValue(stmtCtx, colInfos[0], &x.Datum) + if dval == nil { return nil } - values = []types.Datum{x.Datum} + values = []types.Datum{*dval} case *driver.ParamMarkerExpr: if len(whereColNames) != 1 { return nil } - if !checkCanConvertInPointGet(colInfos[0], x.Datum) { + dval := getPointGetValue(stmtCtx, colInfos[0], &x.Datum) + if dval == nil { return nil } - values = []types.Datum{x.Datum} + values = []types.Datum{*dval} valuesParams = []*driver.ParamMarkerExpr{x} default: return nil @@ -1229,6 +1226,23 @@ func getNameValuePairs(stmtCtx *stmtctx.StatementContext, tbl *model.TableInfo, return nil, false } +func getPointGetValue(stmtCtx *stmtctx.StatementContext, col *model.ColumnInfo, d *types.Datum) *types.Datum { + if !checkCanConvertInPointGet(col, *d) { + return nil + } + dVal, err := d.ConvertTo(stmtCtx, &col.FieldType) + if err != nil { + return nil + } + // The converted result must be same as original datum. + // Compare them based on the dVal's type. + cmp, err := dVal.CompareDatum(stmtCtx, d) + if err != nil || cmp != 0 { + return nil + } + return &dVal +} + func checkCanConvertInPointGet(col *model.ColumnInfo, d types.Datum) bool { kind := d.Kind() switch col.FieldType.EvalType() { diff --git a/planner/core/point_get_plan_test.go b/planner/core/point_get_plan_test.go index 9d426ed719cfc..300370b60dee6 100644 --- a/planner/core/point_get_plan_test.go +++ b/planner/core/point_get_plan_test.go @@ -899,6 +899,36 @@ func (s *testPointGetSuite) TestIssue18042(c *C) { tk.MustExec("drop table t") } +func (s *testPointGetSuite) TestIssue26638(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a float, unique index uidx(a));") + tk.MustExec("insert into t values(9.46347e37), (1.1);") + // If we do not define the precision for the float type. We can not use the equal/ in conditions to find the result. We can only use like to find the result. There is no such restriction for the double type. + tk.MustQuery("explain format='brief' select * from t where a = 9.46347e37;").Check(testkit.Rows("TableDual 0.00 root rows:0")) + tk.MustQuery("explain format='brief' select * from t where a in (-1.56018e38, -1.96716e38, 9.46347e37);").Check(testkit.Rows("TableDual 0.00 root rows:0")) + tk.MustQuery("explain format='brief' select * from t where a in (1.1, 9.46347e37);").Check(testkit.Rows("TableDual 0.00 root rows:0")) + tk.MustExec("prepare stmt from 'select * from t where a in (?, ?, ?);';") + tk.MustExec("prepare stmt1 from 'select * from t where a = ?;';") + tk.MustExec("prepare stmt2 from 'select * from t where a in (?, ?);';") + tk.MustExec("set @a=-1.56018e38, @b=-1.96716e38, @c=9.46347e37, @d=1.1, @e=0, @f=-1, @g=1, @h=2, @i=-1.1;") + tk.MustQuery("execute stmt using @a,@b,@c;").Check(testkit.Rows()) + tk.MustQuery("execute stmt1 using @c;").Check(testkit.Rows()) + tk.MustQuery("execute stmt2 using @c, @d;").Check(testkit.Rows()) + tk.MustExec("drop table if exists t2;") + tk.MustExec("create table t2(a float, b float, c float, primary key(a, b, c));") + tk.MustExec("insert into t2 values(-1, 0, 1), (-1.1, 0, 1.1), (-1.56018e38, -1.96716e38, 9.46347e37), (0, 1, 2);") + tk.MustQuery("explain format='brief' select * from t2 where (a, b, c) in ((-1.1, 0, 1.1), (-1.56018e38, -1.96716e38, 9.46347e37));").Check(testkit.Rows("TableDual 0.00 root rows:0")) + tk.MustQuery("select * from t2 where (a, b, c) in ((-1.1, 0, 1.1), (-1.56018e38, -1.96716e38, 9.46347e37), (-1, 0, 1));").Check(testkit.Rows("-1 0 1")) + tk.MustQuery("select * from t2 where (a, b, c) in ((-1.1, 0, 1.1), (-1.56018e38, -1.96716e38, 9.46347e37), (0, 1, 2));").Check(testkit.Rows("0 1 2")) + tk.MustExec("prepare stmt3 from 'select * from t2 where (a, b, c) in ((?, ?, ?), (?, ?, ?));';") + tk.MustExec("prepare stmt4 from 'select * from t2 where (a, b, c) in ((?, ?, ?), (?, ?, ?), (?, ?, ?));';") + tk.MustQuery("execute stmt3 using @i,@e,@d,@a,@b,@c;").Check(testkit.Rows()) + tk.MustQuery("execute stmt4 using @i,@e,@d,@a,@b,@c,@f,@e,@g;").Check(testkit.Rows("-1 0 1")) + tk.MustQuery("execute stmt4 using @i,@e,@d,@a,@b,@c,@e,@g,@h;").Check(testkit.Rows("0 1 2")) +} + func (s *testPointGetSuite) TestIssue23511(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test")