diff --git a/parser/ast/ddl.go b/parser/ast/ddl.go index 03f07ac194ff4..762181745e3b4 100644 --- a/parser/ast/ddl.go +++ b/parser/ast/ddl.go @@ -525,10 +525,10 @@ const ( ) var ( - invalidOptionForGeneratedColumn = map[ColumnOptionType]struct{}{ - ColumnOptionAutoIncrement: {}, - ColumnOptionOnUpdate: {}, - ColumnOptionDefaultValue: {}, + invalidOptionForGeneratedColumn = map[ColumnOptionType]string{ + ColumnOptionAutoIncrement: "AUTO_INCREMENT", + ColumnOptionOnUpdate: "ON UPDATE", + ColumnOptionDefaultValue: "DEFAULT", } ) @@ -1007,17 +1007,22 @@ func (n *ColumnDef) Accept(v Visitor) (Node, bool) { // For example, generated column definitions that contain such // column options as `ON UPDATE`, `AUTO_INCREMENT`, `DEFAULT` // are illegal. -func (n *ColumnDef) Validate() bool { +func (n *ColumnDef) Validate() error { generatedCol := false - illegalOpt4gc := false + var illegalOpt4gc string for _, opt := range n.Options { if opt.Tp == ColumnOptionGenerated { generatedCol = true } - _, found := invalidOptionForGeneratedColumn[opt.Tp] - illegalOpt4gc = illegalOpt4gc || found + msg, found := invalidOptionForGeneratedColumn[opt.Tp] + if found { + illegalOpt4gc = msg + } + } + if generatedCol && illegalOpt4gc != "" { + return ErrWrongUsage.GenWithStackByArgs(illegalOpt4gc, "generated column") } - return !(generatedCol && illegalOpt4gc) + return nil } type TemporaryKeyword int @@ -3689,6 +3694,7 @@ var ( ErrWrongPartitionTypeExpectedSystemTime = terror.ClassDDL.NewStd(mysql.ErrWrongPartitionTypeExpectedSystemTime) ErrUnknownCharacterSet = terror.ClassDDL.NewStd(mysql.ErrUnknownCharacterSet) ErrCoalescePartitionNoPartition = terror.ClassDDL.NewStd(mysql.ErrCoalescePartitionNoPartition) + ErrWrongUsage = terror.ClassDDL.NewStd(mysql.ErrWrongUsage) ) type SubPartitionDefinition struct { diff --git a/parser/parser.go b/parser/parser.go index ba06d691e94bc..4798c5f453fd4 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -14012,8 +14012,8 @@ yynewstate: case 212: { colDef := &ast.ColumnDef{Name: yyS[yypt-2].item.(*ast.ColumnName), Tp: yyS[yypt-1].item.(*types.FieldType), Options: yyS[yypt-0].item.([]*ast.ColumnOption)} - if !colDef.Validate() { - yylex.AppendError(yylex.Errorf("Invalid column definition")) + if err := colDef.Validate(); err != nil { + yylex.AppendError(err) return 1 } parser.yyVAL.item = colDef @@ -14026,8 +14026,8 @@ yynewstate: options = append(options, yyS[yypt-0].item.([]*ast.ColumnOption)...) tp.AddFlag(mysql.UnsignedFlag) colDef := &ast.ColumnDef{Name: yyS[yypt-2].item.(*ast.ColumnName), Tp: tp, Options: options} - if !colDef.Validate() { - yylex.AppendError(yylex.Errorf("Invalid column definition")) + if err := colDef.Validate(); err != nil { + yylex.AppendError(err) return 1 } parser.yyVAL.item = colDef diff --git a/parser/parser.y b/parser/parser.y index e44dd6e4432fa..eaa8fe5e23110 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -3140,8 +3140,8 @@ ColumnDef: ColumnName Type ColumnOptionListOpt { colDef := &ast.ColumnDef{Name: $1.(*ast.ColumnName), Tp: $2.(*types.FieldType), Options: $3.([]*ast.ColumnOption)} - if !colDef.Validate() { - yylex.AppendError(yylex.Errorf("Invalid column definition")) + if err := colDef.Validate(); err != nil { + yylex.AppendError(err) return 1 } $$ = colDef @@ -3154,8 +3154,8 @@ ColumnDef: options = append(options, $3.([]*ast.ColumnOption)...) tp.AddFlag(mysql.UnsignedFlag) colDef := &ast.ColumnDef{Name: $1.(*ast.ColumnName), Tp: tp, Options: options} - if !colDef.Validate() { - yylex.AppendError(yylex.Errorf("Invalid column definition")) + if err := colDef.Validate(); err != nil { + yylex.AppendError(err) return 1 } $$ = colDef diff --git a/parser/parser_test.go b/parser/parser_test.go index 2229fe6e3fe45..7e1b3cb92bc8d 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -5716,6 +5716,13 @@ func TestGeneratedColumn(t *testing.T) { require.Error(t, err) } } + + _, _, err := p.Parse("create table t1 (a int, b int as (a + 1) default 10);", "", "") + require.Equal(t, err.Error(), "[ddl:1221]Incorrect usage of DEFAULT and generated column") + _, _, err = p.Parse("create table t1 (a int, b int as (a + 1) on update now());", "", "") + require.Equal(t, err.Error(), "[ddl:1221]Incorrect usage of ON UPDATE and generated column") + _, _, err = p.Parse("create table t1 (a int, b int as (a + 1) auto_increment);", "", "") + require.Equal(t, err.Error(), "[ddl:1221]Incorrect usage of AUTO_INCREMENT and generated column") } func TestSetTransaction(t *testing.T) {