From b6b3c3557eb3699e38cc46a6a6f2c5fa65de66f3 Mon Sep 17 00:00:00 2001 From: "yulai.li" Date: Wed, 18 Nov 2020 23:15:20 +0800 Subject: [PATCH 1/6] planner: try to fix should not point get condition --- planner/core/point_get_plan.go | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index 77efe8f5d5a67..fc8f38aca903d 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -25,6 +25,7 @@ import ( "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/opcode" "github.com/pingcap/parser/terror" + ptypes "github.com/pingcap/parser/types" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/infoschema" "github.com/pingcap/tidb/kv" @@ -517,6 +518,9 @@ func newBatchPointGetPlan( if d.IsNull() { return nil } + if !checkCanUseConvertTo(handleCol, d) { + return nil + } intDatum, err := d.ConvertTo(ctx.GetSessionVars().StmtCtx, &handleCol.FieldType) if err != nil { return nil @@ -539,6 +543,14 @@ func newBatchPointGetPlan( // The columns in where clause should be covered by unique index var matchIdxInfo *model.IndexInfo permutations := make([]int, len(whereColNames)) + colInfos := make([]*model.ColumnInfo, len(whereColNames)) + for i, innerCol := range whereColNames { + for _, col := range tbl.Columns { + if col.Name.L == innerCol { + colInfos[i] = col + } + } + } for _, idxInfo := range tbl.Indices { if !idxInfo.Unique || idxInfo.State != model.StatePublic || idxInfo.Invisible { continue @@ -591,8 +603,14 @@ func newBatchPointGetPlan( permIndex := permutations[index] switch innerX := inner.(type) { case *driver.ValueExpr: + if !checkCanUseConvertTo(colInfos[index], innerX.Datum) { + return nil + } values[permIndex] = innerX.Datum case *driver.ParamMarkerExpr: + if !checkCanUseConvertTo(colInfos[index], innerX.Datum) { + return nil + } values[permIndex] = innerX.Datum valuesParams[permIndex] = innerX default: @@ -600,8 +618,14 @@ func newBatchPointGetPlan( } } case *driver.ValueExpr: + if !checkCanUseConvertTo(colInfos[0], x.Datum) { + return nil + } values = []types.Datum{x.Datum} case *driver.ParamMarkerExpr: + if !checkCanUseConvertTo(colInfos[0], x.Datum) { + return nil + } values = []types.Datum{x.Datum} valuesParams = []*driver.ParamMarkerExpr{x} default: @@ -1016,6 +1040,9 @@ func getNameValuePairs(stmtCtx *stmtctx.StatementContext, tbl *model.TableInfo, (col.Tp == mysql.TypeString && col.Collate == charset.CollationBin) { // This type we needn't to pad `\0` in here. return append(nvPairs, nameValuePair{colName: colName.Name.Name.L, value: d, param: param}), false } + if !checkCanUseConvertTo(col, d) { + return nil, false + } dVal, err := d.ConvertTo(stmtCtx, &col.FieldType) if err != nil { if terror.ErrorEqual(types.ErrOverflow, err) { @@ -1039,6 +1066,19 @@ func getNameValuePairs(stmtCtx *stmtctx.StatementContext, tbl *model.TableInfo, return nil, false } +func checkCanUseConvertTo(col *model.ColumnInfo, d types.Datum) bool { + dKind := d.Kind() + switch col.FieldType.EvalType() { + case ptypes.ETString: + switch dKind { + case types.KindInt64, types.KindUint64: + // column type is String and constant type is int or uint + return false + } + } + return true +} + func findPKHandle(tblInfo *model.TableInfo, pairs []nameValuePair) (handlePair nameValuePair, fieldType *types.FieldType) { if !tblInfo.PKIsHandle { rowIDIdx := findInPairs("_tidb_rowid", pairs) From e332717843b37e6fc4bee15534f40c978b21030c Mon Sep 17 00:00:00 2001 From: "yulai.li" Date: Wed, 18 Nov 2020 23:34:56 +0800 Subject: [PATCH 2/6] planner: fix missing decimal type --- planner/core/point_get_plan.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index fc8f38aca903d..cae95fefa4703 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -1074,6 +1074,9 @@ func checkCanUseConvertTo(col *model.ColumnInfo, d types.Datum) bool { case types.KindInt64, types.KindUint64: // column type is String and constant type is int or uint return false + case types.KindFloat32, types.KindFloat64, types.KindMysqlDecimal: + // column type is String and constant type is float or double + return false } } return true From 1d6733ecc3359e8738fc35415c798b0ed090915b Mon Sep 17 00:00:00 2001 From: "yulai.li" Date: Thu, 19 Nov 2020 11:56:36 +0800 Subject: [PATCH 3/6] planner: refactor and add test cases --- planner/core/point_get_plan.go | 26 +++++++-------- planner/core/point_get_plan_test.go | 52 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index cae95fefa4703..4af0eaee27159 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -518,7 +518,7 @@ func newBatchPointGetPlan( if d.IsNull() { return nil } - if !checkCanUseConvertTo(handleCol, d) { + if !checkCanConvertInPointGet(handleCol, d) { return nil } intDatum, err := d.ConvertTo(ctx.GetSessionVars().StmtCtx, &handleCol.FieldType) @@ -603,12 +603,12 @@ func newBatchPointGetPlan( permIndex := permutations[index] switch innerX := inner.(type) { case *driver.ValueExpr: - if !checkCanUseConvertTo(colInfos[index], innerX.Datum) { + if !checkCanConvertInPointGet(colInfos[index], innerX.Datum) { return nil } values[permIndex] = innerX.Datum case *driver.ParamMarkerExpr: - if !checkCanUseConvertTo(colInfos[index], innerX.Datum) { + if !checkCanConvertInPointGet(colInfos[index], innerX.Datum) { return nil } values[permIndex] = innerX.Datum @@ -618,12 +618,12 @@ func newBatchPointGetPlan( } } case *driver.ValueExpr: - if !checkCanUseConvertTo(colInfos[0], x.Datum) { + if !checkCanConvertInPointGet(colInfos[0], x.Datum) { return nil } values = []types.Datum{x.Datum} case *driver.ParamMarkerExpr: - if !checkCanUseConvertTo(colInfos[0], x.Datum) { + if !checkCanConvertInPointGet(colInfos[0], x.Datum) { return nil } values = []types.Datum{x.Datum} @@ -1040,7 +1040,7 @@ func getNameValuePairs(stmtCtx *stmtctx.StatementContext, tbl *model.TableInfo, (col.Tp == mysql.TypeString && col.Collate == charset.CollationBin) { // This type we needn't to pad `\0` in here. return append(nvPairs, nameValuePair{colName: colName.Name.Name.L, value: d, param: param}), false } - if !checkCanUseConvertTo(col, d) { + if !checkCanConvertInPointGet(col, d) { return nil, false } dVal, err := d.ConvertTo(stmtCtx, &col.FieldType) @@ -1066,16 +1066,14 @@ func getNameValuePairs(stmtCtx *stmtctx.StatementContext, tbl *model.TableInfo, return nil, false } -func checkCanUseConvertTo(col *model.ColumnInfo, d types.Datum) bool { - dKind := d.Kind() +func checkCanConvertInPointGet(col *model.ColumnInfo, d types.Datum) bool { + kind := d.Kind() switch col.FieldType.EvalType() { case ptypes.ETString: - switch dKind { - case types.KindInt64, types.KindUint64: - // column type is String and constant type is int or uint - return false - case types.KindFloat32, types.KindFloat64, types.KindMysqlDecimal: - // column type is String and constant type is float or double + switch kind { + case types.KindInt64, types.KindUint64, + types.KindFloat32, types.KindFloat64, types.KindMysqlDecimal: + // column type is String and constant type is numeric return false } } diff --git a/planner/core/point_get_plan_test.go b/planner/core/point_get_plan_test.go index 91c2ff0c5cc5a..46976d8febf98 100644 --- a/planner/core/point_get_plan_test.go +++ b/planner/core/point_get_plan_test.go @@ -562,3 +562,55 @@ func (s *testPointGetSuite) TestBatchPointGetWithInvisibleIndex(c *C) { " └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", )) } + +func (s *testPointGetSuite) TestShouldNotUsePointGetWithCharColumn(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop tables if exists t1, t2, t3, t4") + tk.MustExec("create table t1(id varchar(20) primary key)") + tk.MustExec("create table t2(id varchar(20), unique(id))") + tk.MustExec("create table t3(id varchar(20), d varchar(20), unique(id, d))") + tk.MustExec("create table t4(id int, d varchar(20), c varchar(20), unique(id, d))") + + tk.MustQuery("explain select * from t1 where id = 0").Check(testkit.Rows( + "TableReader_7 8000.00 root data:Selection_6", + "└─Selection_6 8000.00 cop[tikv] eq(cast(test.t1.id), 0)", + " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + )) + tk.MustQuery("explain select * from t1 where id in (0, 1)").Check(testkit.Rows( + "TableReader_7 9600.00 root data:Selection_6", + "└─Selection_6 9600.00 cop[tikv] or(eq(cast(test.t1.id), 0), eq(cast(test.t1.id), 1))", + " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + )) + + tk.MustQuery("explain select * from t2 where id = 0").Check(testkit.Rows( + "IndexReader_10 8000.00 root index:Selection_9", + "└─Selection_9 8000.00 cop[tikv] eq(cast(test.t2.id), 0)", + " └─IndexFullScan_8 10000.00 cop[tikv] table:t2, index:id(id) keep order:false, stats:pseudo", + )) + + tk.MustQuery("explain select * from t2 where id in (0, 1)").Check(testkit.Rows( + "IndexReader_10 9600.00 root index:Selection_9", + "└─Selection_9 9600.00 cop[tikv] or(eq(cast(test.t2.id), 0), eq(cast(test.t2.id), 1))", + " └─IndexFullScan_8 10000.00 cop[tikv] table:t2, index:id(id) keep order:false, stats:pseudo", + )) + + tk.MustQuery("explain select * from t3 where (id, d) in ((0, 't'), (1, 't'))").Check(testkit.Rows( + "IndexReader_10 15.99 root index:Selection_9", + "└─Selection_9 15.99 cop[tikv] or(and(eq(cast(test.t3.id), 0), eq(test.t3.d, \"t\")), and(eq(cast(test.t3.id), 1), eq(test.t3.d, \"t\")))", + " └─IndexFullScan_8 10000.00 cop[tikv] table:t3, index:id(id, d) keep order:false, stats:pseudo", + )) + + tk.MustQuery("explain select * from t4 where (id, d, c) in ((1, 'b', 0))").Check(testkit.Rows( + "Selection_6 0.80 root eq(cast(test.t4.c), 0)", + "└─Point_Get_5 1.00 root table:t4, index:id(id, d) ", + )) + + tk.MustQuery("explain select * from t4 where (id, d, c) in ((1, 0, 0))").Check(testkit.Rows( + "IndexLookUp_12 8.00 root ", + "├─Selection_10(Build) 8.00 cop[tikv] eq(cast(test.t4.d), 0)", + "│ └─IndexRangeScan_8 10.00 cop[tikv] table:t4, index:id(id, d) range:[1,1], keep order:false, stats:pseudo", + "└─Selection_11(Probe) 8.00 cop[tikv] eq(cast(test.t4.c), 0)", + " └─TableRowIDScan_9 8.00 cop[tikv] table:t4 keep order:false, stats:pseudo", + )) +} From 2b032c8af205215e902c74d4e94e33396954f21b Mon Sep 17 00:00:00 2001 From: "yulai.li" Date: Fri, 20 Nov 2020 12:48:46 +0800 Subject: [PATCH 4/6] planner: Refactor unit test and add more cases --- planner/core/point_get_plan_test.go | 66 ++++------ planner/core/testdata/point_get_plan_in.json | 16 +++ planner/core/testdata/point_get_plan_out.json | 123 ++++++++++++++++++ 3 files changed, 163 insertions(+), 42 deletions(-) diff --git a/planner/core/point_get_plan_test.go b/planner/core/point_get_plan_test.go index 46976d8febf98..c086278e531d6 100644 --- a/planner/core/point_get_plan_test.go +++ b/planner/core/point_get_plan_test.go @@ -458,6 +458,7 @@ func (s *testPointGetSuite) TestIssue19141(c *C) { func (s *testPointGetSuite) TestSelectInMultiColumns(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") + tk.MustExec("drop table if exists t2") tk.MustExec("create table t2(a int, b int, c int, primary key(a, b, c));") tk.MustExec("insert into t2 values (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)") tk.MustQuery("select * from t2 where (a, b, c) in ((1, 1, 1));").Check(testkit.Rows("1 1 1")) @@ -563,7 +564,7 @@ func (s *testPointGetSuite) TestBatchPointGetWithInvisibleIndex(c *C) { )) } -func (s *testPointGetSuite) TestShouldNotUsePointGetWithCharColumn(c *C) { +func (s *testPointGetSuite) TestCBOShouldNotUsePointGet(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") tk.MustExec("drop tables if exists t1, t2, t3, t4") @@ -571,46 +572,27 @@ func (s *testPointGetSuite) TestShouldNotUsePointGetWithCharColumn(c *C) { tk.MustExec("create table t2(id varchar(20), unique(id))") tk.MustExec("create table t3(id varchar(20), d varchar(20), unique(id, d))") tk.MustExec("create table t4(id int, d varchar(20), c varchar(20), unique(id, d))") + tk.MustExec("insert into t1 values('asdf'), ('1asdf')") + tk.MustExec("insert into t2 values('asdf'), ('1asdf')") + tk.MustExec("insert into t3 values('asdf', 't'), ('1asdf', 't')") + tk.MustExec("insert into t4 values(1, 'b', 'asdf'), (1, 'c', 'jkl'), (1, 'd', '1jkl')") - tk.MustQuery("explain select * from t1 where id = 0").Check(testkit.Rows( - "TableReader_7 8000.00 root data:Selection_6", - "└─Selection_6 8000.00 cop[tikv] eq(cast(test.t1.id), 0)", - " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - )) - tk.MustQuery("explain select * from t1 where id in (0, 1)").Check(testkit.Rows( - "TableReader_7 9600.00 root data:Selection_6", - "└─Selection_6 9600.00 cop[tikv] or(eq(cast(test.t1.id), 0), eq(cast(test.t1.id), 1))", - " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", - )) - - tk.MustQuery("explain select * from t2 where id = 0").Check(testkit.Rows( - "IndexReader_10 8000.00 root index:Selection_9", - "└─Selection_9 8000.00 cop[tikv] eq(cast(test.t2.id), 0)", - " └─IndexFullScan_8 10000.00 cop[tikv] table:t2, index:id(id) keep order:false, stats:pseudo", - )) - - tk.MustQuery("explain select * from t2 where id in (0, 1)").Check(testkit.Rows( - "IndexReader_10 9600.00 root index:Selection_9", - "└─Selection_9 9600.00 cop[tikv] or(eq(cast(test.t2.id), 0), eq(cast(test.t2.id), 1))", - " └─IndexFullScan_8 10000.00 cop[tikv] table:t2, index:id(id) keep order:false, stats:pseudo", - )) - - tk.MustQuery("explain select * from t3 where (id, d) in ((0, 't'), (1, 't'))").Check(testkit.Rows( - "IndexReader_10 15.99 root index:Selection_9", - "└─Selection_9 15.99 cop[tikv] or(and(eq(cast(test.t3.id), 0), eq(test.t3.d, \"t\")), and(eq(cast(test.t3.id), 1), eq(test.t3.d, \"t\")))", - " └─IndexFullScan_8 10000.00 cop[tikv] table:t3, index:id(id, d) keep order:false, stats:pseudo", - )) - - tk.MustQuery("explain select * from t4 where (id, d, c) in ((1, 'b', 0))").Check(testkit.Rows( - "Selection_6 0.80 root eq(cast(test.t4.c), 0)", - "└─Point_Get_5 1.00 root table:t4, index:id(id, d) ", - )) - - tk.MustQuery("explain select * from t4 where (id, d, c) in ((1, 0, 0))").Check(testkit.Rows( - "IndexLookUp_12 8.00 root ", - "├─Selection_10(Build) 8.00 cop[tikv] eq(cast(test.t4.d), 0)", - "│ └─IndexRangeScan_8 10.00 cop[tikv] table:t4, index:id(id, d) range:[1,1], keep order:false, stats:pseudo", - "└─Selection_11(Probe) 8.00 cop[tikv] eq(cast(test.t4.c), 0)", - " └─TableRowIDScan_9 8.00 cop[tikv] table:t4 keep order:false, stats:pseudo", - )) + var input []string + var output []struct { + SQL string + Plan []string + Res []string + } + s.testData.GetTestCases(c, &input, &output) + for i, sql := range input { + plan := tk.MustQuery("explain " + sql) + res := tk.MustQuery(sql) + s.testData.OnRecord(func() { + output[i].SQL = sql + output[i].Plan = s.testData.ConvertRowsToStrings(plan.Rows()) + output[i].Res = s.testData.ConvertRowsToStrings(res.Rows()) + }) + plan.Check(testkit.Rows(output[i].Plan...)) + res.Check(testkit.Rows(output[i].Res...)) + } } diff --git a/planner/core/testdata/point_get_plan_in.json b/planner/core/testdata/point_get_plan_in.json index 44fa5efa4eacd..a93ac7511d5fe 100644 --- a/planner/core/testdata/point_get_plan_in.json +++ b/planner/core/testdata/point_get_plan_in.json @@ -9,5 +9,21 @@ "select * from t t1 join t t2 on t1.a = t2.a where t1.a = '4' and (t2.b, t2.c) in ((1,1),(2,2))", "select * from t where (t.b, t.c) in ((2,2), (3,3), (4,4)) order by t.b, t.c" ] + }, + { + "name": "TestCBOShouldNotUsePointGet", + "cases": [ + "select * from t1 where id = 0", + "select * from t1 where id = x'00'", + "select * from t1 where id = b'00'", + "select * from t1 where id = 0.0", + "select * from t1 where id = 1.0", + "select * from t1 where id in (0, 1)", + "select * from t2 where id = 0", + "select * from t2 where id in (0, 1)", + "select * from t3 where (id, d) in ((0, 't'), (1, 't'))", + "select * from t4 where (id, d, c) in ((1, 'b', 0))", + "select * from t4 where (id, d, c) in ((1, 0, 0))" + ] } ] diff --git a/planner/core/testdata/point_get_plan_out.json b/planner/core/testdata/point_get_plan_out.json index 5b9349a05e984..6c4ae24bc1a46 100644 --- a/planner/core/testdata/point_get_plan_out.json +++ b/planner/core/testdata/point_get_plan_out.json @@ -67,5 +67,128 @@ ] } ] + }, + { + "Name": "TestCBOShouldNotUsePointGet", + "Cases": [ + { + "SQL": "select * from t1 where id = 0", + "Plan": [ + "TableReader_7 8000.00 root data:Selection_6", + "└─Selection_6 8000.00 cop[tikv] eq(cast(test.t1.id), 0)", + " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" + ], + "Res": [ + "asdf" + ] + }, + { + "SQL": "select * from t1 where id = x'00'", + "Plan": [ + "Point_Get_1 1.00 root table:t1, clustered index:PRIMARY(id) " + ], + "Res": [] + }, + { + "SQL": "select * from t1 where id = b'00'", + "Plan": [ + "Point_Get_1 1.00 root table:t1, clustered index:PRIMARY(id) " + ], + "Res": [] + }, + { + "SQL": "select * from t1 where id = 0.0", + "Plan": [ + "TableReader_7 8000.00 root data:Selection_6", + "└─Selection_6 8000.00 cop[tikv] eq(cast(test.t1.id), 0)", + " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" + ], + "Res": [ + "asdf" + ] + }, + { + "SQL": "select * from t1 where id = 1.0", + "Plan": [ + "TableReader_7 8000.00 root data:Selection_6", + "└─Selection_6 8000.00 cop[tikv] eq(cast(test.t1.id), 1)", + " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" + ], + "Res": [ + "1asdf" + ] + }, + { + "SQL": "select * from t1 where id in (0, 1)", + "Plan": [ + "TableReader_7 9600.00 root data:Selection_6", + "└─Selection_6 9600.00 cop[tikv] or(eq(cast(test.t1.id), 0), eq(cast(test.t1.id), 1))", + " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" + ], + "Res": [ + "1asdf", + "asdf" + ] + }, + { + "SQL": "select * from t2 where id = 0", + "Plan": [ + "IndexReader_10 8000.00 root index:Selection_9", + "└─Selection_9 8000.00 cop[tikv] eq(cast(test.t2.id), 0)", + " └─IndexFullScan_8 10000.00 cop[tikv] table:t2, index:id(id) keep order:false, stats:pseudo" + ], + "Res": [ + "asdf" + ] + }, + { + "SQL": "select * from t2 where id in (0, 1)", + "Plan": [ + "IndexReader_10 9600.00 root index:Selection_9", + "└─Selection_9 9600.00 cop[tikv] or(eq(cast(test.t2.id), 0), eq(cast(test.t2.id), 1))", + " └─IndexFullScan_8 10000.00 cop[tikv] table:t2, index:id(id) keep order:false, stats:pseudo" + ], + "Res": [ + "1asdf", + "asdf" + ] + }, + { + "SQL": "select * from t3 where (id, d) in ((0, 't'), (1, 't'))", + "Plan": [ + "IndexReader_10 15.99 root index:Selection_9", + "└─Selection_9 15.99 cop[tikv] or(and(eq(cast(test.t3.id), 0), eq(test.t3.d, \"t\")), and(eq(cast(test.t3.id), 1), eq(test.t3.d, \"t\")))", + " └─IndexFullScan_8 10000.00 cop[tikv] table:t3, index:id(id, d) keep order:false, stats:pseudo" + ], + "Res": [ + "1asdf t", + "asdf t" + ] + }, + { + "SQL": "select * from t4 where (id, d, c) in ((1, 'b', 0))", + "Plan": [ + "Selection_6 0.80 root eq(cast(test.t4.c), 0)", + "└─Point_Get_5 1.00 root table:t4, index:id(id, d) " + ], + "Res": [ + "1 b asdf" + ] + }, + { + "SQL": "select * from t4 where (id, d, c) in ((1, 0, 0))", + "Plan": [ + "IndexLookUp_12 8.00 root ", + "├─Selection_10(Build) 8.00 cop[tikv] eq(cast(test.t4.d), 0)", + "│ └─IndexRangeScan_8 10.00 cop[tikv] table:t4, index:id(id, d) range:[1,1], keep order:false, stats:pseudo", + "└─Selection_11(Probe) 8.00 cop[tikv] eq(cast(test.t4.c), 0)", + " └─TableRowIDScan_9 8.00 cop[tikv] table:t4 keep order:false, stats:pseudo" + ], + "Res": [ + "1 b asdf", + "1 c jkl" + ] + } + ] } ] From 7b1075e757efd891ae71c419528d2b622d0a1048 Mon Sep 17 00:00:00 2001 From: "yulai.li" Date: Mon, 23 Nov 2020 18:05:10 +0800 Subject: [PATCH 5/6] planner: fix bit column compare with string --- planner/core/point_get_plan.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index 944821616010b..92de0d683705f 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -1078,6 +1078,14 @@ func checkCanConvertInPointGet(col *model.ColumnInfo, d types.Datum) bool { return false } } + switch col.FieldType.Tp { + case mysql.TypeBit: + switch kind { + case types.KindString: + // column type is Bit and constant type is string + return false + } + } return true } From b93ccab01af118632edf0ee7fdfaaf0c76c9a985 Mon Sep 17 00:00:00 2001 From: "yulai.li" Date: Mon, 23 Nov 2020 18:38:53 +0800 Subject: [PATCH 6/6] planner: add test case for bit column compare string --- planner/core/point_get_plan_test.go | 4 +++- planner/core/testdata/point_get_plan_in.json | 3 ++- planner/core/testdata/point_get_plan_out.json | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/planner/core/point_get_plan_test.go b/planner/core/point_get_plan_test.go index c086278e531d6..d763548914fd4 100644 --- a/planner/core/point_get_plan_test.go +++ b/planner/core/point_get_plan_test.go @@ -567,15 +567,17 @@ func (s *testPointGetSuite) TestBatchPointGetWithInvisibleIndex(c *C) { func (s *testPointGetSuite) TestCBOShouldNotUsePointGet(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") - tk.MustExec("drop tables if exists t1, t2, t3, t4") + tk.MustExec("drop tables if exists t1, t2, t3, t4, t5") tk.MustExec("create table t1(id varchar(20) primary key)") tk.MustExec("create table t2(id varchar(20), unique(id))") tk.MustExec("create table t3(id varchar(20), d varchar(20), unique(id, d))") tk.MustExec("create table t4(id int, d varchar(20), c varchar(20), unique(id, d))") + tk.MustExec("create table t5(id bit(64) primary key)") tk.MustExec("insert into t1 values('asdf'), ('1asdf')") tk.MustExec("insert into t2 values('asdf'), ('1asdf')") tk.MustExec("insert into t3 values('asdf', 't'), ('1asdf', 't')") tk.MustExec("insert into t4 values(1, 'b', 'asdf'), (1, 'c', 'jkl'), (1, 'd', '1jkl')") + tk.MustExec("insert into t5 values(48)") var input []string var output []struct { diff --git a/planner/core/testdata/point_get_plan_in.json b/planner/core/testdata/point_get_plan_in.json index a93ac7511d5fe..5b8e22abeb8c5 100644 --- a/planner/core/testdata/point_get_plan_in.json +++ b/planner/core/testdata/point_get_plan_in.json @@ -23,7 +23,8 @@ "select * from t2 where id in (0, 1)", "select * from t3 where (id, d) in ((0, 't'), (1, 't'))", "select * from t4 where (id, d, c) in ((1, 'b', 0))", - "select * from t4 where (id, d, c) in ((1, 0, 0))" + "select * from t4 where (id, d, c) in ((1, 0, 0))", + "select * from t5 where id in ('0')" ] } ] diff --git a/planner/core/testdata/point_get_plan_out.json b/planner/core/testdata/point_get_plan_out.json index 6c4ae24bc1a46..56ae32459f5db 100644 --- a/planner/core/testdata/point_get_plan_out.json +++ b/planner/core/testdata/point_get_plan_out.json @@ -188,6 +188,15 @@ "1 b asdf", "1 c jkl" ] + }, + { + "SQL": "select * from t5 where id in ('0')", + "Plan": [ + "Selection_5 8000.00 root eq(test.t5.id, 0)", + "└─TableReader_7 10000.00 root data:TableFullScan_6", + " └─TableFullScan_6 10000.00 cop[tikv] table:t5 keep order:false, stats:pseudo" + ], + "Res": [] } ] }