diff --git a/ddl/column.go b/ddl/column.go index 7948a33840..4712455604 100644 --- a/ddl/column.go +++ b/ddl/column.go @@ -21,6 +21,7 @@ import ( "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/meta" "github.com/pingcap/tidb/model" + "github.com/pingcap/tidb/mysql" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/tablecodec" "github.com/pingcap/tidb/terror" @@ -165,7 +166,7 @@ func (d *ddl) onAddColumn(t *meta.Meta, job *model.Job) error { if err != nil { return errors.Trace(err) } - if columnInfo.DefaultValue != nil { + if columnInfo.DefaultValue != nil || mysql.HasNotNullFlag(columnInfo.Flag) { err = d.runReorgJob(func() error { return d.backfillColumn(tbl, columnInfo, reorgInfo) }) @@ -321,9 +322,17 @@ func (d *ddl) backfillColumn(t table.Table, columnInfo *model.ColumnInfo, reorgI } func (d *ddl) backfillColumnData(t table.Table, columnInfo *model.ColumnInfo, handles []int64, reorgInfo *reorgInfo) error { - defaultVal, _, err := table.GetColDefaultValue(nil, columnInfo) - if err != nil { - return errors.Trace(err) + var ( + defaultVal types.Datum + err error + ) + if columnInfo.DefaultValue != nil { + defaultVal, _, err = table.GetColDefaultValue(nil, columnInfo) + if err != nil { + return errors.Trace(err) + } + } else if mysql.HasNotNullFlag(columnInfo.Flag) { + defaultVal = table.GetZeroValue(columnInfo) } colMap := make(map[int64]*types.FieldType) for _, col := range t.Meta().Columns { diff --git a/executor/executor_ddl_test.go b/executor/executor_ddl_test.go index 2f673004d9..fd85668298 100644 --- a/executor/executor_ddl_test.go +++ b/executor/executor_ddl_test.go @@ -141,3 +141,18 @@ func (s *testSuite) TestAlterTable(c *C) { tk.MustExec("create table if not exists alter_test (c1 int)") tk.MustExec("alter table alter_test add column c2 int") } + +func (s *testSuite) TestAddNotNullColumnNoDefault(c *C) { + defer testleak.AfterTest(c)() + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("create table nn (c1 int)") + tk.MustExec("insert nn values (1), (2)") + tk.MustExec("alter table nn add column c2 int not null") + tk.MustQuery("select * from nn").Check(testkit.Rows("1 0", "2 0")) + _, err := tk.Exec("insert nn (c1) values (3)") + c.Check(err, NotNil) + tk.MustExec("set sql_mode=''") + tk.MustExec("insert nn (c1) values (3)") + tk.MustQuery("select * from nn").Check(testkit.Rows("1 0", "2 0", "3 0")) +} diff --git a/table/column.go b/table/column.go index 06acdd49d5..89e039536c 100644 --- a/table/column.go +++ b/table/column.go @@ -237,7 +237,7 @@ func GetColDefaultValue(ctx context.Context, col *model.ColumnInfo) (types.Datum sessVars := variable.GetSessionVars(ctx) if !sessVars.StrictSQLMode { // TODO: add warning. - return getZeroValue(col), true, nil + return GetZeroValue(col), true, nil } } return types.Datum{}, false, errors.Trace(err) @@ -269,7 +269,8 @@ func GetColDefaultValue(ctx context.Context, col *model.ColumnInfo) (types.Datum return value, true, nil } -func getZeroValue(col *model.ColumnInfo) types.Datum { +// GetZeroValue gets zero value for given column type. +func GetZeroValue(col *model.ColumnInfo) types.Datum { var d types.Datum switch col.Tp { case mysql.TypeTiny, mysql.TypeInt24, mysql.TypeShort, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear: diff --git a/table/column_test.go b/table/column_test.go index a43f49e86f..1ff60ab2e0 100644 --- a/table/column_test.go +++ b/table/column_test.go @@ -175,7 +175,7 @@ func (s *testColumnSuite) TestGetZeroValue(c *C) { } for _, ca := range cases { colInfo := &model.ColumnInfo{FieldType: *ca.ft} - zv := getZeroValue(colInfo) + zv := GetZeroValue(colInfo) c.Assert(zv.Kind(), Equals, ca.value.Kind()) cmp, err := zv.CompareDatum(ca.value) c.Assert(err, IsNil)