From 964c6a325ad34985765753b9e8f402207e1318e8 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Tue, 5 Nov 2019 21:32:17 +0800 Subject: [PATCH 1/9] planner: Support use `on duplicate key update gc=default` on generated columns --- ddl/db_integration_test.go | 18 +++++++---- planner/core/planbuilder.go | 60 +++++++++++++++++++------------------ 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/ddl/db_integration_test.go b/ddl/db_integration_test.go index 6362082d0a58d..97fcb747f41a9 100644 --- a/ddl/db_integration_test.go +++ b/ddl/db_integration_test.go @@ -2043,11 +2043,19 @@ func (s *testIntegrationSuite3) TestInsertIntoGeneratedColumnWithDefaultExpr(c * tk.MustExec("create table t5 (a int default 10, b int as (a+1))") tk.MustGetErrCode("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") + // generated columns with `ON DUPLICATE KEY UPDATE b=DEFAULT` statement + tk.MustExec("create table t6 (a int unique, b int generated always as (-a) virtual, c int generated always as (-a) stored);") + tk.MustExec("insert into t6 values (1,default,default);") + tk.MustExec("insert into t6 values (1,default,default) on duplicate key update a=2, b=default;") + tk.MustQuery("select * from t6").Check(testkit.Rows("2 -2 -2")) + tk.MustExec("insert into t6 values (2,default,default) on duplicate key update a=3, c=default;") + tk.MustQuery("select * from t6").Check(testkit.Rows("3 -3 -3")) + tk.MustExec("insert into t6 values (3,default,default) on duplicate key update c=default, b=default, a=4;") + tk.MustQuery("select * from t6").Check(testkit.Rows("4 -4 -4")) + tk.MustExec("insert into t6 values (10,default,default) on duplicate key update b=default, a=20, c=default;") + tk.MustQuery("select * from t6").Check(testkit.Rows("4 -4 -4", "10 -10 -10")) + + tk.MustExec("drop table t1, t2, t3, t4, t5, t6") } func (s *testIntegrationSuite3) TestSqlFunctionsInGeneratedColumns(c *C) { diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 36961d66bc343..572149e2b3618 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1764,27 +1764,14 @@ func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) ( mockTablePlan.SetSchema(insertPlan.Schema4OnDuplicate) mockTablePlan.names = insertPlan.names4OnDuplicate - columnByName := make(map[string]*table.Column, len(insertPlan.Table.Cols())) - for _, col := range insertPlan.Table.Cols() { - columnByName[col.Name.L] = col - } - onDupColSet, dupCols, dupColNames, err := insertPlan.validateOnDup(insert.OnDuplicate, columnByName, tableInfo) - if err != nil { - return nil, err - } - for i, assign := range insert.OnDuplicate { - // Construct the function which calculates the assign value of the column. - expr, err1 := b.rewriteInsertOnDuplicateUpdate(ctx, assign.Expr, mockTablePlan, insertPlan) - if err1 != nil { - return nil, err1 - } - insertPlan.OnDuplicate = append(insertPlan.OnDuplicate, &expression.Assignment{ - Col: dupCols[i], - ColName: dupColNames[i].ColName, - Expr: expr, - }) - } + onDupColSet, err := insertPlan.ResolveOnDuplicate(insert.OnDuplicate, tableInfo, func(node ast.ExprNode) (expression.Expression, error) { + expr, err := b.rewriteInsertOnDuplicateUpdate(ctx, node, mockTablePlan, insertPlan) + if err != nil { + return nil, err + } + return expr, nil + }) // Calculate generated columns. mockTablePlan.schema = insertPlan.tableSchema @@ -1798,29 +1785,44 @@ func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) ( return insertPlan, err } -func (p *Insert) validateOnDup(onDup []*ast.Assignment, colMap map[string]*table.Column, tblInfo *model.TableInfo) (map[string]struct{}, []*expression.Column, types.NameSlice, error) { +func (p *Insert) ResolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.TableInfo, yield func(node ast.ExprNode) (expression.Expression, error)) (map[string]struct{}, error) { onDupColSet := make(map[string]struct{}, len(onDup)) - dupCols := make([]*expression.Column, 0, len(onDup)) - dupColNames := make(types.NameSlice, 0, len(onDup)) + colMap := make(map[string]*table.Column, len(p.Table.Cols())) + for _, col := range p.Table.Cols() { + colMap[col.Name.L] = col + } for _, assign := range onDup { // Check whether the column to be updated exists in the source table. idx, err := expression.FindFieldName(p.tableColNames, assign.Column) if err != nil { - return nil, nil, nil, err + return nil, err } else if idx < 0 { - return nil, nil, nil, ErrUnknownColumn.GenWithStackByArgs(assign.Column.OrigColName(), "field list") + return nil, ErrUnknownColumn.GenWithStackByArgs(assign.Column.OrigColName(), "field list") } // Check whether the column to be updated is the generated column. column := colMap[assign.Column.Name.L] if column.IsGenerated() { - return nil, nil, nil, ErrBadGeneratedColumn.GenWithStackByArgs(assign.Column.Name.O, tblInfo.Name.O) + // only `DEFAULT` can be assigned to generated columns + if _, ok := assign.Expr.(*ast.DefaultExpr); ok { + continue + } + return nil, ErrBadGeneratedColumn.GenWithStackByArgs(assign.Column.Name.O, tblInfo.Name.O) } onDupColSet[column.Name.L] = struct{}{} - dupCols = append(dupCols, p.tableSchema.Columns[idx]) - dupColNames = append(dupColNames, p.tableColNames[idx]) + + expr, err := yield(assign.Expr) + if err != nil { + return nil, err + } + + p.OnDuplicate = append(p.OnDuplicate, &expression.Assignment{ + Col: p.tableSchema.Columns[idx], + ColName: p.tableColNames[idx].ColName, + Expr: expr, + }) } - return onDupColSet, dupCols, dupColNames, nil + return onDupColSet, nil } func (b *PlanBuilder) getAffectCols(insertStmt *ast.InsertStmt, insertPlan *Insert) (affectedValuesCols []*table.Column, err error) { From 0ad2e5ee06d9fd754a119c3b34d542aa3e003c5f Mon Sep 17 00:00:00 2001 From: Deardrops Date: Tue, 5 Nov 2019 21:36:33 +0800 Subject: [PATCH 2/9] fixup CI --- planner/core/planbuilder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 572149e2b3618..e4f8faf5eac07 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1765,7 +1765,7 @@ func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) ( mockTablePlan.SetSchema(insertPlan.Schema4OnDuplicate) mockTablePlan.names = insertPlan.names4OnDuplicate - onDupColSet, err := insertPlan.ResolveOnDuplicate(insert.OnDuplicate, tableInfo, func(node ast.ExprNode) (expression.Expression, error) { + onDupColSet, err := insertPlan.resolveOnDuplicate(insert.OnDuplicate, tableInfo, func(node ast.ExprNode) (expression.Expression, error) { expr, err := b.rewriteInsertOnDuplicateUpdate(ctx, node, mockTablePlan, insertPlan) if err != nil { return nil, err @@ -1785,7 +1785,7 @@ func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) ( return insertPlan, err } -func (p *Insert) ResolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.TableInfo, yield func(node ast.ExprNode) (expression.Expression, error)) (map[string]struct{}, error) { +func (p *Insert) resolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.TableInfo, yield func(node ast.ExprNode) (expression.Expression, error)) (map[string]struct{}, error) { onDupColSet := make(map[string]struct{}, len(onDup)) colMap := make(map[string]*table.Column, len(p.Table.Cols())) for _, col := range p.Table.Cols() { From 04d71ec5b4f3a19abe0ae1379a5bf012402492e7 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Tue, 5 Nov 2019 21:39:45 +0800 Subject: [PATCH 3/9] fixup CI --- planner/core/planbuilder.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index e4f8faf5eac07..0eb1df3f0b508 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1772,6 +1772,9 @@ func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) ( } return expr, nil }) + if err != nil { + return nil, err + } // Calculate generated columns. mockTablePlan.schema = insertPlan.tableSchema @@ -1785,7 +1788,7 @@ func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) ( return insertPlan, err } -func (p *Insert) resolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.TableInfo, yield func(node ast.ExprNode) (expression.Expression, error)) (map[string]struct{}, error) { +func (p *Insert) resolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.TableInfo, yield func(ast.ExprNode) (expression.Expression, error)) (map[string]struct{}, error) { onDupColSet := make(map[string]struct{}, len(onDup)) colMap := make(map[string]*table.Column, len(p.Table.Cols())) for _, col := range p.Table.Cols() { From 3efeea0fd01ccd19f7fc1fee31f8e330e13386a9 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Tue, 5 Nov 2019 21:44:15 +0800 Subject: [PATCH 4/9] fixup CI --- planner/core/planbuilder.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 0eb1df3f0b508..b13608fca4c5c 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1766,11 +1766,7 @@ func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) ( mockTablePlan.names = insertPlan.names4OnDuplicate onDupColSet, err := insertPlan.resolveOnDuplicate(insert.OnDuplicate, tableInfo, func(node ast.ExprNode) (expression.Expression, error) { - expr, err := b.rewriteInsertOnDuplicateUpdate(ctx, node, mockTablePlan, insertPlan) - if err != nil { - return nil, err - } - return expr, nil + return b.rewriteInsertOnDuplicateUpdate(ctx, node, mockTablePlan, insertPlan) }) if err != nil { return nil, err From 9c04ddf23d6ed0e98e89b3f2e3059b2e0d666d13 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Tue, 12 Nov 2019 20:35:52 +0800 Subject: [PATCH 5/9] add more tests --- executor/write_test.go | 35 ++++++++++++++++++++++++++++ expression/expression.go | 7 +++--- planner/core/logical_plan_builder.go | 11 +++++++++ planner/core/planbuilder.go | 8 +++++-- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/executor/write_test.go b/executor/write_test.go index d63d4d8328aea..68f6a3e60fe03 100644 --- a/executor/write_test.go +++ b/executor/write_test.go @@ -749,6 +749,41 @@ func (s *testSuite4) TestInsertIgnoreOnDup(c *C) { r.Check(testkit.Rows("1 1", "2 2")) } +func (s *testSuite4) TestInsertOnDupUpdateDefault(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + // Assign `DEFAULT` in `INSERT ... ON DUPLICATE KEY UPDATE ...` statement + tk.MustExec("drop table if exists t1, t2;") + tk.MustExec("create table t1 (a int unique, b int default 20, c int default 30);") + tk.MustExec("insert into t1 values (1,default,default);") + tk.MustExec("insert into t1 values (1,default,default) on duplicate key update b=default;") + tk.MustQuery("select * from t1;").Check(testkit.Rows("1 20 30")) + tk.MustExec("insert into t1 values (1,default,default) on duplicate key update c=default, b=default;") + tk.MustQuery("select * from t1;").Check(testkit.Rows("1 20 30")) + tk.MustExec("insert into t1 values (1,default,default) on duplicate key update c=default, a=2") + tk.MustQuery("select * from t1;").Check(testkit.Rows("2 20 30")) + tk.MustExec("insert into t1 values (2,default,default) on duplicate key update c=default(b)") + tk.MustQuery("select * from t1;").Check(testkit.Rows("2 20 20")) + tk.MustExec("insert into t1 values (2,default,default) on duplicate key update a=default(b)+default(c)") + tk.MustQuery("select * from t1;").Check(testkit.Rows("50 20 20")) + // With generated columns + tk.MustExec("create table t2 (a int unique, b int generated always as (-a) virtual, c int generated always as (-a) stored);") + tk.MustExec("insert into t2 values (1,default,default);") + tk.MustExec("insert into t2 values (1,default,default) on duplicate key update a=2, b=default;") + tk.MustQuery("select * from t2").Check(testkit.Rows("2 -2 -2")) + tk.MustExec("insert into t2 values (2,default,default) on duplicate key update a=3, c=default;") + tk.MustQuery("select * from t2").Check(testkit.Rows("3 -3 -3")) + tk.MustExec("insert into t2 values (3,default,default) on duplicate key update c=default, b=default, a=4;") + tk.MustQuery("select * from t2").Check(testkit.Rows("4 -4 -4")) + tk.MustExec("insert into t2 values (10,default,default) on duplicate key update b=default, a=20, c=default;") + tk.MustQuery("select * from t2").Check(testkit.Rows("4 -4 -4", "10 -10 -10")) + tk.MustGetErrCode("insert into t2 values (4,default,default) on duplicate key update b=default(a);", mysql.ErrBadGeneratedColumn) + tk.MustGetErrCode("insert into t2 values (4,default,default) on duplicate key update a=default(b), b=default(b);", mysql.ErrBadGeneratedColumn) + tk.MustGetErrCode("insert into t2 values (4,default,default) on duplicate key update a=default(a), c=default(c);", mysql.ErrBadGeneratedColumn) + tk.MustGetErrCode("insert into t2 values (4,default,default) on duplicate key update a=default(a), c=default(a);", mysql.ErrBadGeneratedColumn) + tk.MustExec("drop table t1, t2") +} + func (s *testSuite4) TestReplace(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") diff --git a/expression/expression.go b/expression/expression.go index a0fbe3786964c..c08e535444d00 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -611,9 +611,10 @@ func ColumnInfos2ColumnsAndNames(ctx sessionctx.Context, dbName, tblName model.C continue } names = append(names, &types.FieldName{ - ColName: col.Name, - TblName: tblName, - DBName: dbName, + ColName: col.Name, + TblName: tblName, + DBName: dbName, + OrigTblName: tblName, }) newCol := &Column{ RetType: &col.FieldType, diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 7b566afc226fe..8290a5cd431b5 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -3101,6 +3101,17 @@ func (b *PlanBuilder) buildUpdateLists( return newList, p, allAssignmentsAreConstant, nil } +// extractDefaultExpr extract a `DefaultExpr` without any parameter from a `ExprNode` +// return it and if successful extract it +// Note the sql function `DEFAULT(a)` is not same with keyword `DEFAULT` +// Sql function `DEFAULT(a)` will return `false` +func extractDefaultExpr(node ast.ExprNode) (*ast.DefaultExpr, bool) { + if expr, ok := node.(*ast.DefaultExpr); ok && expr.Name == nil { + return expr, true + } + return nil, false +} + func (b *PlanBuilder) buildDelete(ctx context.Context, delete *ast.DeleteStmt) (Plan, error) { b.pushSelectOffset(0) b.pushTableHints(delete.TableHints, typeDelete, 0) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index d3714615e2453..0646d6e9cd9a6 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1834,13 +1834,17 @@ func (p *Insert) resolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.Tabl // Check whether the column to be updated is the generated column. column := colMap[assign.Column.Name.L] + defaultExpr, isDefaultExpr := extractDefaultExpr(assign.Expr) + if isDefaultExpr { + defaultExpr.Name = assign.Column + } if column.IsGenerated() { - // only `DEFAULT` can be assigned to generated columns - if _, ok := assign.Expr.(*ast.DefaultExpr); ok { + if isDefaultExpr { continue } return nil, ErrBadGeneratedColumn.GenWithStackByArgs(assign.Column.Name.O, tblInfo.Name.O) } + onDupColSet[column.Name.L] = struct{}{} expr, err := yield(assign.Expr) From 2f40feef95f71e6c7a446c6f0be76af058333a27 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Tue, 12 Nov 2019 20:39:01 +0800 Subject: [PATCH 6/9] cleanup test cases --- ddl/db_integration_test.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/ddl/db_integration_test.go b/ddl/db_integration_test.go index 97fcb747f41a9..305400d9a5912 100644 --- a/ddl/db_integration_test.go +++ b/ddl/db_integration_test.go @@ -2043,19 +2043,7 @@ func (s *testIntegrationSuite3) TestInsertIntoGeneratedColumnWithDefaultExpr(c * tk.MustExec("create table t5 (a int default 10, b int as (a+1))") tk.MustGetErrCode("insert into t5 values (20, default(a))", mysql.ErrBadGeneratedColumn) - // generated columns with `ON DUPLICATE KEY UPDATE b=DEFAULT` statement - tk.MustExec("create table t6 (a int unique, b int generated always as (-a) virtual, c int generated always as (-a) stored);") - tk.MustExec("insert into t6 values (1,default,default);") - tk.MustExec("insert into t6 values (1,default,default) on duplicate key update a=2, b=default;") - tk.MustQuery("select * from t6").Check(testkit.Rows("2 -2 -2")) - tk.MustExec("insert into t6 values (2,default,default) on duplicate key update a=3, c=default;") - tk.MustQuery("select * from t6").Check(testkit.Rows("3 -3 -3")) - tk.MustExec("insert into t6 values (3,default,default) on duplicate key update c=default, b=default, a=4;") - tk.MustQuery("select * from t6").Check(testkit.Rows("4 -4 -4")) - tk.MustExec("insert into t6 values (10,default,default) on duplicate key update b=default, a=20, c=default;") - tk.MustQuery("select * from t6").Check(testkit.Rows("4 -4 -4", "10 -10 -10")) - - tk.MustExec("drop table t1, t2, t3, t4, t5, t6") + tk.MustExec("drop table t1, t2, t3, t4, t5") } func (s *testIntegrationSuite3) TestSqlFunctionsInGeneratedColumns(c *C) { From 98d88b2f12d38a8ae391040ac1842b20d4b448f2 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Wed, 20 Nov 2019 19:01:16 -0800 Subject: [PATCH 7/9] address comment --- planner/core/logical_plan_builder.go | 17 ++++++++--------- planner/core/planbuilder.go | 20 ++++++++++++-------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 980365d8029ad..924363cf1e2d1 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -3020,7 +3020,7 @@ func (b *PlanBuilder) buildUpdateLists( columnFullName := fmt.Sprintf("%s.%s.%s", name.DBName.L, name.TblName.L, name.ColName.L) // We save a flag for the column in map `modifyColumns` // This flag indicated if assign keyword `DEFAULT` to the column - if _, ok := extractDefaultExpr(assign.Expr); ok { + if extractDefaultExpr(assign.Expr) != nil { modifyColumns[columnFullName] = true } else { modifyColumns[columnFullName] = false @@ -3073,7 +3073,7 @@ func (b *PlanBuilder) buildUpdateLists( var np LogicalPlan if i < len(list) { // If assign `DEFAULT` to column, fill the `defaultExpr.Name` before rewrite expression - if expr, ok := extractDefaultExpr(assign.Expr); ok { + if expr := extractDefaultExpr(assign.Expr); expr != nil { expr.Name = assign.Column } newExpr, np, err = b.rewrite(ctx, assign.Expr, p, nil, false) @@ -3115,15 +3115,14 @@ func (b *PlanBuilder) buildUpdateLists( return newList, p, allAssignmentsAreConstant, nil } -// extractDefaultExpr extract a `DefaultExpr` without any parameter from a `ExprNode`, -// return the `DefaultExpr` and whether it's extracted successfully. -// Note: the SQL function `DEFAULT(a)` is not the same with keyword `DEFAULT`, -// SQL function `DEFAULT(a)` will return `false`. -func extractDefaultExpr(node ast.ExprNode) (*ast.DefaultExpr, bool) { +// extractDefaultExpr extract a `DefaultExpr` from `ExprNode`, +// If it is a `DEFAULT` function like `DEFAULT(a)`, return nil. +// Only if it is `DEFAULT` keyword, it will return the `DefaultExpr`. +func extractDefaultExpr(node ast.ExprNode) *ast.DefaultExpr { if expr, ok := node.(*ast.DefaultExpr); ok && expr.Name == nil { - return expr, true + return expr } - return nil, false + return nil } func (b *PlanBuilder) buildDelete(ctx context.Context, delete *ast.DeleteStmt) (Plan, error) { diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 769c966698193..2157cc58eb953 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1866,12 +1866,15 @@ func (p *Insert) resolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.Tabl // Check whether the column to be updated is the generated column. column := colMap[assign.Column.Name.L] - defaultExpr, isDefaultExpr := extractDefaultExpr(assign.Expr) - if isDefaultExpr { - defaultExpr.Name = assign.Column + isDefault := false + if expr := extractDefaultExpr(assign.Expr); expr != nil { + expr.Name = assign.Column + isDefault = true } + // Note: For INSERT, REPLACE, and UPDATE, if a generated column is inserted into, replaced, or updated explicitly, the only permitted value is DEFAULT. + // see https://dev.mysql.com/doc/refman/8.0/en/create-table-generated-columns.html if column.IsGenerated() { - if isDefaultExpr { + if isDefault { continue } return nil, ErrBadGeneratedColumn.GenWithStackByArgs(assign.Column.Name.O, tblInfo.Name.O) @@ -1946,14 +1949,15 @@ func (b *PlanBuilder) buildSetValuesOfInsert(ctx context.Context, insert *ast.In insertPlan.AllAssignmentsAreConstant = true for i, assign := range insert.Setlist { - defaultExpr, isDefaultExpr := extractDefaultExpr(assign.Expr) - if isDefaultExpr { - defaultExpr.Name = assign.Column + isDefault := false + if expr := extractDefaultExpr(assign.Expr); expr != nil { + expr.Name = assign.Column + isDefault = true } // Note: For INSERT, REPLACE, and UPDATE, if a generated column is inserted into, replaced, or updated explicitly, the only permitted value is DEFAULT. // see https://dev.mysql.com/doc/refman/8.0/en/create-table-generated-columns.html if _, ok := generatedColumns[assign.Column.Name.L]; ok { - if isDefaultExpr { + if isDefault { continue } return ErrBadGeneratedColumn.GenWithStackByArgs(assign.Column.Name.O, tableInfo.Name.O) From d98ebbcc8d3757adeb5b2add94a10f73e61545f1 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Wed, 20 Nov 2019 19:35:25 -0800 Subject: [PATCH 8/9] address comment --- planner/core/planbuilder.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 2157cc58eb953..71cf456aeae78 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1866,15 +1866,14 @@ func (p *Insert) resolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.Tabl // Check whether the column to be updated is the generated column. column := colMap[assign.Column.Name.L] - isDefault := false - if expr := extractDefaultExpr(assign.Expr); expr != nil { - expr.Name = assign.Column - isDefault = true + var defaultExpr *ast.DefaultExpr + if defaultExpr = extractDefaultExpr(assign.Expr); defaultExpr != nil { + defaultExpr.Name = assign.Column } // Note: For INSERT, REPLACE, and UPDATE, if a generated column is inserted into, replaced, or updated explicitly, the only permitted value is DEFAULT. // see https://dev.mysql.com/doc/refman/8.0/en/create-table-generated-columns.html if column.IsGenerated() { - if isDefault { + if defaultExpr != nil { continue } return nil, ErrBadGeneratedColumn.GenWithStackByArgs(assign.Column.Name.O, tblInfo.Name.O) @@ -1949,15 +1948,14 @@ func (b *PlanBuilder) buildSetValuesOfInsert(ctx context.Context, insert *ast.In insertPlan.AllAssignmentsAreConstant = true for i, assign := range insert.Setlist { - isDefault := false - if expr := extractDefaultExpr(assign.Expr); expr != nil { - expr.Name = assign.Column - isDefault = true + var defaultExpr *ast.DefaultExpr + if defaultExpr = extractDefaultExpr(assign.Expr); defaultExpr != nil { + defaultExpr.Name = assign.Column } // Note: For INSERT, REPLACE, and UPDATE, if a generated column is inserted into, replaced, or updated explicitly, the only permitted value is DEFAULT. // see https://dev.mysql.com/doc/refman/8.0/en/create-table-generated-columns.html if _, ok := generatedColumns[assign.Column.Name.L]; ok { - if isDefault { + if defaultExpr != nil { continue } return ErrBadGeneratedColumn.GenWithStackByArgs(assign.Column.Name.O, tableInfo.Name.O) From 36e87c05dc7815a0e280455d9aeccdb7e0a4a5e3 Mon Sep 17 00:00:00 2001 From: Deardrops Date: Wed, 20 Nov 2019 19:48:20 -0800 Subject: [PATCH 9/9] address comment --- planner/core/planbuilder.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 71cf456aeae78..5155cd9f3d380 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -1866,8 +1866,8 @@ func (p *Insert) resolveOnDuplicate(onDup []*ast.Assignment, tblInfo *model.Tabl // Check whether the column to be updated is the generated column. column := colMap[assign.Column.Name.L] - var defaultExpr *ast.DefaultExpr - if defaultExpr = extractDefaultExpr(assign.Expr); defaultExpr != nil { + defaultExpr := extractDefaultExpr(assign.Expr) + if defaultExpr != nil { defaultExpr.Name = assign.Column } // Note: For INSERT, REPLACE, and UPDATE, if a generated column is inserted into, replaced, or updated explicitly, the only permitted value is DEFAULT. @@ -1948,8 +1948,8 @@ func (b *PlanBuilder) buildSetValuesOfInsert(ctx context.Context, insert *ast.In insertPlan.AllAssignmentsAreConstant = true for i, assign := range insert.Setlist { - var defaultExpr *ast.DefaultExpr - if defaultExpr = extractDefaultExpr(assign.Expr); defaultExpr != nil { + defaultExpr := extractDefaultExpr(assign.Expr) + if defaultExpr != nil { defaultExpr.Name = assign.Column } // Note: For INSERT, REPLACE, and UPDATE, if a generated column is inserted into, replaced, or updated explicitly, the only permitted value is DEFAULT.