From 6a0efc72220ff07e3ee8543180aafea9f600f999 Mon Sep 17 00:00:00 2001 From: tangenta Date: Thu, 21 Jul 2022 15:59:06 +0800 Subject: [PATCH] ddl: fix update panic in the middle of multi-schema change --- ddl/column.go | 2 ++ ddl/multi_schema_change_test.go | 41 ++++++++++++++++++++++++++++ planner/core/logical_plan_builder.go | 2 +- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/ddl/column.go b/ddl/column.go index a1888bcace351..ed05069130a93 100644 --- a/ddl/column.go +++ b/ddl/column.go @@ -260,6 +260,7 @@ func onDropColumn(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) case model.StateWriteOnly: // write only -> delete only colInfo.State = model.StateDeleteOnly + tblInfo.MoveColumnInfo(colInfo.Offset, len(tblInfo.Columns)-1) if len(idxInfos) > 0 { newIndices := make([]*model.IndexInfo, 0, len(tblInfo.Indices)) for _, idx := range tblInfo.Indices { @@ -277,6 +278,7 @@ func onDropColumn(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) case model.StateDeleteOnly: // delete only -> reorganization colInfo.State = model.StateDeleteReorganization + tblInfo.MoveColumnInfo(colInfo.Offset, len(tblInfo.Columns)-1) ver, err = updateVersionAndTableInfo(d, t, job, tblInfo, originalState != colInfo.State) if err != nil { return ver, errors.Trace(err) diff --git a/ddl/multi_schema_change_test.go b/ddl/multi_schema_change_test.go index c16ab46a62648..92d55fed0932c 100644 --- a/ddl/multi_schema_change_test.go +++ b/ddl/multi_schema_change_test.go @@ -1155,6 +1155,47 @@ func TestMultiSchemaChangeUnsupportedType(t *testing.T) { "[ddl:8200]Unsupported multi schema change for modify auto id cache") } +func TestMultiSchemaChangeMixedWithUpdate(t *testing.T) { + store, dom, clean := testkit.CreateMockStoreAndDomain(t) + defer clean() + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test;") + tk.MustExec("create table t (c_1 int, c_2 char(20), c_pos_1 int, c_idx_visible int, c_3 decimal(5, 3), " + + "c_drop_1 time, c_4 datetime, c_drop_idx char(10), c_5 time, c_6 double, c_drop_2 int, c_pos_2 char(10), " + + "c_add_idx_1 int, c_add_idx_2 char(20), index idx_1(c_1), index idx_2(c_2), index idx_drop(c_drop_idx), " + + "index idx_3(c_drop_1), index idx_4(c_4), index idx_5(c_pos_1, c_pos_2), index idx_visible(c_idx_visible));") + tk.MustExec("insert into t values (100, 'c_2_insert', 101, 12, 2.1, '10:00:00', " + + "'2020-01-01 10:00:00', 'wer', '10:00:00', 2.1, 12, 'qwer', 12, 'asdf');") + + originHook := dom.DDL().GetHook() + hook := &ddl.TestDDLCallback{Do: dom} + var checkErr error + hook.OnJobRunBeforeExported = func(job *model.Job) { + if checkErr != nil { + return + } + assert.Equal(t, model.ActionMultiSchemaChange, job.Type) + if job.MultiSchemaInfo.SubJobs[9].SchemaState == model.StateDeleteOnly { + tk2 := testkit.NewTestKit(t, store) + tk2.MustExec("use test;") + _, checkErr = tk2.Exec("update t set c_4 = '2020-01-01 10:00:00', c_5 = 'c_5_update', c_1 = 102, " + + "c_2 = '1', c_pos_1 = 102, c_idx_visible = 102, c_3 = 3.1, c_drop_idx = 'er', c_6 = 2, c_pos_2 = 'dddd', " + + "c_add_idx_1 = 102, c_add_idx_2 = 'zxc', c_add_2 = 10001, c_add_1 = 10001 where c_drop_idx = 'wer';") + if checkErr != nil { + return + } + } + } + dom.DDL().SetHook(hook) + tk.MustExec("alter table t add index i_add_1(c_add_idx_1), drop index idx_drop, " + + "add index i_add_2(c_add_idx_2), modify column c_2 char(100), add column c_add_2 bigint, " + + "modify column c_1 bigint, add column c_add_1 bigint, modify column c_5 varchar(255) first, " + + "modify column c_4 datetime first, drop column c_drop_1, drop column c_drop_2, modify column c_6 int, " + + "alter index idx_visible invisible, modify column c_3 decimal(10, 2);") + require.NoError(t, checkErr) + dom.DDL().SetHook(originHook) +} + type cancelOnceHook struct { store kv.Storage triggered bool diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 70ab80fa6cbc1..8e28747b11c41 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -5344,7 +5344,7 @@ func (b *PlanBuilder) buildUpdateLists(ctx context.Context, tableList []*ast.Tab if !found { return nil, nil, false, infoschema.ErrTableNotExists.GenWithStackByArgs(tn.DBInfo.Name.O, tableInfo.Name.O) } - for i, colInfo := range tableInfo.Columns { + for i, colInfo := range tableVal.Cols() { if !colInfo.IsGenerated() { continue }