diff --git a/ddl/db_integration_test.go b/ddl/db_integration_test.go index 45df0e8f4715d..2d9581ffd7d21 100644 --- a/ddl/db_integration_test.go +++ b/ddl/db_integration_test.go @@ -1959,3 +1959,65 @@ func (s *testIntegrationSuite4) TestDropAutoIncrementIndex(c *C) { dropIndexSQL = "alter table t1 drop index a" assertErrorCode(c, tk, dropIndexSQL, mysql.ErrWrongAutoKey) } + +func (s *testIntegrationSuite3) TestInsertIntoGeneratedColumnWithDefaultExpr(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("create database if not exists test") + tk.MustExec("use test") + + // insert into virtual / stored columns + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1 (a int, b int as (-a) virtual, c int as (-a) stored)") + tk.MustExec("insert into t1 values (1, default, default)") + tk.MustQuery("select * from t1").Check(testkit.Rows("1 -1 -1")) + tk.MustExec("delete from t1") + + // insert multiple rows + tk.MustExec("insert into t1(a,b) values (1, default), (2, default)") + tk.MustQuery("select * from t1").Check(testkit.Rows("1 -1 -1", "2 -2 -2")) + tk.MustExec("delete from t1") + + // insert into generated columns only + tk.MustExec("insert into t1(b) values (default)") + tk.MustQuery("select * from t1").Check(testkit.Rows(" ")) + tk.MustExec("delete from t1") + tk.MustExec("insert into t1(c) values (default)") + tk.MustQuery("select * from t1").Check(testkit.Rows(" ")) + tk.MustExec("delete from t1") + + // generated columns with index + tk.MustExec("drop table if exists t2") + tk.MustExec("create table t2 like t1") + tk.MustExec("alter table t2 add index idx1(a)") + tk.MustExec("alter table t2 add index idx2(b)") + tk.MustExec("insert into t2 values (1, default, default)") + tk.MustQuery("select * from t2").Check(testkit.Rows("1 -1 -1")) + tk.MustExec("delete from t2") + tk.MustExec("alter table t2 drop index idx1") + tk.MustExec("alter table t2 drop index idx2") + tk.MustExec("insert into t2 values (1, default, default)") + tk.MustQuery("select * from t2").Check(testkit.Rows("1 -1 -1")) + + // generated columns in different position + tk.MustExec("drop table if exists t3") + tk.MustExec("create table t3 (gc1 int as (r+1), gc2 int as (r+1) stored, gc3 int as (gc2+1), gc4 int as (gc1+1) stored, r int)") + tk.MustExec("insert into t3 values (default, default, default, default, 1)") + tk.MustQuery("select * from t3").Check(testkit.Rows("2 2 3 3 1")) + + // generated columns in replace statement + tk.MustExec("create table t4 (a int key, b int, c int as (a+1), d int as (b+1) stored)") + tk.MustExec("insert into t4 values (1, 10, default, default)") + tk.MustQuery("select * from t4").Check(testkit.Rows("1 10 2 11")) + tk.MustExec("replace into t4 values (1, 20, default, default)") + tk.MustQuery("select * from t4").Check(testkit.Rows("1 20 2 21")) + + // generated columns with default function is not allowed + tk.MustExec("create table t5 (a int default 10, b int as (a+1))") + assertErrorCode(c, tk, "insert into t5 values (20, default(a))", mysql.ErrBadGeneratedColumn) + + tk.MustExec("drop table t1") + tk.MustExec("drop table t2") + tk.MustExec("drop table t3") + tk.MustExec("drop table t4") + tk.MustExec("drop table t5") +} diff --git a/executor/insert_common.go b/executor/insert_common.go index 2b34afcf8735e..7fba881845d35 100644 --- a/executor/insert_common.go +++ b/executor/insert_common.go @@ -116,9 +116,6 @@ func (e *InsertValues) initInsertColumns() error { for _, v := range e.Columns { columns = append(columns, v.Name.O) } - for _, v := range e.GenColumns { - columns = append(columns, v.Name.O) - } cols, err = table.FindCols(tableCols, columns, e.Table.Meta().PKIsHandle) if err != nil { return errors.Errorf("INSERT INTO %s: %s", e.Table.Meta().Name.O, err) @@ -128,6 +125,9 @@ func (e *InsertValues) initInsertColumns() error { cols = tableCols } for _, col := range cols { + if !col.IsGenerated() { + e.insertColumns = append(e.insertColumns, col) + } if col.Name.L == model.ExtraHandleName.L { if !e.ctx.GetSessionVars().AllowWriteRowID { return errors.Errorf("insert, update and replace statements for _tidb_rowid are not supported.") @@ -142,7 +142,6 @@ func (e *InsertValues) initInsertColumns() error { if err != nil { return err } - e.insertColumns = cols return nil } diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index eaa70b419cd44..c1c4eb65e87dd 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1762,12 +1762,6 @@ func (b *PlanBuilder) buildValuesListOfInsert(ctx context.Context, insert *ast.I if len(insert.Lists[0]) != len(affectedValuesCols) { return ErrWrongValueCountOnRow.GenWithStackByArgs(1) } - // No generated column is allowed. - for _, col := range affectedValuesCols { - if col.IsGenerated() { - return ErrBadGeneratedColumn.GenWithStackByArgs(col.Name.O, insertPlan.Table.Meta().Name.O) - } - } } insertPlan.AllAssignmentsAreConstant = true @@ -1785,8 +1779,17 @@ func (b *PlanBuilder) buildValuesListOfInsert(ctx context.Context, insert *ast.I for j, valueItem := range valuesItem { var expr expression.Expression var err error + var generatedColumnWithDefaultExpr bool + col := affectedValuesCols[j] switch x := valueItem.(type) { case *ast.DefaultExpr: + if col.IsGenerated() { + if x.Name != nil { + return ErrBadGeneratedColumn.GenWithStackByArgs(col.Name.O, insertPlan.Table.Meta().Name.O) + } + generatedColumnWithDefaultExpr = true + break + } if x.Name != nil { expr, err = b.findDefaultValue(totalTableCols, x.Name) } else { @@ -1807,6 +1810,15 @@ func (b *PlanBuilder) buildValuesListOfInsert(ctx context.Context, insert *ast.I _, isConstant := expr.(*expression.Constant) insertPlan.AllAssignmentsAreConstant = isConstant } + // insert value into a generated column is not allowed + if col.IsGenerated() { + // but there is only one exception: + // it is allowed to insert the `default` value into a generated column + if generatedColumnWithDefaultExpr { + continue + } + return ErrBadGeneratedColumn.GenWithStackByArgs(col.Name.O, insertPlan.Table.Meta().Name.O) + } exprList = append(exprList, expr) } insertPlan.Lists = append(insertPlan.Lists, exprList)