diff --git a/pkg/ddl/db_integration_test.go b/pkg/ddl/db_integration_test.go index 5fcedeb4e2384..ddf3629275e5c 100644 --- a/pkg/ddl/db_integration_test.go +++ b/pkg/ddl/db_integration_test.go @@ -1172,7 +1172,10 @@ func TestAlterColumn(t *testing.T) { tk.MustExec("alter table test_alter_column alter column d set default null") tk.MustExec("alter table test_alter_column alter column a drop default") tk.MustGetErrCode("insert into test_alter_column set b = 'd', c = 'dd'", errno.ErrNoDefaultForField) - tk.MustQuery("select a from test_alter_column").Check(testkit.Rows("111", "222", "222", "123")) + tk.MustGetErrCode("insert into test_alter_column set a = DEFAULT, b = 'd', c = 'dd'", errno.ErrNoDefaultForField) + tk.MustGetErrCode("insert into test_alter_column values (DEFAULT, 'd', 'dd', DEFAULT)", errno.ErrNoDefaultForField) + tk.MustExec("insert into test_alter_column set a = NULL, b = 'd', c = 'dd'") + tk.MustQuery("select a from test_alter_column").Check(testkit.Rows("111", "222", "222", "123", "")) // for failing tests sql := "alter table db_not_exist.test_alter_column alter column b set default 'c'" diff --git a/pkg/executor/insert_common.go b/pkg/executor/insert_common.go index e8d48aaf45709..861ef511c0c0e 100644 --- a/pkg/executor/insert_common.go +++ b/pkg/executor/insert_common.go @@ -580,6 +580,9 @@ func (e *InsertValues) getColDefaultValue(idx int, col *table.Column) (d types.D if col.DefaultIsExpr && col.DefaultExpr != nil { defaultVal, err = table.EvalColDefaultExpr(e.Ctx(), col.ToInfo(), col.DefaultExpr) } else { + if err := table.CheckNoDefaultValueForInsert(e.Ctx().GetSessionVars().StmtCtx, col.ToInfo()); err != nil { + return types.Datum{}, err + } defaultVal, err = table.GetColDefaultValue(e.Ctx(), col.ToInfo()) } if err != nil { diff --git a/pkg/executor/test/executor/executor_test.go b/pkg/executor/test/executor/executor_test.go index d16d02a5148cb..fb8455e05421d 100644 --- a/pkg/executor/test/executor/executor_test.go +++ b/pkg/executor/test/executor/executor_test.go @@ -4352,3 +4352,104 @@ func TestIssues49377(t *testing.T) { "limit 1" + ");").Sort().Check(testkit.Rows("1 Furina 1", "1 Furina 1", "1 Furina 1", "2 Klee 1", "2 Klee 1", "3 Eula 1", "3 Eula 1")) } + +func TestIssue50043(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + // Test simplified case by update. + tk.MustExec("use test") + tk.MustExec("create table t (c1 boolean ,c2 decimal ( 37 , 17 ), unique key idx1 (c1 ,c2),unique key idx2 ( c1 ));") + tk.MustExec("insert into t values (0,NULL);") + tk.MustExec("alter table t alter column c2 drop default;") + tk.MustExec("update t set c2 = 5 where c1 = 0;") + tk.MustQuery("select * from t order by c1,c2").Check(testkit.Rows("0 5.00000000000000000")) + + // Test simplified case by insert on duplicate key update. + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (c1 boolean ,c2 decimal ( 37 , 17 ), unique key idx1 (c1 ,c2));") + tk.MustExec("alter table t alter column c2 drop default;") + tk.MustExec("alter table t add unique key idx4 ( c1 );") + tk.MustExec("insert into t values (0, NULL), (1, 1);") + tk.MustExec("insert into t values (0, 2) ,(1, 3) on duplicate key update c2 = 5;") + tk.MustQuery("show warnings").Check(testkit.Rows()) + tk.MustQuery("select * from t order by c1,c2").Check(testkit.Rows("0 5.00000000000000000", "1 5.00000000000000000")) + + // Test Issue 50043. + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (c1 boolean ,c2 decimal ( 37 , 17 ), unique key idx1 (c1 ,c2));") + tk.MustExec("alter table t alter column c2 drop default;") + tk.MustExec("alter table t add unique key idx4 ( c1 );") + tk.MustExec("insert into t values (0, NULL), (1, 1);") + tk.MustExec("insert ignore into t values (0, 2) ,(1, 3) on duplicate key update c2 = 5, c1 = 0") + tk.MustQuery("select * from t order by c1,c2").Check(testkit.Rows("0 5.00000000000000000", "1 1.00000000000000000")) +} + +func TestIssue51324(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t (id int key, a int, b enum('a', 'b'))") + tk.MustGetErrMsg("insert into t values ()", "[table:1364]Field 'id' doesn't have a default value") + tk.MustExec("insert into t set id = 1") + tk.MustExec("insert into t set id = 2, a = NULL, b = NULL") + tk.MustExec("insert into t set id = 3, a = DEFAULT, b = DEFAULT") + tk.MustQuery("select * from t order by id").Check(testkit.Rows("1 ", "2 ", "3 ")) + + tk.MustExec("alter table t alter column a drop default") + tk.MustExec("alter table t alter column b drop default") + tk.MustGetErrMsg("insert into t set id = 4;", "[table:1364]Field 'a' doesn't have a default value") + tk.MustExec("insert into t set id = 5, a = NULL, b = NULL;") + tk.MustGetErrMsg("insert into t set id = 6, a = DEFAULT, b = DEFAULT;", "[table:1364]Field 'a' doesn't have a default value") + tk.MustQuery("select * from t order by id").Check(testkit.Rows("1 ", "2 ", "3 ", "5 ")) + + tk.MustExec("insert ignore into t set id = 4;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'a' doesn't have a default value")) + tk.MustExec("insert ignore into t set id = 6, a = DEFAULT, b = DEFAULT;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'a' doesn't have a default value")) + tk.MustQuery("select * from t order by id").Check(testkit.Rows("1 ", "2 ", "3 ", "4 ", "5 ", "6 ")) + tk.MustExec("update t set id = id + 10") + tk.MustQuery("show warnings").Check(testkit.Rows()) + tk.MustQuery("select * from t order by id").Check(testkit.Rows("11 ", "12 ", "13 ", "14 ", "15 ", "16 ")) + + // Test not null case. + tk.MustExec("drop table t") + tk.MustExec("create table t (id int key, a int not null, b enum('a', 'b') not null)") + tk.MustGetErrMsg("insert into t values ()", "[table:1364]Field 'id' doesn't have a default value") + tk.MustGetErrMsg("insert into t set id = 1", "[table:1364]Field 'a' doesn't have a default value") + tk.MustGetErrMsg("insert into t set id = 2, a = NULL, b = NULL", "[table:1048]Column 'a' cannot be null") + tk.MustGetErrMsg("insert into t set id = 2, a = 2, b = NULL", "[table:1048]Column 'b' cannot be null") + tk.MustGetErrMsg("insert into t set id = 3, a = DEFAULT, b = DEFAULT", "[table:1364]Field 'a' doesn't have a default value") + tk.MustExec("alter table t alter column a drop default") + tk.MustExec("alter table t alter column b drop default") + tk.MustExec("insert ignore into t set id = 4;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'a' doesn't have a default value")) + tk.MustExec("insert ignore into t set id = 5, a = NULL, b = NULL;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1048 Column 'a' cannot be null", "Warning 1048 Column 'b' cannot be null")) + tk.MustExec("insert ignore into t set id = 6, a = 6, b = NULL;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1048 Column 'b' cannot be null")) + tk.MustExec("insert ignore into t set id = 7, a = DEFAULT, b = DEFAULT;") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'a' doesn't have a default value")) + tk.MustQuery("select * from t order by id").Check(testkit.Rows("4 0 a", "5 0 ", "6 6 ", "7 0 a")) + + // Test add column with OriginDefaultValue case. + tk.MustExec("drop table t") + tk.MustExec("create table t (id int, unique key idx (id))") + tk.MustExec("insert into t values (1)") + tk.MustExec("alter table t add column a int default 1") + tk.MustExec("alter table t add column b int default null") + tk.MustExec("alter table t add column c int not null") + tk.MustExec("alter table t add column d int not null default 1") + tk.MustExec("insert ignore into t (id) values (2)") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'c' doesn't have a default value")) + tk.MustExec("insert ignore into t (id) values (1),(2) on duplicate key update id = id+10") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'c' doesn't have a default value")) + tk.MustExec("alter table t alter column a drop default") + tk.MustExec("alter table t alter column b drop default") + tk.MustExec("alter table t alter column c drop default") + tk.MustExec("alter table t alter column d drop default") + tk.MustExec("insert ignore into t (id) values (3)") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'a' doesn't have a default value", "Warning 1364 Field 'b' doesn't have a default value", "Warning 1364 Field 'c' doesn't have a default value", "Warning 1364 Field 'd' doesn't have a default value")) + tk.MustExec("insert ignore into t (id) values (11),(12),(3) on duplicate key update id = id+10") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1364 Field 'a' doesn't have a default value", "Warning 1364 Field 'b' doesn't have a default value", "Warning 1364 Field 'c' doesn't have a default value", "Warning 1364 Field 'd' doesn't have a default value")) + tk.MustQuery("select * from t order by id").Check(testkit.Rows("13 0 0", "21 1 0 1", "22 1 0 1")) +} diff --git a/pkg/planner/core/expression_rewriter.go b/pkg/planner/core/expression_rewriter.go index f2a0cd05b0b2b..b249edd19eccb 100644 --- a/pkg/planner/core/expression_rewriter.go +++ b/pkg/planner/core/expression_rewriter.go @@ -2297,7 +2297,7 @@ func (er *expressionRewriter) evalDefaultExpr(v *ast.DefaultExpr) { } default: // for other columns, just use what it is - val, er.err = er.b.getDefaultValue(col) + val, er.err = er.b.getDefaultValue(col, false) } if er.err != nil { return diff --git a/pkg/planner/core/planbuilder.go b/pkg/planner/core/planbuilder.go index 8d3e6926965c4..930d64128aec8 100644 --- a/pkg/planner/core/planbuilder.go +++ b/pkg/planner/core/planbuilder.go @@ -3855,7 +3855,7 @@ func genAuthErrForGrantStmt(sctx sessionctx.Context, dbName string) error { return ErrDBaccessDenied.FastGenByArgs(u, h, dbName) } -func (b *PlanBuilder) getDefaultValue(col *table.Column) (*expression.Constant, error) { +func (b *PlanBuilder) getDefaultValue(col *table.Column, isInsert bool) (*expression.Constant, error) { var ( value types.Datum err error @@ -3863,6 +3863,11 @@ func (b *PlanBuilder) getDefaultValue(col *table.Column) (*expression.Constant, if col.DefaultIsExpr && col.DefaultExpr != nil { value, err = table.EvalColDefaultExpr(b.ctx, col.ToInfo(), col.DefaultExpr) } else { + if isInsert { + if err := table.CheckNoDefaultValueForInsert(b.ctx.GetSessionVars().StmtCtx, col.ToInfo()); err != nil { + return nil, err + } + } value, err = table.GetColDefaultValue(b.ctx, col.ToInfo()) } if err != nil { @@ -4151,7 +4156,7 @@ func (b PlanBuilder) getInsertColExpr(ctx context.Context, insertPlan *Insert, m // See note in the end of the function. Only default for generated columns are OK. return nil, nil } - outExpr, err = b.getDefaultValue(refCol) + outExpr, err = b.getDefaultValue(refCol, true) case *driver.ValueExpr: outExpr = &expression.Constant{ Value: x.Datum, diff --git a/pkg/table/column.go b/pkg/table/column.go index b7a3c95de27f9..7c315fe318a41 100644 --- a/pkg/table/column.go +++ b/pkg/table/column.go @@ -529,6 +529,22 @@ func GetColOriginDefaultValueWithoutStrictSQLMode(ctx sessionctx.Context, col *m }) } +// CheckNoDefaultValueForInsert checks if the column has no default value before insert data. +// CheckNoDefaultValueForInsert extracts the check logic from getColDefaultValueFromNil, +// since getColDefaultValueFromNil function is public path and both read/write and other places use it. +// But CheckNoDefaultValueForInsert logic should only check before insert. +func CheckNoDefaultValueForInsert(sc *stmtctx.StatementContext, col *model.ColumnInfo) error { + if mysql.HasNoDefaultValueFlag(col.GetFlag()) && !col.DefaultIsExpr && col.GetDefaultValue() == nil && col.GetType() != mysql.TypeEnum { + if !sc.BadNullAsWarning { + return ErrNoDefaultValue.GenWithStackByArgs(col.Name) + } + if !mysql.HasNotNullFlag(col.GetFlag()) { + sc.AppendWarning(ErrNoDefaultValue.FastGenByArgs(col.Name)) + } + } + return nil +} + // GetColDefaultValue gets default value of the column. func GetColDefaultValue(ctx sessionctx.Context, col *model.ColumnInfo) (types.Datum, error) { defaultValue := col.GetDefaultValue() @@ -617,22 +633,19 @@ func getColDefaultValue(ctx sessionctx.Context, col *model.ColumnInfo, defaultVa } func getColDefaultValueFromNil(ctx sessionctx.Context, col *model.ColumnInfo, args *getColOriginDefaultValue) (types.Datum, error) { - if !mysql.HasNotNullFlag(col.GetFlag()) && !mysql.HasNoDefaultValueFlag(col.GetFlag()) { + if !mysql.HasNotNullFlag(col.GetFlag()) { return types.Datum{}, nil } if col.GetType() == mysql.TypeEnum { // For enum type, if no default value and not null is set, // the default value is the first element of the enum list - if mysql.HasNotNullFlag(col.GetFlag()) { - defEnum, err := types.ParseEnumValue(col.FieldType.GetElems(), 1) - if err != nil { - return types.Datum{}, err - } - return types.NewCollateMysqlEnumDatum(defEnum, col.GetCollate()), nil + defEnum, err := types.ParseEnumValue(col.FieldType.GetElems(), 1) + if err != nil { + return types.Datum{}, err } - return types.Datum{}, nil + return types.NewCollateMysqlEnumDatum(defEnum, col.GetCollate()), nil } - if mysql.HasAutoIncrementFlag(col.GetFlag()) && !mysql.HasNoDefaultValueFlag(col.GetFlag()) { + if mysql.HasAutoIncrementFlag(col.GetFlag()) { // Auto increment column doesn't have default value and we should not return error. return GetZeroValue(col), nil } @@ -646,15 +659,16 @@ func getColDefaultValueFromNil(ctx sessionctx.Context, col *model.ColumnInfo, ar } if !strictSQLMode { sc.AppendWarning(ErrNoDefaultValue.FastGenByArgs(col.Name)) - if mysql.HasNotNullFlag(col.GetFlag()) { - return GetZeroValue(col), nil - } - if mysql.HasNoDefaultValueFlag(col.GetFlag()) { - return types.Datum{}, nil - } + return GetZeroValue(col), nil } if sc.BadNullAsWarning { - sc.AppendWarning(ErrColumnCantNull.FastGenByArgs(col.Name)) + var err error + if mysql.HasNoDefaultValueFlag(col.GetFlag()) { + err = ErrNoDefaultValue.FastGenByArgs(col.Name) + } else { + err = ErrColumnCantNull.FastGenByArgs(col.Name) + } + sc.AppendWarning(err) return GetZeroValue(col), nil } return types.Datum{}, ErrNoDefaultValue.GenWithStackByArgs(col.Name)