diff --git a/executor/insert_common.go b/executor/insert_common.go index dbd4a5ae264cd..1c20005c69b20 100644 --- a/executor/insert_common.go +++ b/executor/insert_common.go @@ -32,6 +32,7 @@ import ( "github.com/pingcap/tidb/parser/ast" "github.com/pingcap/tidb/parser/model" "github.com/pingcap/tidb/parser/mysql" + "github.com/pingcap/tidb/planner/core" "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/sessiontxn" @@ -745,7 +746,16 @@ func setDatumAutoIDAndCast(ctx sessionctx.Context, d *types.Datum, id int64, col 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. + // Auto ID is out of range. + sc := ctx.GetSessionVars().StmtCtx + insertPlan, ok := sc.GetPlan().(*core.Insert) + if ok && sc.TruncateAsWarning && len(insertPlan.OnDuplicate) > 0 { + // Fix issue #38950: AUTO_INCREMENT is incompatible with mysql + // An auto id out of range error occurs in `insert ignore into ... on duplicate ...`. + // We should allow the SQL to be executed successfully. + return nil + } + // 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 } diff --git a/executor/write_test.go b/executor/write_test.go index 32aa261c5518d..2b6915a775163 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -592,6 +592,25 @@ commit;` tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1526 Table has no partition for value 3")) } +func TestIssue38950(t *testing.T) { + store := testkit.CreateMockStore(t) + var cfg kv.InjectionConfig + tk := testkit.NewTestKit(t, kv.NewInjectedStore(store, &cfg)) + tk.MustExec("use test;") + tk.MustExec("drop table if exists t; create table t (id smallint auto_increment primary key);") + tk.MustExec("alter table t add column c1 int default 1;") + tk.MustExec("insert ignore into t(id) values (194626268);") + require.Empty(t, tk.Session().LastMessage()) + + tk.MustQuery("select * from t").Check(testkit.Rows("32767 1")) + + tk.MustExec("insert ignore into t(id) values ('*') on duplicate key update c1 = 2;") + require.Equal(t, int64(2), int64(tk.Session().AffectedRows())) + require.Empty(t, tk.Session().LastMessage()) + + tk.MustQuery("select * from t").Check(testkit.Rows("32767 2")) +} + func TestInsertOnDup(t *testing.T) { store := testkit.CreateMockStore(t) var cfg kv.InjectionConfig