From d5f648f126e0b0e227d216f4ecf6285ed269f1d8 Mon Sep 17 00:00:00 2001 From: guo-shaoge Date: Mon, 14 Mar 2022 11:32:50 +0800 Subject: [PATCH 1/3] executor: fix wrong result of delete multiple tables using left join Signed-off-by: guo-shaoge --- executor/delete.go | 3 +++ executor/executor_test.go | 29 +++++++++++++++++++++++++++++ executor/update.go | 4 ++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/executor/delete.go b/executor/delete.go index c859b41a83c75..c327236ee0f18 100644 --- a/executor/delete.go +++ b/executor/delete.go @@ -159,6 +159,9 @@ func (e *DeleteExec) doBatchDelete(ctx context.Context) error { func (e *DeleteExec) composeTblRowMap(tblRowMap tableRowMapType, colPosInfos []plannercore.TblColPosInfo, joinedRow []types.Datum) error { // iterate all the joined tables, and got the copresonding rows in joinedRow. for _, info := range colPosInfos { + if unmatchedOuterRow(info, joinedRow) { + continue + } if tblRowMap[info.TblID] == nil { tblRowMap[info.TblID] = kv.NewHandleMap() } diff --git a/executor/executor_test.go b/executor/executor_test.go index 2c61049d0eda8..bbb4b04a9bce7 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -8521,3 +8521,32 @@ func (s *testSuite1) TestBitColumnIn(c *C) { tk.MustExec("insert into t values (65)") tk.MustQuery("select * from t where id not in (-1,2)").Check(testkit.Rows("\x00A")) } + +func (s *testSuite) TestDeleteWithMulTbl(c *C) { + tk := testkit.NewTestKit(c, s.store) + + // Delete multiple tables from left joined table. + // The result of left join is (3, null, null). + // Because rows in t2 are not matched, so no row will be deleted in t2. + // But row in t1 is matched, so row is deleted. + tk.MustExec("use test;") + tk.MustExec("drop table if exists t1, t2;") + tk.MustExec("create table t1 (c1 int);") + tk.MustExec("create table t2 (c1 int primary key, c2 int);") + tk.MustExec("insert into t1 values(3);") + tk.MustExec("insert into t2 values(2, 2);") + tk.MustExec("insert into t2 values(0, 0);") + tk.MustExec("delete from t1, t2 using t1 left join t2 t1.c1 = t2.c2;") + tk.MustQuery("select * from t1 order by c1;").Check(testkit.Rows()) + tk.MustQuery("select * from t2 order by c1;").Check(testkit.Rows("0 0", "2 2")) + + // The null values are not generated by join. + tk.MustExec("drop table if exists t1, t2;") + tk.MustExec("create table t1 (c1 int);") + tk.MustExec("create table t2 (c2 int);") + tk.MustExec("insert into t1 values(null);") + tk.MustExec("insert into t2 values(null);") + tk.MustExec("delete from t1, t2 using t1 join t2 where t1.c1 is null;") + tk.MustQuery("select * from t1;").Check(testkit.Rows("")) + tk.MustQuery("select * from t2;").Check(testkit.Rows("")) +} diff --git a/executor/update.go b/executor/update.go index 7173897757fc2..ed5c76f44c278 100644 --- a/executor/update.go +++ b/executor/update.go @@ -96,7 +96,7 @@ func (e *UpdateExec) prepare(row []types.Datum) (err error) { break } } - if e.unmatchedOuterRow(content, row) { + if unmatchedOuterRow(content, row) { updatable = false } e.tableUpdatable = append(e.tableUpdatable, updatable) @@ -211,7 +211,7 @@ func (e *UpdateExec) exec(ctx context.Context, schema *expression.Schema, row, n // the inner handle field is filled with a NULL value. // // This fixes: https://github.com/pingcap/tidb/issues/7176. -func (e *UpdateExec) unmatchedOuterRow(tblPos plannercore.TblColPosInfo, waitUpdateRow []types.Datum) bool { +func unmatchedOuterRow(tblPos plannercore.TblColPosInfo, waitUpdateRow []types.Datum) bool { firstHandleIdx := tblPos.HandleCols.GetCol(0) return waitUpdateRow[firstHandleIdx.Index].IsNull() } From e6809cc1b2e1fcf4499301a029808540d6158ed6 Mon Sep 17 00:00:00 2001 From: guo-shaoge Date: Mon, 14 Mar 2022 16:31:22 +0800 Subject: [PATCH 2/3] fix case Signed-off-by: guo-shaoge --- executor/executor_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index bbb4b04a9bce7..04bec76af51f1 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -8536,7 +8536,7 @@ func (s *testSuite) TestDeleteWithMulTbl(c *C) { tk.MustExec("insert into t1 values(3);") tk.MustExec("insert into t2 values(2, 2);") tk.MustExec("insert into t2 values(0, 0);") - tk.MustExec("delete from t1, t2 using t1 left join t2 t1.c1 = t2.c2;") + tk.MustExec("delete from t1, t2 using t1 left join t2 on t1.c1 = t2.c2;") tk.MustQuery("select * from t1 order by c1;").Check(testkit.Rows()) tk.MustQuery("select * from t2 order by c1;").Check(testkit.Rows("0 0", "2 2")) @@ -8547,6 +8547,6 @@ func (s *testSuite) TestDeleteWithMulTbl(c *C) { tk.MustExec("insert into t1 values(null);") tk.MustExec("insert into t2 values(null);") tk.MustExec("delete from t1, t2 using t1 join t2 where t1.c1 is null;") - tk.MustQuery("select * from t1;").Check(testkit.Rows("")) - tk.MustQuery("select * from t2;").Check(testkit.Rows("")) + tk.MustQuery("select * from t1;").Check(testkit.Rows()) + tk.MustQuery("select * from t2;").Check(testkit.Rows()) } From 1835aad43287b935d4498b069eb8f4b41d17f8d2 Mon Sep 17 00:00:00 2001 From: guo-shaoge Date: Mon, 14 Mar 2022 19:44:46 +0800 Subject: [PATCH 3/3] fix comment Signed-off-by: guo-shaoge --- executor/executor_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/executor/executor_test.go b/executor/executor_test.go index 04bec76af51f1..f3d46e60d0169 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -8528,7 +8528,7 @@ func (s *testSuite) TestDeleteWithMulTbl(c *C) { // Delete multiple tables from left joined table. // The result of left join is (3, null, null). // Because rows in t2 are not matched, so no row will be deleted in t2. - // But row in t1 is matched, so row is deleted. + // But row in t1 is matched, so it should be deleted. tk.MustExec("use test;") tk.MustExec("drop table if exists t1, t2;") tk.MustExec("create table t1 (c1 int);") @@ -8540,7 +8540,8 @@ func (s *testSuite) TestDeleteWithMulTbl(c *C) { tk.MustQuery("select * from t1 order by c1;").Check(testkit.Rows()) tk.MustQuery("select * from t2 order by c1;").Check(testkit.Rows("0 0", "2 2")) - // The null values are not generated by join. + // Rows in both t1 and t2 are matched, so will be deleted even if it's null. + // NOTE: The null values are not generated by join. tk.MustExec("drop table if exists t1, t2;") tk.MustExec("create table t1 (c1 int);") tk.MustExec("create table t2 (c2 int);")