From fbbdde103741744d5e6bfe7954eb9de45127fc97 Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Wed, 1 Aug 2018 17:22:05 +0800 Subject: [PATCH 1/9] in non-strict SQL mode,fix column type is text /blob/json default value null not processed. --- ddl/db_test.go | 39 +++++++++++++++++++++++++++++++++++++++ ddl/ddl_api.go | 32 +++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/ddl/db_test.go b/ddl/db_test.go index a0bc2f87d397e..f8f1d3abb519e 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -2115,6 +2115,45 @@ func (s *testDBSuite) TestYearTypeCreateTable(c *C) { c.Assert(mysql.HasUnsignedFlag(yearCol.Flag), IsFalse) } +func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { + s.tk = testkit.NewTestKit(c, s.store) + s.tk.MustExec("use test;") + s.tk.MustExec("drop table if exists text_default_text;") + s.testErrorCode(c, "create table text_default_text(c1 text not null default '');", tmysql.ErrBlobCantHaveDefault) + s.testErrorCode(c, "create table text_default_text(c1 text not null default 'scds');", tmysql.ErrBlobCantHaveDefault) + + s.tk.MustExec("drop table if exists text_default_json;") + s.testErrorCode(c, "create table text_default_json(c1 json not null default '');", tmysql.ErrBlobCantHaveDefault) + s.testErrorCode(c, "create table text_default_json(c1 json not null default 'dfew555');", tmysql.ErrBlobCantHaveDefault) + + s.tk.MustExec("drop table if exists text_default_blob;") + s.testErrorCode(c, "create table text_default_blob(c1 blob not null default '');", tmysql.ErrBlobCantHaveDefault) + s.testErrorCode(c, "create table text_default_blob(c1 blob not null default 'scds54');", tmysql.ErrBlobCantHaveDefault) + + s.tk.MustExec("set sql_mode='';") + s.tk.MustExec("drop table if exists text_default_text;") + s.tk.MustExec("create table text_default_text(c1 text not null default '');") + ctx := s.tk.Se.(sessionctx.Context) + is := domain.GetDomain(ctx).InfoSchema() + tblInfo, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_text")) + c.Assert(err, IsNil) + c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, "") + + s.tk.MustExec("drop table if exists text_default_blob;") + s.tk.MustExec("create table text_default_blob(c1 blob not null default '');") + is = domain.GetDomain(ctx).InfoSchema() + tblInfo, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_blob")) + c.Assert(err, IsNil) + c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, "") + + s.tk.MustExec("drop table if exists text_default_json;") + s.tk.MustExec("create table text_default_json(c1 json not null default '');") + is = domain.GetDomain(ctx).InfoSchema() + tblInfo, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_json")) + c.Assert(err, IsNil) + c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, `null`) +} + func (s *testDBSuite) TestCharacterSetInColumns(c *C) { s.tk = testkit.NewTestKit(c, s.store) s.tk.MustExec("drop database if exists varchar_test;") diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 034d8278f831f..e58dfbb0e7d7a 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -244,10 +244,15 @@ 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) { + if !ctx.GetSessionVars().SQLMode.HasStrictMode() && value == "" { + sc := ctx.GetSessionVars().StmtCtx + sc.AppendWarning(errBlobCantHaveDefault.GenByArgs(col.Name.O)) + return nil + } // TEXT/BLOB/JSON can't have not null default values. return errBlobCantHaveDefault.GenByArgs(col.Name.O) } @@ -314,11 +319,11 @@ 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 - hasDefaultValue = true + hasDefaultValue = ignoreNullDefaultValuesForColumns(ctx, col, value) removeOnUpdateNowFlag(col) case ast.ColumnOptionOnUpdate: // TODO: Support other time functions. @@ -374,6 +379,23 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef) ( return col, constraints, nil } +// ignoreNullDefaultValuesForColumns in non-strict SQL mode, if the default value of the column is an empty string, can ignore it. +func ignoreNullDefaultValuesForColumns(ctx sessionctx.Context, col *table.Column, value interface{}) bool { + hasDefaultValue := true + if !ctx.GetSessionVars().SQLMode.HasStrictMode() { + if col.Tp == mysql.TypeBlob || col.Tp == mysql.TypeLongBlob && value == "" { + hasDefaultValue = false + } + // In non-strict SQL mode, the json default value is empty, and then initialize it as an empty array. + if col.Tp == mysql.TypeJSON && value == "" { + col.DefaultValue = `null` + hasDefaultValue = true + } + return hasDefaultValue + } + return true +} + func getDefaultValue(ctx sessionctx.Context, c *ast.ColumnOption, tp byte, fsp int) (interface{}, error) { if tp == mysql.TypeTimestamp || tp == mysql.TypeDatetime { vd, err := expression.GetTimeValue(ctx, c.Expr, tp, fsp) @@ -1418,11 +1440,11 @@ 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 - hasDefaultValue = true + hasDefaultValue = ignoreNullDefaultValuesForColumns(ctx, col, value) case ast.ColumnOptionComment: err := setColumnComment(ctx, col, opt) if err != nil { From 7a57b63e8e747c5e8d7d00594699b19958a4fb2b Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Wed, 1 Aug 2018 17:37:35 +0800 Subject: [PATCH 2/9] update comments --- ddl/ddl_api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index e58dfbb0e7d7a..a053f843e425b 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -386,7 +386,7 @@ func ignoreNullDefaultValuesForColumns(ctx sessionctx.Context, col *table.Column if col.Tp == mysql.TypeBlob || col.Tp == mysql.TypeLongBlob && value == "" { hasDefaultValue = false } - // In non-strict SQL mode, the json default value is empty, and then initialize it as an empty array. + // In non-strict SQL mode, if the column type is json and the default value is null, it is initialized to an empty array. if col.Tp == mysql.TypeJSON && value == "" { col.DefaultValue = `null` hasDefaultValue = true From dbc1ac1e5ac2321e9b31828aee49ba62c5eb830d Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Wed, 1 Aug 2018 22:57:45 +0800 Subject: [PATCH 3/9] address comments --- ddl/ddl_api.go | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index a053f843e425b..a140dbb542d1f 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -244,19 +244,24 @@ 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(ctx sessionctx.Context, col *table.Column, value interface{}) (err error) { +func checkColumnCantHaveDefaultValue(ctx sessionctx.Context, col *table.Column, value interface{}) (bool, error) { + hasDefaultValue := true if value != nil && (col.Tp == mysql.TypeJSON || col.Tp == mysql.TypeTinyBlob || col.Tp == mysql.TypeMediumBlob || col.Tp == mysql.TypeLongBlob || col.Tp == mysql.TypeBlob) { if !ctx.GetSessionVars().SQLMode.HasStrictMode() && value == "" { + // In non-strict SQL mode, if the default value of the column is an empty string, can ignore it. + if col.Tp == mysql.TypeBlob || col.Tp == mysql.TypeLongBlob && value == "" { + hasDefaultValue = false + } sc := ctx.GetSessionVars().StmtCtx sc.AppendWarning(errBlobCantHaveDefault.GenByArgs(col.Name.O)) - return nil + return hasDefaultValue, nil } // TEXT/BLOB/JSON can't have not null default values. - return errBlobCantHaveDefault.GenByArgs(col.Name.O) + return hasDefaultValue, errBlobCantHaveDefault.GenByArgs(col.Name.O) } - return nil + return hasDefaultValue, nil } // isExplicitTimeStamp is used to check if explicit_defaults_for_timestamp is on or off. @@ -319,11 +324,15 @@ 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(ctx, col, value); err != nil { + if hasDefaultValue, err = checkColumnCantHaveDefaultValue(ctx, col, value); err != nil { return nil, nil, errors.Trace(err) } col.DefaultValue = value - hasDefaultValue = ignoreNullDefaultValuesForColumns(ctx, col, value) + // In non-strict SQL mode, if the column type is json and the default value is null, it is initialized to an empty array. + if col.Tp == mysql.TypeJSON && value == "" { + col.DefaultValue = `null` + hasDefaultValue = true + } removeOnUpdateNowFlag(col) case ast.ColumnOptionOnUpdate: // TODO: Support other time functions. @@ -379,23 +388,6 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef) ( return col, constraints, nil } -// ignoreNullDefaultValuesForColumns in non-strict SQL mode, if the default value of the column is an empty string, can ignore it. -func ignoreNullDefaultValuesForColumns(ctx sessionctx.Context, col *table.Column, value interface{}) bool { - hasDefaultValue := true - if !ctx.GetSessionVars().SQLMode.HasStrictMode() { - if col.Tp == mysql.TypeBlob || col.Tp == mysql.TypeLongBlob && value == "" { - hasDefaultValue = false - } - // In non-strict SQL mode, if the column type is json and the default value is null, it is initialized to an empty array. - if col.Tp == mysql.TypeJSON && value == "" { - col.DefaultValue = `null` - hasDefaultValue = true - } - return hasDefaultValue - } - return true -} - func getDefaultValue(ctx sessionctx.Context, c *ast.ColumnOption, tp byte, fsp int) (interface{}, error) { if tp == mysql.TypeTimestamp || tp == mysql.TypeDatetime { vd, err := expression.GetTimeValue(ctx, c.Expr, tp, fsp) @@ -1440,11 +1432,14 @@ func setDefaultAndComment(ctx sessionctx.Context, col *table.Column, options []* if err != nil { return ErrColumnBadNull.Gen("invalid default value - %s", err) } - if err = checkColumnCantHaveDefaultValue(ctx, col, value); err != nil { + if hasDefaultValue, err = checkColumnCantHaveDefaultValue(ctx, col, value); err != nil { return errors.Trace(err) } col.DefaultValue = value - hasDefaultValue = ignoreNullDefaultValuesForColumns(ctx, col, value) + if col.Tp == mysql.TypeJSON && value == "" { + col.DefaultValue = `null` + hasDefaultValue = true + } case ast.ColumnOptionComment: err := setColumnComment(ctx, col, opt) if err != nil { From cc0babcd3e67a86b023e337e4cf4050d30f345d9 Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Wed, 1 Aug 2018 23:58:38 +0800 Subject: [PATCH 4/9] address comments --- ddl/ddl_api.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index a140dbb542d1f..733b9e90c5cb2 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -331,7 +331,6 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef) ( // In non-strict SQL mode, if the column type is json and the default value is null, it is initialized to an empty array. if col.Tp == mysql.TypeJSON && value == "" { col.DefaultValue = `null` - hasDefaultValue = true } removeOnUpdateNowFlag(col) case ast.ColumnOptionOnUpdate: @@ -1438,7 +1437,6 @@ func setDefaultAndComment(ctx sessionctx.Context, col *table.Column, options []* col.DefaultValue = value if col.Tp == mysql.TypeJSON && value == "" { col.DefaultValue = `null` - hasDefaultValue = true } case ast.ColumnOptionComment: err := setColumnComment(ctx, col, opt) From 40aad3eeb320550a619459989274a23ff7bdae90 Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Thu, 2 Aug 2018 16:30:00 +0800 Subject: [PATCH 5/9] address comments --- ddl/db_test.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/ddl/db_test.go b/ddl/db_test.go index f8f1d3abb519e..6eb99e416e7b3 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -2133,25 +2133,30 @@ func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { s.tk.MustExec("set sql_mode='';") s.tk.MustExec("drop table if exists text_default_text;") s.tk.MustExec("create table text_default_text(c1 text not null default '');") - ctx := s.tk.Se.(sessionctx.Context) - is := domain.GetDomain(ctx).InfoSchema() - tblInfo, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_text")) - c.Assert(err, IsNil) - c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, "") + s.tk.MustQuery(`show create table text_default_text`).Check(testutil.RowsWithSep("|", + ""+ + "text_default_text CREATE TABLE `text_default_text` (\n"+ + " `c1` text NOT NULL\n"+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", + )) s.tk.MustExec("drop table if exists text_default_blob;") s.tk.MustExec("create table text_default_blob(c1 blob not null default '');") - is = domain.GetDomain(ctx).InfoSchema() - tblInfo, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_blob")) - c.Assert(err, IsNil) - c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, "") + s.tk.MustQuery(`show create table text_default_blob`).Check(testutil.RowsWithSep("|", + ""+ + "text_default_blob CREATE TABLE `text_default_blob` (\n"+ + " `c1` blob NOT NULL\n"+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", + )) s.tk.MustExec("drop table if exists text_default_json;") s.tk.MustExec("create table text_default_json(c1 json not null default '');") - is = domain.GetDomain(ctx).InfoSchema() - tblInfo, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_json")) - c.Assert(err, IsNil) - c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, `null`) + s.tk.MustQuery(`show create table text_default_json`).Check(testutil.RowsWithSep("|", + ""+ + "text_default_json CREATE TABLE `text_default_json` (\n"+ + " `c1` json NOT NULL DEFAULT 'null'\n"+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", + )) } func (s *testDBSuite) TestCharacterSetInColumns(c *C) { From eaa585039e9c47334e997896b9c26213bc526927 Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Fri, 3 Aug 2018 11:25:16 +0800 Subject: [PATCH 6/9] address comments --- ddl/db_test.go | 9 +++------ ddl/ddl_api.go | 10 ++++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ddl/db_test.go b/ddl/db_test.go index 1f4a21dfeada7..871fdab721b3a 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -2164,8 +2164,7 @@ func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { s.tk.MustExec("drop table if exists text_default_text;") s.tk.MustExec("create table text_default_text(c1 text not null default '');") s.tk.MustQuery(`show create table text_default_text`).Check(testutil.RowsWithSep("|", - ""+ - "text_default_text CREATE TABLE `text_default_text` (\n"+ + "text_default_text CREATE TABLE `text_default_text` (\n"+ " `c1` text NOT NULL\n"+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", )) @@ -2173,8 +2172,7 @@ func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { s.tk.MustExec("drop table if exists text_default_blob;") s.tk.MustExec("create table text_default_blob(c1 blob not null default '');") s.tk.MustQuery(`show create table text_default_blob`).Check(testutil.RowsWithSep("|", - ""+ - "text_default_blob CREATE TABLE `text_default_blob` (\n"+ + "text_default_blob CREATE TABLE `text_default_blob` (\n"+ " `c1` blob NOT NULL\n"+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", )) @@ -2182,8 +2180,7 @@ func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { s.tk.MustExec("drop table if exists text_default_json;") s.tk.MustExec("create table text_default_json(c1 json not null default '');") s.tk.MustQuery(`show create table text_default_json`).Check(testutil.RowsWithSep("|", - ""+ - "text_default_json CREATE TABLE `text_default_json` (\n"+ + "text_default_json CREATE TABLE `text_default_json` (\n"+ " `c1` json NOT NULL DEFAULT 'null'\n"+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", )) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 20cd9bc89222a..095a6a20a211e 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -252,22 +252,24 @@ 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. +// In non-strict SQL mode, if the default value of the column is an empty string, the default value can be ignored. +// In strict SQL mode, TEXT/BLOB/JSON can't have not null default values. func checkColumnCantHaveDefaultValue(ctx sessionctx.Context, col *table.Column, value interface{}) (bool, error) { hasDefaultValue := true if value != nil && (col.Tp == mysql.TypeJSON || col.Tp == mysql.TypeTinyBlob || col.Tp == mysql.TypeMediumBlob || col.Tp == mysql.TypeLongBlob || col.Tp == mysql.TypeBlob) { + // In non-strict SQL mode. if !ctx.GetSessionVars().SQLMode.HasStrictMode() && value == "" { - // In non-strict SQL mode, if the default value of the column is an empty string, can ignore it. - if col.Tp == mysql.TypeBlob || col.Tp == mysql.TypeLongBlob && value == "" { + if col.Tp == mysql.TypeBlob || col.Tp == mysql.TypeLongBlob { + // The TEXT/BLOB default value can be ignored. hasDefaultValue = false } sc := ctx.GetSessionVars().StmtCtx sc.AppendWarning(errBlobCantHaveDefault.GenByArgs(col.Name.O)) return hasDefaultValue, nil } - // TEXT/BLOB/JSON can't have not null default values. + // In strict SQL mode. return hasDefaultValue, errBlobCantHaveDefault.GenByArgs(col.Name.O) } return hasDefaultValue, nil From 69ae6652ba3a8bf9c6e56738f53985b59b491b62 Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Fri, 3 Aug 2018 15:54:37 +0800 Subject: [PATCH 7/9] address comments --- ddl/ddl_api.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 095a6a20a211e..4adf6516e1cfe 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -251,10 +251,10 @@ func buildColumnAndConstraint(ctx sessionctx.Context, offset int, return col, cts, nil } -// checkColumnCantHaveDefaultValue checks the column can have value as default or not. +// checkColumnDefaultValue checks the default value of the column. // In non-strict SQL mode, if the default value of the column is an empty string, the default value can be ignored. // In strict SQL mode, TEXT/BLOB/JSON can't have not null default values. -func checkColumnCantHaveDefaultValue(ctx sessionctx.Context, col *table.Column, value interface{}) (bool, error) { +func checkColumnDefaultValue(ctx sessionctx.Context, col *table.Column, value interface{}) (bool, interface{}, error) { hasDefaultValue := true if value != nil && (col.Tp == mysql.TypeJSON || col.Tp == mysql.TypeTinyBlob || col.Tp == mysql.TypeMediumBlob || @@ -265,14 +265,18 @@ func checkColumnCantHaveDefaultValue(ctx sessionctx.Context, col *table.Column, // The TEXT/BLOB default value can be ignored. hasDefaultValue = false } + // In non-strict SQL mode, if the column type is json and the default value is null, it is initialized to an empty array. + if col.Tp == mysql.TypeJSON { + value = `null` + } sc := ctx.GetSessionVars().StmtCtx sc.AppendWarning(errBlobCantHaveDefault.GenByArgs(col.Name.O)) - return hasDefaultValue, nil + return hasDefaultValue, value, nil } // In strict SQL mode. - return hasDefaultValue, errBlobCantHaveDefault.GenByArgs(col.Name.O) + return hasDefaultValue, value, errBlobCantHaveDefault.GenByArgs(col.Name.O) } - return hasDefaultValue, nil + return hasDefaultValue, value, nil } // isExplicitTimeStamp is used to check if explicit_defaults_for_timestamp is on or off. @@ -338,14 +342,10 @@ func columnDefToCol(ctx sessionctx.Context, offset int, colDef *ast.ColumnDef, o if err != nil { return nil, nil, ErrColumnBadNull.Gen("invalid default value - %s", err) } - if hasDefaultValue, err = checkColumnCantHaveDefaultValue(ctx, col, value); err != nil { + if hasDefaultValue, value, err = checkColumnDefaultValue(ctx, col, value); err != nil { return nil, nil, errors.Trace(err) } col.DefaultValue = value - // In non-strict SQL mode, if the column type is json and the default value is null, it is initialized to an empty array. - if col.Tp == mysql.TypeJSON && value == "" { - col.DefaultValue = `null` - } removeOnUpdateNowFlag(col) case ast.ColumnOptionOnUpdate: // TODO: Support other time functions. @@ -1477,13 +1477,10 @@ func setDefaultAndComment(ctx sessionctx.Context, col *table.Column, options []* if err != nil { return ErrColumnBadNull.Gen("invalid default value - %s", err) } - if hasDefaultValue, err = checkColumnCantHaveDefaultValue(ctx, col, value); err != nil { + if hasDefaultValue, value, err = checkColumnDefaultValue(ctx, col, value); err != nil { return errors.Trace(err) } col.DefaultValue = value - if col.Tp == mysql.TypeJSON && value == "" { - col.DefaultValue = `null` - } case ast.ColumnOptionComment: err := setColumnComment(ctx, col, opt) if err != nil { From 3b25e376da370236e06d18305b3c7f49a9a2cd02 Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Fri, 3 Aug 2018 16:04:31 +0800 Subject: [PATCH 8/9] add testCheckColumnDefaultValue test --- ddl/db_test.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ddl/db_test.go b/ddl/db_test.go index 871fdab721b3a..6e9209aac4aa9 100644 --- a/ddl/db_test.go +++ b/ddl/db_test.go @@ -2145,7 +2145,7 @@ func (s *testDBSuite) TestYearTypeCreateTable(c *C) { c.Assert(mysql.HasUnsignedFlag(yearCol.Flag), IsFalse) } -func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { +func (s *testDBSuite) TestCheckColumnDefaultValue(c *C) { s.tk = testkit.NewTestKit(c, s.store) s.tk.MustExec("use test;") s.tk.MustExec("drop table if exists text_default_text;") @@ -2168,6 +2168,11 @@ func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { " `c1` text NOT NULL\n"+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", )) + ctx := s.tk.Se.(sessionctx.Context) + is := domain.GetDomain(ctx).InfoSchema() + tblInfo, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_text")) + c.Assert(err, IsNil) + c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, "") s.tk.MustExec("drop table if exists text_default_blob;") s.tk.MustExec("create table text_default_blob(c1 blob not null default '');") @@ -2176,6 +2181,10 @@ func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { " `c1` blob NOT NULL\n"+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", )) + is = domain.GetDomain(ctx).InfoSchema() + tblInfo, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_blob")) + c.Assert(err, IsNil) + c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, "") s.tk.MustExec("drop table if exists text_default_json;") s.tk.MustExec("create table text_default_json(c1 json not null default '');") @@ -2184,6 +2193,10 @@ func (s *testDBSuite) TestCheckColumnCantHaveDefaultValue(c *C) { " `c1` json NOT NULL DEFAULT 'null'\n"+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin", )) + is = domain.GetDomain(ctx).InfoSchema() + tblInfo, err = is.TableByName(model.NewCIStr("test"), model.NewCIStr("text_default_json")) + c.Assert(err, IsNil) + c.Assert(tblInfo.Meta().Columns[0].DefaultValue, Equals, `null`) } func (s *testDBSuite) TestCharacterSetInColumns(c *C) { From 2226cb55deb1bd9ca6a7074e3ceeb7d1539ff2f7 Mon Sep 17 00:00:00 2001 From: ciscoxll Date: Mon, 6 Aug 2018 10:16:22 +0800 Subject: [PATCH 9/9] address comments --- ddl/ddl_api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index 4adf6516e1cfe..34117c01cd73c 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -273,7 +273,7 @@ func checkColumnDefaultValue(ctx sessionctx.Context, col *table.Column, value in sc.AppendWarning(errBlobCantHaveDefault.GenByArgs(col.Name.O)) return hasDefaultValue, value, nil } - // In strict SQL mode. + // In strict SQL mode or default value is not an empty string. return hasDefaultValue, value, errBlobCantHaveDefault.GenByArgs(col.Name.O) } return hasDefaultValue, value, nil