diff --git a/executor/insert_common.go b/executor/insert_common.go index e16253a7756bc..9c7adbb3c4d1a 100644 --- a/executor/insert_common.go +++ b/executor/insert_common.go @@ -682,6 +682,11 @@ func setDatumAutoIDAndCast(ctx sessionctx.Context, d *types.Datum, id int64, col d.SetAutoID(id, col.Flag) var err error *d, err = table.CastValue(ctx, *d, col.ToInfo(), false, false) + if err == nil && d.GetInt64() < id { + // Auto ID is out of range, the truncated ID is possible to duplicate with an existing ID. + // To prevent updating unrelated rows in the REPLACE statement, it is better to throw an error. + return autoid.ErrAutoincReadFailed + } return err } diff --git a/executor/insert_test.go b/executor/insert_test.go index 0d6788dad075a..72735d160440d 100644 --- a/executor/insert_test.go +++ b/executor/insert_test.go @@ -1825,3 +1825,18 @@ func (s *testAutoRandomSuite) TestInsertIssue29892(c *C) { c.Assert(err, NotNil) c.Assert(strings.Contains(err.Error(), "Duplicate entry"), Equals, true) } + +// https://github.com/pingcap/tidb/issues/29483. +func (s *testSuite13) TestReplaceAllocatingAutoID(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("drop database if exists replace_auto_id;") + tk.MustExec("create database replace_auto_id;") + tk.MustExec(`use replace_auto_id;`) + + tk.MustExec("SET sql_mode='NO_ENGINE_SUBSTITUTION';") + tk.MustExec("DROP TABLE IF EXISTS t1;") + tk.MustExec("CREATE TABLE t1 (a tinyint not null auto_increment primary key, b char(20));") + tk.MustExec("INSERT INTO t1 VALUES (127,'maxvalue');") + // Note that this error is different from MySQL's duplicated primary key error. + tk.MustGetErrCode("REPLACE INTO t1 VALUES (0,'newmaxvalue');", errno.ErrAutoincReadFailed) +}