From 7c7b2a601819c6d65b7c6b92194c2773dba4247a Mon Sep 17 00:00:00 2001 From: Ziqian Qin Date: Tue, 15 Feb 2022 14:31:38 +0800 Subject: [PATCH 1/3] cherry pick #32308 to release-5.2 Signed-off-by: ti-srebot --- executor/executor_test.go | 345 ++++++++++++++++++++++++++++++++++++++ util/codec/codec.go | 4 +- 2 files changed, 347 insertions(+), 2 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index 1edabe0d76b3f..3fab6158b02e6 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -9066,3 +9066,348 @@ func (s *testSerialSuite) TestIssue28650(c *C) { }() } } +<<<<<<< HEAD +======= + +func (s *testSerialSuite) TestIssue30289(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + fpName := "github.com/pingcap/tidb/executor/issue30289" + c.Assert(failpoint.Enable(fpName, `return(true)`), IsNil) + defer func() { + c.Assert(failpoint.Disable(fpName), IsNil) + }() + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int)") + err := tk.QueryToErr("select /*+ hash_join(t1) */ * from t t1 join t t2 on t1.a=t2.a") + c.Assert(err.Error(), Matches, "issue30289 build return error") +} + +func (s *testSerialSuite) TestIssue29498(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("DROP TABLE IF EXISTS t1;") + tk.MustExec("CREATE TABLE t1 (t3 TIME(3), d DATE, t TIME);") + tk.MustExec("INSERT INTO t1 VALUES ('00:00:00.567', '2002-01-01', '00:00:02');") + + res := tk.MustQuery("SELECT CONCAT(IFNULL(t3, d)) AS col1 FROM t1;") + row := res.Rows()[0][0].(string) + c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) + c.Assert(row[len(row)-12:], Equals, "00:00:00.567") + + res = tk.MustQuery("SELECT IFNULL(t3, d) AS col1 FROM t1;") + row = res.Rows()[0][0].(string) + c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) + c.Assert(row[len(row)-12:], Equals, "00:00:00.567") + + res = tk.MustQuery("SELECT CONCAT(IFNULL(t, d)) AS col1 FROM t1;") + row = res.Rows()[0][0].(string) + c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp) + c.Assert(row[len(row)-8:], Equals, "00:00:02") + + res = tk.MustQuery("SELECT IFNULL(t, d) AS col1 FROM t1;") + row = res.Rows()[0][0].(string) + c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp) + c.Assert(row[len(row)-8:], Equals, "00:00:02") + + res = tk.MustQuery("SELECT CONCAT(xx) FROM (SELECT t3 AS xx FROM t1 UNION SELECT d FROM t1) x ORDER BY -xx LIMIT 1;") + row = res.Rows()[0][0].(string) + c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) + c.Assert(row[len(row)-12:], Equals, "00:00:00.567") + + res = tk.MustQuery("SELECT CONCAT(CASE WHEN d IS NOT NULL THEN t3 ELSE d END) AS col1 FROM t1;") + row = res.Rows()[0][0].(string) + c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) + c.Assert(row[len(row)-12:], Equals, "00:00:00.567") +} + +// Test invoke Close without invoking Open before for each operators. +func (s *testSerialSuite) TestUnreasonablyClose(c *C) { + defer testleak.AfterTest(c)() + + is := infoschema.MockInfoSchema([]*model.TableInfo{plannercore.MockSignedTable(), plannercore.MockUnsignedTable()}) + se, err := session.CreateSession4Test(s.store) + c.Assert(err, IsNil) + _, err = se.Execute(context.Background(), "use test") + c.Assert(err, IsNil) + // To enable the shuffleExec operator. + _, err = se.Execute(context.Background(), "set @@tidb_merge_join_concurrency=4") + c.Assert(err, IsNil) + + var opsNeedsCovered = []plannercore.PhysicalPlan{ + &plannercore.PhysicalHashJoin{}, + &plannercore.PhysicalMergeJoin{}, + &plannercore.PhysicalIndexJoin{}, + &plannercore.PhysicalIndexHashJoin{}, + &plannercore.PhysicalTableReader{}, + &plannercore.PhysicalIndexReader{}, + &plannercore.PhysicalIndexLookUpReader{}, + &plannercore.PhysicalIndexMergeReader{}, + &plannercore.PhysicalApply{}, + &plannercore.PhysicalHashAgg{}, + &plannercore.PhysicalStreamAgg{}, + &plannercore.PhysicalLimit{}, + &plannercore.PhysicalSort{}, + &plannercore.PhysicalTopN{}, + &plannercore.PhysicalCTE{}, + &plannercore.PhysicalCTETable{}, + &plannercore.PhysicalMaxOneRow{}, + &plannercore.PhysicalProjection{}, + &plannercore.PhysicalSelection{}, + &plannercore.PhysicalTableDual{}, + &plannercore.PhysicalWindow{}, + &plannercore.PhysicalShuffle{}, + &plannercore.PhysicalUnionAll{}, + } + executorBuilder := executor.NewMockExecutorBuilderForTest(se, is, nil, math.MaxUint64, false, "global") + + var opsNeedsCoveredMask uint64 = 1< t1.a) AS a from t as t1) t", + "select /*+ hash_agg() */ count(f) from t group by a", + "select /*+ stream_agg() */ count(f) from t group by a", + "select * from t order by a, f", + "select * from t order by a, f limit 1", + "select * from t limit 1", + "select (select t1.a from t t1 where t1.a > t2.a) as a from t t2;", + "select a + 1 from t", + "select count(*) a from t having a > 1", + "select * from t where a = 1.1", + "with recursive cte1(c1) as (select 1 union select c1 + 1 from cte1 limit 5 offset 0) select * from cte1", + "select /*+use_index_merge(t, c_d_e, f)*/ * from t where c < 1 or f > 2", + "select sum(f) over (partition by f) from t", + "select /*+ merge_join(t1)*/ * from t t1 join t t2 on t1.d = t2.d", + "select a from t union all select a from t", + } { + comment := Commentf("case:%v sql:%s", i, tc) + c.Assert(err, IsNil, comment) + stmt, err := s.ParseOneStmt(tc, "", "") + c.Assert(err, IsNil, comment) + + err = se.NewTxn(context.Background()) + c.Assert(err, IsNil, comment) + p, _, err := planner.Optimize(context.TODO(), se, stmt, is) + c.Assert(err, IsNil, comment) + // This for loop level traverses the plan tree to get which operators are covered. + for child := []plannercore.PhysicalPlan{p.(plannercore.PhysicalPlan)}; len(child) != 0; { + newChild := make([]plannercore.PhysicalPlan, 0, len(child)) + for _, ch := range child { + found := false + for k, t := range opsNeedsCovered { + if reflect.TypeOf(t) == reflect.TypeOf(ch) { + opsAlreadyCoveredMask |= 1 << k + found = true + break + } + } + c.Assert(found, IsTrue, Commentf("case: %v sql: %s operator %v is not registered in opsNeedsCoveredMask", i, tc, reflect.TypeOf(ch))) + switch x := ch.(type) { + case *plannercore.PhysicalCTE: + newChild = append(newChild, x.RecurPlan) + newChild = append(newChild, x.SeedPlan) + continue + case *plannercore.PhysicalShuffle: + newChild = append(newChild, x.DataSources...) + newChild = append(newChild, x.Tails...) + continue + } + newChild = append(newChild, ch.Children()...) + } + child = newChild + } + + e := executorBuilder.Build(p) + + func() { + defer func() { + r := recover() + buf := make([]byte, 4096) + stackSize := runtime.Stack(buf, false) + buf = buf[:stackSize] + c.Assert(r, IsNil, Commentf("case: %v\n sql: %s\n error stack: %v", i, tc, string(buf))) + }() + c.Assert(e.Close(), IsNil, comment) + }() + } + // The following code is used to make sure all the operators registered + // in opsNeedsCoveredMask are covered. + commentBuf := strings.Builder{} + if opsAlreadyCoveredMask != opsNeedsCoveredMask { + for i := range opsNeedsCovered { + if opsAlreadyCoveredMask&(1<>>>>>> 886650b58... codec: Don't convert set or enum datum to float64 when encoding them (#32308) diff --git a/util/codec/codec.go b/util/codec/codec.go index 2f9ce666ed643..47e6fa07f10d3 100644 --- a/util/codec/codec.go +++ b/util/codec/codec.go @@ -113,9 +113,9 @@ func encode(sc *stmtctx.StatementContext, b []byte, vals []types.Datum, comparab err = sc.HandleOverflow(err, err) } case types.KindMysqlEnum: - b = encodeUnsignedInt(b, uint64(vals[i].GetMysqlEnum().ToNumber()), comparable) + b = encodeUnsignedInt(b, vals[i].GetMysqlEnum().Value, comparable) case types.KindMysqlSet: - b = encodeUnsignedInt(b, uint64(vals[i].GetMysqlSet().ToNumber()), comparable) + b = encodeUnsignedInt(b, vals[i].GetMysqlSet().Value, comparable) case types.KindMysqlBit, types.KindBinaryLiteral: // We don't need to handle errors here since the literal is ensured to be able to store in uint64 in convertToMysqlBit. var val uint64 From 45772024174a37d84824867142f66db0075a1ca9 Mon Sep 17 00:00:00 2001 From: ekexium Date: Wed, 16 Feb 2022 13:54:27 +0800 Subject: [PATCH 2/3] fix conflict Signed-off-by: ekexium --- executor/executor_test.go | 331 -------------------------------------- 1 file changed, 331 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index 3fab6158b02e6..452543b3beeb6 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -9066,336 +9066,6 @@ func (s *testSerialSuite) TestIssue28650(c *C) { }() } } -<<<<<<< HEAD -======= - -func (s *testSerialSuite) TestIssue30289(c *C) { - tk := testkit.NewTestKit(c, s.store) - tk.MustExec("use test") - fpName := "github.com/pingcap/tidb/executor/issue30289" - c.Assert(failpoint.Enable(fpName, `return(true)`), IsNil) - defer func() { - c.Assert(failpoint.Disable(fpName), IsNil) - }() - tk.MustExec("drop table if exists t") - tk.MustExec("create table t(a int)") - err := tk.QueryToErr("select /*+ hash_join(t1) */ * from t t1 join t t2 on t1.a=t2.a") - c.Assert(err.Error(), Matches, "issue30289 build return error") -} - -func (s *testSerialSuite) TestIssue29498(c *C) { - tk := testkit.NewTestKit(c, s.store) - tk.MustExec("use test") - tk.MustExec("DROP TABLE IF EXISTS t1;") - tk.MustExec("CREATE TABLE t1 (t3 TIME(3), d DATE, t TIME);") - tk.MustExec("INSERT INTO t1 VALUES ('00:00:00.567', '2002-01-01', '00:00:02');") - - res := tk.MustQuery("SELECT CONCAT(IFNULL(t3, d)) AS col1 FROM t1;") - row := res.Rows()[0][0].(string) - c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) - c.Assert(row[len(row)-12:], Equals, "00:00:00.567") - - res = tk.MustQuery("SELECT IFNULL(t3, d) AS col1 FROM t1;") - row = res.Rows()[0][0].(string) - c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) - c.Assert(row[len(row)-12:], Equals, "00:00:00.567") - - res = tk.MustQuery("SELECT CONCAT(IFNULL(t, d)) AS col1 FROM t1;") - row = res.Rows()[0][0].(string) - c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp) - c.Assert(row[len(row)-8:], Equals, "00:00:02") - - res = tk.MustQuery("SELECT IFNULL(t, d) AS col1 FROM t1;") - row = res.Rows()[0][0].(string) - c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp) - c.Assert(row[len(row)-8:], Equals, "00:00:02") - - res = tk.MustQuery("SELECT CONCAT(xx) FROM (SELECT t3 AS xx FROM t1 UNION SELECT d FROM t1) x ORDER BY -xx LIMIT 1;") - row = res.Rows()[0][0].(string) - c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) - c.Assert(row[len(row)-12:], Equals, "00:00:00.567") - - res = tk.MustQuery("SELECT CONCAT(CASE WHEN d IS NOT NULL THEN t3 ELSE d END) AS col1 FROM t1;") - row = res.Rows()[0][0].(string) - c.Assert(len(row), Equals, mysql.MaxDatetimeWidthNoFsp+3+1) - c.Assert(row[len(row)-12:], Equals, "00:00:00.567") -} - -// Test invoke Close without invoking Open before for each operators. -func (s *testSerialSuite) TestUnreasonablyClose(c *C) { - defer testleak.AfterTest(c)() - - is := infoschema.MockInfoSchema([]*model.TableInfo{plannercore.MockSignedTable(), plannercore.MockUnsignedTable()}) - se, err := session.CreateSession4Test(s.store) - c.Assert(err, IsNil) - _, err = se.Execute(context.Background(), "use test") - c.Assert(err, IsNil) - // To enable the shuffleExec operator. - _, err = se.Execute(context.Background(), "set @@tidb_merge_join_concurrency=4") - c.Assert(err, IsNil) - - var opsNeedsCovered = []plannercore.PhysicalPlan{ - &plannercore.PhysicalHashJoin{}, - &plannercore.PhysicalMergeJoin{}, - &plannercore.PhysicalIndexJoin{}, - &plannercore.PhysicalIndexHashJoin{}, - &plannercore.PhysicalTableReader{}, - &plannercore.PhysicalIndexReader{}, - &plannercore.PhysicalIndexLookUpReader{}, - &plannercore.PhysicalIndexMergeReader{}, - &plannercore.PhysicalApply{}, - &plannercore.PhysicalHashAgg{}, - &plannercore.PhysicalStreamAgg{}, - &plannercore.PhysicalLimit{}, - &plannercore.PhysicalSort{}, - &plannercore.PhysicalTopN{}, - &plannercore.PhysicalCTE{}, - &plannercore.PhysicalCTETable{}, - &plannercore.PhysicalMaxOneRow{}, - &plannercore.PhysicalProjection{}, - &plannercore.PhysicalSelection{}, - &plannercore.PhysicalTableDual{}, - &plannercore.PhysicalWindow{}, - &plannercore.PhysicalShuffle{}, - &plannercore.PhysicalUnionAll{}, - } - executorBuilder := executor.NewMockExecutorBuilderForTest(se, is, nil, math.MaxUint64, false, "global") - - var opsNeedsCoveredMask uint64 = 1< t1.a) AS a from t as t1) t", - "select /*+ hash_agg() */ count(f) from t group by a", - "select /*+ stream_agg() */ count(f) from t group by a", - "select * from t order by a, f", - "select * from t order by a, f limit 1", - "select * from t limit 1", - "select (select t1.a from t t1 where t1.a > t2.a) as a from t t2;", - "select a + 1 from t", - "select count(*) a from t having a > 1", - "select * from t where a = 1.1", - "with recursive cte1(c1) as (select 1 union select c1 + 1 from cte1 limit 5 offset 0) select * from cte1", - "select /*+use_index_merge(t, c_d_e, f)*/ * from t where c < 1 or f > 2", - "select sum(f) over (partition by f) from t", - "select /*+ merge_join(t1)*/ * from t t1 join t t2 on t1.d = t2.d", - "select a from t union all select a from t", - } { - comment := Commentf("case:%v sql:%s", i, tc) - c.Assert(err, IsNil, comment) - stmt, err := s.ParseOneStmt(tc, "", "") - c.Assert(err, IsNil, comment) - - err = se.NewTxn(context.Background()) - c.Assert(err, IsNil, comment) - p, _, err := planner.Optimize(context.TODO(), se, stmt, is) - c.Assert(err, IsNil, comment) - // This for loop level traverses the plan tree to get which operators are covered. - for child := []plannercore.PhysicalPlan{p.(plannercore.PhysicalPlan)}; len(child) != 0; { - newChild := make([]plannercore.PhysicalPlan, 0, len(child)) - for _, ch := range child { - found := false - for k, t := range opsNeedsCovered { - if reflect.TypeOf(t) == reflect.TypeOf(ch) { - opsAlreadyCoveredMask |= 1 << k - found = true - break - } - } - c.Assert(found, IsTrue, Commentf("case: %v sql: %s operator %v is not registered in opsNeedsCoveredMask", i, tc, reflect.TypeOf(ch))) - switch x := ch.(type) { - case *plannercore.PhysicalCTE: - newChild = append(newChild, x.RecurPlan) - newChild = append(newChild, x.SeedPlan) - continue - case *plannercore.PhysicalShuffle: - newChild = append(newChild, x.DataSources...) - newChild = append(newChild, x.Tails...) - continue - } - newChild = append(newChild, ch.Children()...) - } - child = newChild - } - - e := executorBuilder.Build(p) - - func() { - defer func() { - r := recover() - buf := make([]byte, 4096) - stackSize := runtime.Stack(buf, false) - buf = buf[:stackSize] - c.Assert(r, IsNil, Commentf("case: %v\n sql: %s\n error stack: %v", i, tc, string(buf))) - }() - c.Assert(e.Close(), IsNil, comment) - }() - } - // The following code is used to make sure all the operators registered - // in opsNeedsCoveredMask are covered. - commentBuf := strings.Builder{} - if opsAlreadyCoveredMask != opsNeedsCoveredMask { - for i := range opsNeedsCovered { - if opsAlreadyCoveredMask&(1<>>>>>> 886650b58... codec: Don't convert set or enum datum to float64 when encoding them (#32308) From c8a7f71f31109a4de8f59ac50dc19ad42ce6ad50 Mon Sep 17 00:00:00 2001 From: Ziqian Qin Date: Wed, 23 Feb 2022 16:57:43 +0800 Subject: [PATCH 3/3] cherry pick Signed-off-by: ekexium --- util/codec/codec.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/util/codec/codec.go b/util/codec/codec.go index 47e6fa07f10d3..a3dc563076737 100644 --- a/util/codec/codec.go +++ b/util/codec/codec.go @@ -156,9 +156,9 @@ func EstimateValueSize(sc *stmtctx.StatementContext, val types.Datum) (int, erro case types.KindMysqlDecimal: l = valueSizeOfDecimal(val.GetMysqlDecimal(), val.Length(), val.Frac()) + 1 case types.KindMysqlEnum: - l = valueSizeOfUnsignedInt(uint64(val.GetMysqlEnum().ToNumber())) + l = valueSizeOfUnsignedInt(val.GetMysqlEnum().Value) case types.KindMysqlSet: - l = valueSizeOfUnsignedInt(uint64(val.GetMysqlSet().ToNumber())) + l = valueSizeOfUnsignedInt(val.GetMysqlSet().Value) case types.KindMysqlBit, types.KindBinaryLiteral: val, err := val.GetBinaryLiteral().ToInt(sc) terror.Log(errors.Trace(err)) @@ -352,11 +352,11 @@ func encodeHashChunkRowIdx(sc *stmtctx.StatementContext, row chunk.Row, tp *type case mysql.TypeEnum: if mysql.HasEnumSetAsIntFlag(tp.Flag) { flag = uvarintFlag - v := uint64(row.GetEnum(idx).ToNumber()) + v := row.GetEnum(idx).Value b = (*[sizeUint64]byte)(unsafe.Pointer(&v))[:] } else { flag = compactBytesFlag - v := uint64(row.GetEnum(idx).ToNumber()) + v := row.GetEnum(idx).Value str := "" if enum, err := types.ParseEnumValue(tp.Elems, v); err == nil { // str will be empty string if v out of definition of enum. @@ -566,11 +566,11 @@ func HashChunkSelected(sc *stmtctx.StatementContext, h []hash.Hash64, chk *chunk isNull[i] = !ignoreNull } else if mysql.HasEnumSetAsIntFlag(tp.Flag) { buf[0] = uvarintFlag - v := uint64(column.GetEnum(i).ToNumber()) + v := column.GetEnum(i).Value b = (*[sizeUint64]byte)(unsafe.Pointer(&v))[:] } else { buf[0] = compactBytesFlag - v := uint64(column.GetEnum(i).ToNumber()) + v := column.GetEnum(i).Value str := "" if enum, err := types.ParseEnumValue(tp.Elems, v); err == nil { // str will be empty string if v out of definition of enum.