From a8900d864ef681b233278d7136f4fe7944dbfa12 Mon Sep 17 00:00:00 2001 From: Yu Shuaipeng Date: Wed, 24 Apr 2019 17:01:59 +0800 Subject: [PATCH] executor: fix bad null error handling for insert statement when disabling the strict SQL mode (#10161) --- executor/executor.go | 5 ++++- executor/executor_test.go | 9 ++++++++- executor/insert_common.go | 4 ++++ executor/write_test.go | 5 +++++ table/column.go | 9 +++++++-- table/table.go | 4 ++-- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/executor/executor.go b/executor/executor.go index fe654e1cd74b5..f64266c2553f7 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -1290,8 +1290,11 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) { sc.Priority = stmt.Priority case *ast.InsertStmt: sc.InInsertStmt = true + // For insert statement (not for update statement), disabling the StrictSQLMode + // should make TruncateAsWarning and DividedByZeroAsWarning, + // but should not make DupKeyAsWarning or BadNullAsWarning, sc.DupKeyAsWarning = stmt.IgnoreErr - sc.BadNullAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr + sc.BadNullAsWarning = stmt.IgnoreErr sc.TruncateAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr sc.AllowInvalidDate = vars.SQLMode.HasAllowInvalidDatesMode() diff --git a/executor/executor_test.go b/executor/executor_test.go index c6e40801d2fa6..91465619b4e18 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -1764,8 +1764,15 @@ func (s *testSuite) TestSQLMode(c *C) { tk.MustExec("set sql_mode = ''") tk.MustExec("insert t values ()") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'a' doesn't have a default value")) + _, err = tk.Exec("insert t values (null)") + c.Check(err, NotNil) + tk.MustExec("insert ignore t values (null)") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1048 Column 'a' cannot be null")) + tk.MustExec("insert t select null") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1048 Column 'a' cannot be null")) tk.MustExec("insert t values (1000)") - tk.MustQuery("select * from t").Check(testkit.Rows("0", "127")) + tk.MustQuery("select * from t order by a").Check(testkit.Rows("0", "0", "0", "127")) tk.MustExec("insert tdouble values (10.23)") tk.MustQuery("select * from tdouble").Check(testkit.Rows("9.99")) diff --git a/executor/insert_common.go b/executor/insert_common.go index f77502d16ed51..988152ac6753e 100644 --- a/executor/insert_common.go +++ b/executor/insert_common.go @@ -302,6 +302,10 @@ func (e *InsertValues) insertRowsFromSelect(ctx context.Context, exec func(rows rows := make([][]types.Datum, 0, chk.Capacity()) sessVars := e.ctx.GetSessionVars() + if !sessVars.StrictSQLMode { + // If StrictSQLMode is disabled and it is a insert-select statement, it also handle BadNullAsWarning. + sessVars.StmtCtx.BadNullAsWarning = true + } batchInsert := (sessVars.BatchInsert && !sessVars.InTxn()) || config.GetGlobalConfig().EnableBatchDML for { diff --git a/executor/write_test.go b/executor/write_test.go index 61275164c70dc..79834bfceaf76 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -679,6 +679,11 @@ commit;` tk.MustExec(`INSERT IGNORE t1 VALUES (1, 1) ON DUPLICATE KEY UPDATE f2 = null;`) tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1048 Column 'f2' cannot be null")) tk.MustQuery(`SELECT * FROM t1 order by f1;`).Check(testkit.Rows("1 0", "2 2")) + + tk.MustExec(`SET sql_mode='';`) + _, err = tk.Exec(`INSERT t1 VALUES (1, 1) ON DUPLICATE KEY UPDATE f2 = null;`) + c.Assert(err, NotNil) + tk.MustQuery(`SELECT * FROM t1 order by f1;`).Check(testkit.Rows("1 0", "2 2")) } func (s *testSuite) TestInsertIgnoreOnDup(c *C) { diff --git a/table/column.go b/table/column.go index 595429b19fb2b..bd2eb36bfe821 100644 --- a/table/column.go +++ b/table/column.go @@ -426,12 +426,17 @@ func getColDefaultValueFromNil(ctx sessionctx.Context, col *model.ColumnInfo) (t if col.IsGenerated() { return types.Datum{}, nil } - sc := ctx.GetSessionVars().StmtCtx + vars := ctx.GetSessionVars() + sc := vars.StmtCtx if sc.BadNullAsWarning { sc.AppendWarning(ErrColumnCantNull.GenWithStackByArgs(col.Name)) return GetZeroValue(col), nil } - return types.Datum{}, ErrNoDefaultValue.GenWithStack("Field '%s' doesn't have a default value", col.Name) + if !vars.StrictSQLMode { + sc.AppendWarning(ErrNoDefaultValue.GenWithStackByArgs(col.Name)) + return GetZeroValue(col), nil + } + return types.Datum{}, ErrNoDefaultValue.GenWithStackByArgs(col.Name) } // GetZeroValue gets zero value for given column type. diff --git a/table/table.go b/table/table.go index 0b56779825c37..788a194103998 100644 --- a/table/table.go +++ b/table/table.go @@ -58,7 +58,7 @@ var ( // ErrNoDefaultValue is used when insert a row, the column value is not given, and the column has not null flag // and it doesn't have a default value. - ErrNoDefaultValue = terror.ClassTable.New(codeNoDefaultValue, "field doesn't have a default value") + ErrNoDefaultValue = terror.ClassTable.New(codeNoDefaultValue, mysql.MySQLErrName[mysql.ErrNoDefaultForField]) // ErrIndexOutBound returns for index column offset out of bound. ErrIndexOutBound = terror.ClassTable.New(codeIndexOutBound, "index column offset out of bound") // ErrUnsupportedOp returns for unsupported operation. @@ -199,7 +199,7 @@ const ( codeColumnCantNull = mysql.ErrBadNull codeUnknownColumn = 1054 codeDuplicateColumn = 1110 - codeNoDefaultValue = 1364 + codeNoDefaultValue = mysql.ErrNoDefaultForField codeTruncateWrongValue = 1366 // MySQL error code, "Trigger creation context of table `%-.64s`.`%-.64s` is invalid". // It may happen when inserting some data outside of all table partitions.