diff --git a/meta/autoid/autoid.go b/meta/autoid/autoid.go index e2fe504a3bc08..a201bb98bf64c 100644 --- a/meta/autoid/autoid.go +++ b/meta/autoid/autoid.go @@ -245,6 +245,9 @@ func (alloc *allocator) alloc4Unsigned(tableID int64) (int64, error) { alloc.base, alloc.end = newBase, newEnd } + if uint64(alloc.base)+uint64(1) == math.MaxUint64 { + return 0, ErrAutoincReadFailed + } alloc.base = int64(uint64(alloc.base) + 1) logutil.Logger(context.Background()).Debug("alloc unsigned ID", zap.Uint64("ID", uint64(alloc.base)), @@ -281,6 +284,9 @@ func (alloc *allocator) alloc4Signed(tableID int64) (int64, error) { alloc.base, alloc.end = newBase, newEnd } + if alloc.base+1 == math.MaxInt64 { + return 0, ErrAutoincReadFailed + } alloc.base++ logutil.Logger(context.Background()).Debug("alloc signed ID", zap.Uint64("ID", uint64(alloc.base)), diff --git a/meta/autoid/autoid_test.go b/meta/autoid/autoid_test.go index c907277528594..aae2a687a3882 100644 --- a/meta/autoid/autoid_test.go +++ b/meta/autoid/autoid_test.go @@ -15,6 +15,7 @@ package autoid_test import ( "fmt" + "math" "sync" "testing" "time" @@ -133,6 +134,14 @@ func (*testSuite) TestT(c *C) { id, err = alloc.Alloc(3) c.Assert(err, IsNil) c.Assert(id, Equals, int64(6544)) + + // Test the MaxInt64 is the upper bound of `alloc` function but not `rebase`. + err = alloc.Rebase(3, int64(math.MaxInt64-1), true) + c.Assert(err, IsNil) + _, err = alloc.Alloc(3) + c.Assert(alloc, NotNil) + err = alloc.Rebase(3, int64(math.MaxInt64), true) + c.Assert(err, IsNil) } func (*testSuite) TestUnsignedAutoid(c *C) { @@ -229,6 +238,17 @@ func (*testSuite) TestUnsignedAutoid(c *C) { id, err = alloc.Alloc(3) c.Assert(err, IsNil) c.Assert(id, Equals, int64(6544)) + + // Test the MaxUint64 is the upper bound of `alloc` func but not `rebase`. + var n uint64 = math.MaxUint64 - 1 + un := int64(n) + err = alloc.Rebase(3, un, true) + c.Assert(err, IsNil) + _, err = alloc.Alloc(3) + c.Assert(err, NotNil) + un = int64(n + 1) + err = alloc.Rebase(3, un, true) + c.Assert(err, IsNil) } // TestConcurrentAlloc is used for the test that diff --git a/session/session_test.go b/session/session_test.go index 88cc6300ae270..07927ac0c55ea 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -792,8 +792,11 @@ func (s *testSessionSuite) TestAutoIncrementID(c *C) { tk.MustExec("insert into autoid values();") tk.MustExec("insert into autoid values();") tk.MustQuery("select * from autoid").Check(testkit.Rows("9223372036854775808", "9223372036854775810", "9223372036854775812")) - tk.MustExec("insert into autoid values(18446744073709551614);") - _, err := tk.Exec("insert into autoid values()") + // In TiDB : _tidb_rowid will also consume the autoID when the auto_increment column is not the primary key. + // Using the MaxUint64 and MaxInt64 as the autoID upper limit like MySQL will cause _tidb_rowid allocation fail here. + _, err := tk.Exec("insert into autoid values(18446744073709551614)") + c.Assert(terror.ErrorEqual(err, autoid.ErrAutoincReadFailed), IsTrue) + _, err = tk.Exec("insert into autoid values()") c.Assert(terror.ErrorEqual(err, autoid.ErrAutoincReadFailed), IsTrue) // FixMe: MySQL works fine with the this sql. _, err = tk.Exec("insert into autoid values(18446744073709551615)") @@ -816,12 +819,15 @@ func (s *testSessionSuite) TestAutoIncrementID(c *C) { // Corner cases for signed bigint auto_increment Columns. tk.MustExec("drop table if exists autoid") tk.MustExec("create table autoid(`auto_inc_id` bigint(20) NOT NULL AUTO_INCREMENT,UNIQUE KEY `auto_inc_id` (`auto_inc_id`))") - tk.MustExec("insert into autoid values(9223372036854775806);") - tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid").Check(testkit.Rows("9223372036854775806 9223372036854775807")) + // In TiDB : _tidb_rowid will also consume the autoID when the auto_increment column is not the primary key. + // Using the MaxUint64 and MaxInt64 as autoID upper limit like MySQL will cause insert fail if the values is + // 9223372036854775806. Because _tidb_rowid will be allocated 9223372036854775807 at same time. + tk.MustExec("insert into autoid values(9223372036854775805);") + tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index()").Check(testkit.Rows("9223372036854775805 9223372036854775806")) _, err = tk.Exec("insert into autoid values();") c.Assert(terror.ErrorEqual(err, autoid.ErrAutoincReadFailed), IsTrue) - tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid").Check(testkit.Rows("9223372036854775806 9223372036854775807")) - tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index(auto_inc_id)").Check(testkit.Rows("9223372036854775806 9223372036854775807")) + tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index()").Check(testkit.Rows("9223372036854775805 9223372036854775806")) + tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index(auto_inc_id)").Check(testkit.Rows("9223372036854775805 9223372036854775806")) tk.MustExec("drop table if exists autoid") tk.MustExec("create table autoid(`auto_inc_id` bigint(20) NOT NULL AUTO_INCREMENT,UNIQUE KEY `auto_inc_id` (`auto_inc_id`))")