Please answer these questions before submitting your issue. Thanks!
Initialization:
set @@tidb_txn_mode=""; -- use optimistic transaction
create table t (id int not null auto_increment unique key, idx int unique key, c int);
create table src (a int);
Session1, Session2 execute for 100 times:
insert into t(idx, c) select 1 as idx, 1 as c from src on duplicate key update c = %d;
Session3 executes for 100 times:
insert into src values (null);
When these sessions run concurrently:
(null, 1, %d). This triggers the transaction retry.auto_increment ids are allocated before conflicts. They are reused in the following retry.src keep increasing, the auto ids that allocated before conflicts are not enough in retry. As a result, an index-out-of-range error is converted to Cannot get auto-id in retry. The complete test code
func (s *seqTestSuite) TestInsertFromSelectConflictRetryAutoID(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("drop table if exists t;")
tk.MustExec("create table t (id int not null auto_increment unique key, idx int unique key, c int);")
tk.MustExec("create table src (a int);")
concurrency := 2
var wg sync.WaitGroup
var err []error
wgCount := concurrency + 1
wg.Add(wgCount)
err = make([]error, concurrency)
for i := 0; i < concurrency; i++ {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("set autocommit = 1")
go func(idx int) {
for i := 0; i < 10; i++ {
sql := fmt.Sprintf("insert into t(idx, c) select 1 as idx, 1 as c from src on duplicate key update c = %[1]d", i)
_, e := tk.Exec(sql)
if e != nil {
err[idx] = e
wg.Done()
return
}
}
wg.Done()
}(i)
}
var insertErr error
go func() {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("set autocommit = 1")
for i := 0; i < 10; i++ {
_, e := tk.Exec("insert into src values (null);")
if e != nil {
insertErr = e
wg.Done()
return
}
}
wg.Done()
}()
wg.Wait()
for _, e := range err {
c.Assert(e, IsNil)
}
c.Assert(insertErr, IsNil)
}
All of these statements should encounter no error.
release-3.0:
cannot get valid auto-increment id in retry
release-4.0/master
Cannot get a valid auto-ID when retrying the statement
All of the TiDB versions.
The description is impressive.
When executing INSERT statement, the allocated auto-increment ids are cached for the future retries. However, it is possible that the retrying INSERT statement populates a different number of rows. As a result, auto-increment IDs in cache are not enough. For details, see https://github.com/pingcap/tidb/issues/20629.
TiDB reports Cannot get auto-id in retry 'INSERT INTO ... SELECT FROM' when inserting rows.
INSERT .. ON DUPLICATE UPDATE triggers statements retry.INSERT statement.Retry the statement in application.
[v3.0.0:v3.0.19], [v4.0.0:v4.0.8]
v4.0.9
The values in ( FixedVersions ) fields are incorrect.
The values in ( FixedVersions ) fields are incorrect.
@tangenta please cherry-pick the bugfix to the release branches.