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

planner: allow insert default into generated columns #11901

Merged
merged 8 commits into from
Aug 30, 2019
Merged
62 changes: 62 additions & 0 deletions ddl/db_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1931,3 +1931,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("<nil> <nil> <nil>"))
tk.MustExec("delete from t1")
tk.MustExec("insert into t1(c) values (default)")
tk.MustQuery("select * from t1").Check(testkit.Rows("<nil> <nil> <nil>"))
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")
}
7 changes: 3 additions & 4 deletions executor/insert_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.")
Expand All @@ -142,7 +142,6 @@ func (e *InsertValues) initInsertColumns() error {
if err != nil {
return err
}
e.insertColumns = cols
return nil
}

Expand Down
24 changes: 18 additions & 6 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1755,12 +1755,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
Expand All @@ -1778,8 +1772,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 {
Expand All @@ -1800,6 +1803,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)
Expand Down