Skip to content

Commit 1cc3f9b

Browse files
authored
*: fix 'Duplicate entry' error when @@auto_increment_increment and @@auto_increment_offset is set (#52626) (#53057)
close #52622
1 parent 45d1613 commit 1cc3f9b

File tree

5 files changed

+73
-20
lines changed

5 files changed

+73
-20
lines changed

pkg/autoid_service/autoid.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ func (alloc *autoIDValue) rebase4Unsigned(ctx context.Context,
200200
return nil
201201
}
202202
// Satisfied by alloc.end, need to update alloc.base.
203-
if requiredBase <= uint64(alloc.end) {
203+
if requiredBase > uint64(alloc.base) && requiredBase <= uint64(alloc.end) {
204204
alloc.base = int64(requiredBase)
205205
return nil
206206
}
@@ -243,7 +243,7 @@ func (alloc *autoIDValue) rebase4Signed(ctx context.Context, store kv.Storage, d
243243
return nil
244244
}
245245
// Satisfied by alloc.end, need to update alloc.base.
246-
if requiredBase <= alloc.end {
246+
if requiredBase > alloc.base && requiredBase <= alloc.end {
247247
alloc.base = requiredBase
248248
return nil
249249
}
@@ -501,6 +501,7 @@ func (s *Service) allocAutoID(ctx context.Context, req *autoid.AutoIDRequest) (*
501501
if err1 != nil {
502502
return err1
503503
}
504+
val.base = currentEnd
504505
val.end = currentEnd
505506
return nil
506507
})

pkg/executor/test/autoidtest/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ go_test(
99
],
1010
flaky = True,
1111
race = "on",
12-
shard_count = 10,
12+
shard_count = 11,
1313
deps = [
1414
"//pkg/autoid_service",
1515
"//pkg/config",

pkg/executor/test/autoidtest/autoid_test.go

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ func TestAutoIDIncrementAndOffset(t *testing.T) {
606606
for _, str := range []string{"", " AUTO_ID_CACHE 1"} {
607607
tk.MustExec(`create table io (a int key auto_increment)` + str)
608608
tk.MustExec(`insert into io values (null),(null),(null)`)
609-
tk.MustQuery(`select * from io`).Check(testkit.Rows("10", "15", "20"))
609+
tk.MustQuery(`select * from io`).Check(testkit.Rows("1", "6", "11"))
610610
tk.MustExec(`drop table io`)
611611
}
612612

@@ -616,23 +616,23 @@ func TestAutoIDIncrementAndOffset(t *testing.T) {
616616
tk.Session().GetSessionVars().AutoIncrementOffset = 10
617617
tk.Session().GetSessionVars().AutoIncrementIncrement = 2
618618
tk.MustExec(`insert into io values (),(),()`)
619-
tk.MustQuery(`select * from io`).Check(testkit.Rows("10", "12", "14"))
619+
tk.MustQuery(`select * from io`).Check(testkit.Rows("1", "3", "5"))
620620
tk.MustExec(`delete from io`)
621621

622622
// Test reset the increment.
623623
tk.Session().GetSessionVars().AutoIncrementIncrement = 5
624624
tk.MustExec(`insert into io values (),(),()`)
625-
tk.MustQuery(`select * from io`).Check(testkit.Rows("15", "20", "25"))
625+
tk.MustQuery(`select * from io`).Check(testkit.Rows("6", "11", "16"))
626626
tk.MustExec(`delete from io`)
627627

628628
tk.Session().GetSessionVars().AutoIncrementIncrement = 10
629629
tk.MustExec(`insert into io values (),(),()`)
630-
tk.MustQuery(`select * from io`).Check(testkit.Rows("30", "40", "50"))
630+
tk.MustQuery(`select * from io`).Check(testkit.Rows("20", "30", "40"))
631631
tk.MustExec(`delete from io`)
632632

633633
tk.Session().GetSessionVars().AutoIncrementIncrement = 5
634634
tk.MustExec(`insert into io values (),(),()`)
635-
tk.MustQuery(`select * from io`).Check(testkit.Rows("55", "60", "65"))
635+
tk.MustQuery(`select * from io`).Check(testkit.Rows("41", "46", "51"))
636636
tk.MustExec(`drop table io`)
637637
}
638638

@@ -643,10 +643,10 @@ func TestAutoIDIncrementAndOffset(t *testing.T) {
643643
tk.MustExec(`create table io (a int, b int auto_increment, key(b))` + str)
644644
tk.MustExec(`insert into io(b) values (null),(null),(null)`)
645645
// AutoID allocation will take increment and offset into consideration.
646-
tk.MustQuery(`select b from io`).Check(testkit.Rows("10", "12", "14"))
646+
tk.MustQuery(`select b from io`).Check(testkit.Rows("1", "3", "5"))
647647
if str == "" {
648648
// HandleID allocation will ignore the increment and offset.
649-
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("15", "16", "17"))
649+
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("6", "7", "8"))
650650
} else {
651651
// Separate row id and auto inc id, increment and offset works on auto inc id
652652
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("1", "2", "3"))
@@ -655,9 +655,9 @@ func TestAutoIDIncrementAndOffset(t *testing.T) {
655655

656656
tk.Session().GetSessionVars().AutoIncrementIncrement = 10
657657
tk.MustExec(`insert into io(b) values (null),(null),(null)`)
658-
tk.MustQuery(`select b from io`).Check(testkit.Rows("20", "30", "40"))
658+
tk.MustQuery(`select b from io`).Check(testkit.Rows("10", "20", "30"))
659659
if str == "" {
660-
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("41", "42", "43"))
660+
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("31", "32", "33"))
661661
} else {
662662
tk.MustQuery(`select _tidb_rowid from io`).Check(testkit.Rows("4", "5", "6"))
663663
}
@@ -806,3 +806,43 @@ func TestAutoIDConstraint(t *testing.T) {
806806
tk.MustExec("create table tt2 (id int, c int auto_increment, key c_idx(c))")
807807
tk.MustExec("alter table tt2 drop index c_idx")
808808
}
809+
810+
func TestIssue52622(t *testing.T) {
811+
store := testkit.CreateMockStore(t)
812+
813+
tk := testkit.NewTestKit(t, store)
814+
tk.MustExec("use test")
815+
tk.MustExec(`set @@auto_increment_increment = 66;`)
816+
tk.MustExec(`set @@auto_increment_offset = 9527;`)
817+
818+
tk.MustQuery(`select @@auto_increment_increment;`).Check(testkit.Rows("66"))
819+
tk.MustQuery(`select @@auto_increment_offset;`).Check(testkit.Rows("9527"))
820+
821+
for i := 0; i < 2; i++ {
822+
createTableSQL := "create table issue52622 (id int primary key auto_increment, k int)"
823+
if i == 0 {
824+
createTableSQL = createTableSQL + " AUTO_ID_CACHE 1"
825+
}
826+
827+
tk.MustExec(createTableSQL)
828+
tk.MustExec("insert into issue52622 (k) values (1),(2),(3);")
829+
tk.MustQuery("select * from issue52622").Check(testkit.Rows("1 1", "67 2", "133 3"))
830+
if i == 0 {
831+
tk.MustQuery("show create table issue52622").CheckContain("134")
832+
}
833+
tk.MustExec("insert into issue52622 (k) values (4);")
834+
tk.MustQuery("select * from issue52622").Check(testkit.Rows("1 1", "67 2", "133 3", "199 4"))
835+
836+
tk.MustExec("truncate table issue52622;")
837+
tk.MustExec("insert into issue52622 (k) values (1)")
838+
tk.MustExec("insert into issue52622 (k) values (2)")
839+
tk.MustExec("insert into issue52622 (k) values (3)")
840+
if i == 0 {
841+
tk.MustQuery("show create table issue52622").CheckContain("134")
842+
}
843+
tk.MustExec("insert into issue52622 (k) values (4);")
844+
tk.MustQuery("select * from issue52622").Check(testkit.Rows("1 1", "67 2", "133 3", "199 4"))
845+
846+
tk.MustExec("drop table issue52622;")
847+
}
848+
}

pkg/table/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ go_library(
2323
"//pkg/parser/types",
2424
"//pkg/sessionctx",
2525
"//pkg/sessionctx/stmtctx",
26+
"//pkg/sessionctx/variable",
2627
"//pkg/types",
2728
"//pkg/util/chunk",
2829
"//pkg/util/dbterror",

pkg/table/table.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/pingcap/tidb/pkg/meta/autoid"
2828
"github.com/pingcap/tidb/pkg/parser/model"
2929
"github.com/pingcap/tidb/pkg/sessionctx"
30+
"github.com/pingcap/tidb/pkg/sessionctx/variable"
3031
"github.com/pingcap/tidb/pkg/types"
3132
"github.com/pingcap/tidb/pkg/util/dbterror"
3233
"github.com/pingcap/tidb/pkg/util/sqlexec"
@@ -206,12 +207,23 @@ type Table interface {
206207
GetPartitionedTable() PartitionedTable
207208
}
208209

210+
func getIncrementAndOffset(vars *variable.SessionVars) (int, int) {
211+
increment := vars.AutoIncrementIncrement
212+
offset := vars.AutoIncrementOffset
213+
// When the value of auto_increment_offset is greater than that of auto_increment_increment,
214+
// the value of auto_increment_offset is ignored.
215+
// Ref https://dev.mysql.com/doc/refman/8.0/en/replication-options-source.html
216+
if offset > increment {
217+
offset = 1
218+
}
219+
return increment, offset
220+
}
221+
209222
// AllocAutoIncrementValue allocates an auto_increment value for a new row.
210223
func AllocAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Context) (int64, error) {
211224
r, ctx := tracing.StartRegionEx(ctx, "table.AllocAutoIncrementValue")
212225
defer r.End()
213-
increment := sctx.GetSessionVars().AutoIncrementIncrement
214-
offset := sctx.GetSessionVars().AutoIncrementOffset
226+
increment, offset := getIncrementAndOffset(sctx.GetSessionVars())
215227
alloc := t.Allocators(sctx).Get(autoid.AutoIncrementType)
216228
_, max, err := alloc.Alloc(ctx, uint64(1), int64(increment), int64(offset))
217229
if err != nil {
@@ -222,18 +234,17 @@ func AllocAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Conte
222234

223235
// AllocBatchAutoIncrementValue allocates batch auto_increment value for rows, returning firstID, increment and err.
224236
// The caller can derive the autoID by adding increment to firstID for N-1 times.
225-
func AllocBatchAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Context, N int) (firstID int64, increment int64, err error) {
226-
increment = int64(sctx.GetSessionVars().AutoIncrementIncrement)
227-
offset := int64(sctx.GetSessionVars().AutoIncrementOffset)
237+
func AllocBatchAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Context, N int) ( /* firstID */ int64 /* increment */, int64 /* err */, error) {
238+
increment1, offset := getIncrementAndOffset(sctx.GetSessionVars())
228239
alloc := t.Allocators(sctx).Get(autoid.AutoIncrementType)
229-
min, max, err := alloc.Alloc(ctx, uint64(N), increment, offset)
240+
min, max, err := alloc.Alloc(ctx, uint64(N), int64(increment1), int64(offset))
230241
if err != nil {
231242
return min, max, err
232243
}
233244
// SeekToFirstAutoIDUnSigned seeks to first autoID. Because AutoIncrement always allocate from 1,
234245
// signed and unsigned value can be unified as the unsigned handle.
235-
nr := int64(autoid.SeekToFirstAutoIDUnSigned(uint64(min), uint64(increment), uint64(offset)))
236-
return nr, increment, nil
246+
nr := int64(autoid.SeekToFirstAutoIDUnSigned(uint64(min), uint64(increment1), uint64(offset)))
247+
return nr, int64(increment1), nil
237248
}
238249

239250
// PhysicalTable is an abstraction for two kinds of table representation: partition or non-partitioned table.

0 commit comments

Comments
 (0)