diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 9b98d569fccbf..af9242066490c 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -244,13 +244,27 @@ func buildColumnAndConstraint(ctx sessionctx.Context, offset int, // checkColumnCantHaveDefaultValue checks the column can have value as default or not. // Now, TEXT/BLOB/JSON can't have not null value as default. -func checkColumnCantHaveDefaultValue(col *table.Column, value interface{}) (err error) { +func checkColumnCantHaveDefaultValue(ctx sessionctx.Context, col *table.Column, value interface{}) (err error) { if value != nil && (col.Tp == mysql.TypeJSON || col.Tp == mysql.TypeTinyBlob || col.Tp == mysql.TypeMediumBlob || col.Tp == mysql.TypeLongBlob || col.Tp == mysql.TypeBlob) { // TEXT/BLOB/JSON can't have not null default values. return errBlobCantHaveDefault.GenByArgs(col.Name.O) } + if value != nil && ctx.GetSessionVars().SQLMode.HasNoZeroDateMode() && + ctx.GetSessionVars().SQLMode.HasStrictMode() && types.IsTypeTime(col.Tp) { + if vv, ok := value.(string); ok { + t, err := types.ParseTime(nil, vv, col.Tp, 6) + if err != nil { + // Ignores ParseTime error, because ParseTime error has been dealt in getDefaultValue + // Some builtin function like CURRENT_TIMESTAMP() will cause ParseTime error. + return nil + } + if t.Time == types.ZeroTime { + return types.ErrInvalidDefault.GenByArgs(col.Name.O) + } + } + } return nil } @@ -314,7 +328,7 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef) ( if err != nil { return nil, nil, ErrColumnBadNull.Gen("invalid default value - %s", err) } - if err = checkColumnCantHaveDefaultValue(col, value); err != nil { + if err = checkColumnCantHaveDefaultValue(ctx, col, value); err != nil { return nil, nil, errors.Trace(err) } col.DefaultValue = value @@ -1293,7 +1307,7 @@ func setDefaultAndComment(ctx sessionctx.Context, col *table.Column, options []* if err != nil { return ErrColumnBadNull.Gen("invalid default value - %s", err) } - if err = checkColumnCantHaveDefaultValue(col, value); err != nil { + if err = checkColumnCantHaveDefaultValue(ctx, col, value); err != nil { return errors.Trace(err) } col.DefaultValue = value diff --git a/ddl/integration_test.go b/ddl/integration_test.go index 2e0246533f50f..69629017fc38b 100644 --- a/ddl/integration_test.go +++ b/ddl/integration_test.go @@ -15,6 +15,7 @@ package ddl_test import ( "fmt" + "github.com/pingcap/tidb/types" "github.com/juju/errors" . "github.com/pingcap/check" @@ -141,3 +142,31 @@ func newStoreWithBootstrap() (kv.Storage, *domain.Domain, error) { dom, err := session.BootstrapSession(store) return store, dom, errors.Trace(err) } + +func (s *testIntegrationSuite) TestNoZeroDateMode(c *C) { + tk := testkit.NewTestKit(c, s.store) + + defer tk.MustExec("set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';") + + tk.MustExec("use test;") + tk.MustExec("set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ENGINE_SUBSTITUTION';") + + _, err := tk.Exec("create table test_zero_date(agent_start_time date NOT NULL DEFAULT '0000-00-00')") + c.Assert(err, NotNil) + c.Assert(terror.ErrorEqual(err, types.ErrInvalidDefault), IsTrue, Commentf("err %v", err)) + + _, err = tk.Exec("create table test_zero_date(agent_start_time datetime NOT NULL DEFAULT '0000-00-00 00:00:00')") + c.Assert(err, NotNil) + c.Assert(terror.ErrorEqual(err, types.ErrInvalidDefault), IsTrue, Commentf("err %v", err)) + + _, err = tk.Exec("create table test_zero_date(agent_start_time timestamp NOT NULL DEFAULT '0000-00-00 00:00:00')") + c.Assert(err, NotNil) + c.Assert(terror.ErrorEqual(err, types.ErrInvalidDefault), IsTrue, Commentf("err %v", err)) + + _, err = tk.Exec("create table test_zero_date(a timestamp default '0000-00-00 00')") + c.Assert(err, NotNil) + + _, err = tk.Exec("create table test_zero_date(a timestamp default 0)") + c.Assert(err, NotNil) + c.Assert(terror.ErrorEqual(err, types.ErrInvalidDefault), IsTrue, Commentf("err %v", err)) +}