From 31f7e39ab08b557cd13e36fd21cb1ae1b5a13b19 Mon Sep 17 00:00:00 2001 From: tangenta Date: Wed, 1 Dec 2021 14:00:29 +0800 Subject: [PATCH] executor: replace should not change other rows when auto ID is out of range --- executor/insert_common.go | 5 +++++ executor/insert_test.go | 15 +++++++++++++++ 2 files changed, 20 insertions(+) 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 6a2245abb96e3..ab41475d3e6fa 100644 --- a/executor/insert_test.go +++ b/executor/insert_test.go @@ -1820,3 +1820,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) +}