Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

table: fix issue of get default value from column when column doesn't have default value (#51309) #51391

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion ddl/db_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1619,7 +1619,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", "<nil>"))

// for failing tests
sql := "alter table db_not_exist.test_alter_column alter column b set default 'c'"
Expand Down
101 changes: 101 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6340,3 +6340,104 @@ func TestProcessInfoOfSubQuery(t *testing.T) {
tk2.MustQuery("select 1 from information_schema.processlist where TxnStart != '' and info like 'select%sleep% from t%'").Check(testkit.Rows("1"))
wg.Wait()
}

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 <nil> <nil>", "2 <nil> <nil>", "3 <nil> <nil>"))

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 <nil> <nil>", "2 <nil> <nil>", "3 <nil> <nil>", "5 <nil> <nil>"))

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 <nil> <nil>", "2 <nil> <nil>", "3 <nil> <nil>", "4 <nil> <nil>", "5 <nil> <nil>", "6 <nil> <nil>"))
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 <nil> <nil>", "12 <nil> <nil>", "13 <nil> <nil>", "14 <nil> <nil>", "15 <nil> <nil>", "16 <nil> <nil>"))

// 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 <nil> <nil> 0 0", "21 1 <nil> 0 1", "22 1 <nil> 0 1"))
}
3 changes: 3 additions & 0 deletions executor/insert_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,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 {
Expand Down
2 changes: 1 addition & 1 deletion planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2130,7 +2130,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
Expand Down
9 changes: 7 additions & 2 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3561,14 +3561,19 @@ 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
)
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 {
Expand Down Expand Up @@ -3858,7 +3863,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,
Expand Down
46 changes: 30 additions & 16 deletions table/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,22 @@
return getColDefaultValue(ctx, col, col.GetOriginDefaultValue())
}

// 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()
Expand Down Expand Up @@ -580,38 +596,36 @@
}

func getColDefaultValueFromNil(ctx sessionctx.Context, col *model.ColumnInfo) (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

Check warning on line 607 in table/column.go

View check run for this annotation

Codecov / codecov/patch

table/column.go#L607

Added line #L607 was not covered by tests
}
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
}
vars := ctx.GetSessionVars()
sc := vars.StmtCtx
if !vars.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.FastGenByArgs(col.Name)
Expand Down
Loading