executor: special handling is required when an "auto id out of range" error occurs in insert ignore into ... on on duplicate ... (#39847)

close pingcap/tidb#38950
This commit is contained in:
Jk Xu
2023-01-03 21:28:20 +08:00
committed by GitHub
parent 1f344ba108
commit 3ccff46aa3
2 changed files with 30 additions and 1 deletions

View File

@ -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"
@ -771,7 +772,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
}

View File

@ -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