diff --git a/executor/write.go b/executor/write.go index e250703ed8141..e4ca1d1f837c3 100644 --- a/executor/write.go +++ b/executor/write.go @@ -193,7 +193,7 @@ func updateRecord(ctx context.Context, sctx sessionctx.Context, h kv.Handle, old if sc.DupKeyAsWarning { // For `UPDATE IGNORE`/`INSERT IGNORE ON DUPLICATE KEY UPDATE` // If the new handle or unique index exists, this will avoid to remove the record. - err = tables.CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore(ctx, sctx, t, newHandle, newData) + err = tables.CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore(ctx, sctx, t, newHandle, newData, modified) if err != nil { if terr, ok := errors.Cause(err).(*terror.Error); sctx.GetSessionVars().StmtCtx.IgnoreNoPartition && ok && terr.Code() == errno.ErrNoPartitionForGivenValue { return false, nil diff --git a/executor/write_test.go b/executor/write_test.go index 199109adcc48a..27ea70ae748a5 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -798,6 +798,14 @@ func (s *testSuite4) TestInsertIgnoreOnDup(c *C) { tk.MustExec("update ignore t5 set k2 = '2', uk1 = 2 where k1 = '1' and k2 = '1'") tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1062 Duplicate entry '2' for key 'ukk1'")) tk.MustQuery("select * from t5").Check(testkit.Rows("1 1 1 100", "1 3 2 200")) + + tk.MustExec("drop table if exists t6") + tk.MustExec("create table t6 (a int, b int, c int, primary key(a, b) clustered, unique key idx_14(b), unique key idx_15(b), unique key idx_16(a, b))") + tk.MustExec("insert into t6 select 10, 10, 20") + tk.MustExec("insert ignore into t6 set a = 20, b = 10 on duplicate key update a = 100") + tk.MustQuery("select * from t6").Check(testkit.Rows("100 10 20")) + tk.MustExec("insert ignore into t6 set a = 200, b= 10 on duplicate key update c = 1000") + tk.MustQuery("select * from t6").Check(testkit.Rows("100 10 1000")) } func (s *testSuite4) TestInsertSetWithDefault(c *C) { diff --git a/table/tables/tables.go b/table/tables/tables.go index c4ceffebacc69..0746f0e6f33e5 100644 --- a/table/tables/tables.go +++ b/table/tables/tables.go @@ -1449,11 +1449,11 @@ func FindIndexByColName(t table.Table, name string) table.Index { // CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore check whether recordID key or unique index key exists. if not exists, return nil, // otherwise return kv.ErrKeyExists error. -func CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore(ctx context.Context, sctx sessionctx.Context, t table.Table, recordID kv.Handle, data []types.Datum) error { +func CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore(ctx context.Context, sctx sessionctx.Context, t table.Table, recordID kv.Handle, newRow []types.Datum, modified []bool) error { physicalTableID := t.Meta().ID if pt, ok := t.(*partitionedTable); ok { info := t.Meta().GetPartitionInfo() - pid, err := pt.locatePartition(sctx, info, data) + pid, err := pt.locatePartition(sctx, info, newRow) if err != nil { return err } @@ -1471,7 +1471,7 @@ func CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore(ctx context.C recordKey := tablecodec.EncodeRecordKey(prefix, recordID) _, err = txn.Get(ctx, recordKey) if err == nil { - handleStr := getDuplicateErrorHandleString(t, recordID, data) + handleStr := getDuplicateErrorHandleString(t, recordID, newRow) return kv.ErrKeyExists.FastGenByArgs(handleStr, "PRIMARY") } else if !kv.ErrNotExist.Equal(err) { return err @@ -1480,18 +1480,27 @@ func CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore(ctx context.C // Check unique key exists. { - for _, idx := range t.Indices() { - if !IsIndexWritable(idx) { - continue + shouldSkipIgnoreCheck := func(idx table.Index) bool { + if !IsIndexWritable(idx) || !idx.Meta().Unique || (t.Meta().IsCommonHandle && idx.Meta().Primary) { + return true + } + for _, c := range idx.Meta().Columns { + if modified[c.Offset] { + return false + } } - if !idx.Meta().Unique { + return true + } + + for _, idx := range t.Indices() { + if shouldSkipIgnoreCheck(idx) { continue } - vals, err := idx.FetchValues(data, nil) + newVals, err := idx.FetchValues(newRow, nil) if err != nil { return err } - key, _, err := idx.GenIndexKey(sctx.GetSessionVars().StmtCtx, vals, recordID, nil) + key, _, err := idx.GenIndexKey(sctx.GetSessionVars().StmtCtx, newVals, recordID, nil) if err != nil { return err } @@ -1502,7 +1511,7 @@ func CheckHandleOrUniqueKeyExistForUpdateIgnoreOrInsertOnDupIgnore(ctx context.C if err != nil { return err } - entryKey, err := genIndexKeyStr(vals) + entryKey, err := genIndexKeyStr(newVals) if err != nil { return err }