From f9098235895fd72f88437766f99a26e8cc4b27a4 Mon Sep 17 00:00:00 2001 From: Lingyu Song Date: Fri, 12 Jul 2019 14:56:55 +0800 Subject: [PATCH] executor: handle missing timestamp value for load data (#11093) --- executor/load_data.go | 6 ++++++ executor/write_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/executor/load_data.go b/executor/load_data.go index f9b602df887a9..8dd66812df223 100644 --- a/executor/load_data.go +++ b/executor/load_data.go @@ -282,8 +282,14 @@ func (e *LoadDataInfo) SetMessage() { } func (e *LoadDataInfo) colsToRow(ctx context.Context, cols []field) []types.Datum { + totalCols := e.Table.Cols() for i := 0; i < len(e.row); i++ { if i >= len(cols) { + // If some columns is missing and their type is time and has not null flag, they should be set as current time. + if types.IsTypeTime(totalCols[i].Tp) && mysql.HasNotNullFlag(totalCols[i].Flag) { + e.row[i].SetMysqlTime(types.CurrentTime(totalCols[i].Tp)) + continue + } e.row[i].SetNull() continue } diff --git a/executor/write_test.go b/executor/write_test.go index 50e59fd1689cd..fa0a981a5a4eb 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -21,6 +21,7 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/failpoint" "github.com/pingcap/parser/model" + "github.com/pingcap/parser/mysql" "github.com/pingcap/tidb/executor" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/planner/core" @@ -1775,6 +1776,43 @@ func (s *testSuite4) TestQualifiedDelete(c *C) { c.Assert(err, NotNil) } +func (s *testSuite4) TestLoadDataMissingColumn(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + createSQL := `create table load_data_missing (id int, t timestamp not null)` + tk.MustExec(createSQL) + tk.MustExec("load data local infile '/tmp/nonexistence.csv' ignore into table load_data_missing") + ctx := tk.Se.(sessionctx.Context) + ld, ok := ctx.Value(executor.LoadDataVarKey).(*executor.LoadDataInfo) + c.Assert(ok, IsTrue) + defer ctx.SetValue(executor.LoadDataVarKey, nil) + c.Assert(ld, NotNil) + + deleteSQL := "delete from load_data_missing" + selectSQL := "select * from load_data_missing;" + _, reachLimit, err := ld.InsertData(context.Background(), nil, nil) + c.Assert(err, IsNil) + c.Assert(reachLimit, IsFalse) + r := tk.MustQuery(selectSQL) + r.Check(nil) + + curTime := types.CurrentTime(mysql.TypeTimestamp) + timeStr := curTime.String() + tests := []testCase{ + {nil, []byte("12\n"), []string{fmt.Sprintf("12|%v", timeStr)}, nil, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 0"}, + } + checkCases(tests, ld, c, tk, ctx, selectSQL, deleteSQL) + + tk.MustExec("alter table load_data_missing add column t2 timestamp null") + curTime = types.CurrentTime(mysql.TypeTimestamp) + timeStr = curTime.String() + tests = []testCase{ + {nil, []byte("12\n"), []string{fmt.Sprintf("12|%v|", timeStr)}, nil, "Records: 1 Deleted: 0 Skipped: 0 Warnings: 0"}, + } + checkCases(tests, ld, c, tk, ctx, selectSQL, deleteSQL) + +} + func (s *testSuite4) TestLoadData(c *C) { trivialMsg := "Records: 1 Deleted: 0 Skipped: 0 Warnings: 0" tk := testkit.NewTestKit(c, s.store)