diff --git a/ast/ddl.go b/ast/ddl.go index a8656ca4a..1e5395c42 100644 --- a/ast/ddl.go +++ b/ast/ddl.go @@ -477,6 +477,8 @@ type ColumnOption struct { AutoRandomBitLength int // Enforced is only for Check, default is true. Enforced bool + // Name is only used for Check Constraint name. + ConstraintName string } // Restore implements Node interface. @@ -534,6 +536,11 @@ func (n *ColumnOption) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("COLLATE ") ctx.WritePlain(n.StrValue) case ColumnOptionCheck: + if n.ConstraintName != "" { + ctx.WriteKeyWord("CONSTRAINT ") + ctx.WriteName(n.ConstraintName) + ctx.WritePlain(" ") + } ctx.WriteKeyWord("CHECK") ctx.WritePlain("(") if err := n.Expr.Restore(ctx); err != nil { @@ -702,6 +709,10 @@ type Constraint struct { Expr ExprNode // Used for Check Enforced bool // Used for Check + + InColumn bool // Used for Check + + InColumnName string // Used for Check } // Restore implements Node interface. diff --git a/model/model.go b/model/model.go index 97efe4322..5fe96d1a9 100644 --- a/model/model.go +++ b/model/model.go @@ -212,22 +212,24 @@ type TableInfo struct { Charset string `json:"charset"` Collate string `json:"collate"` // Columns are listed in the order in which they appear in the schema. - Columns []*ColumnInfo `json:"cols"` - Indices []*IndexInfo `json:"index_info"` - ForeignKeys []*FKInfo `json:"fk_info"` - State SchemaState `json:"state"` + Columns []*ColumnInfo `json:"cols"` + Indices []*IndexInfo `json:"index_info"` + Constraints []*ConstraintInfo `json:"constraint_info"` + ForeignKeys []*FKInfo `json:"fk_info"` + State SchemaState `json:"state"` // PKIsHandle is true when primary key is a single integer column. PKIsHandle bool `json:"pk_is_handle"` // IsCommonHandle is true when clustered index feature is // enabled and the primary key is not a single integer column. IsCommonHandle bool `json:"is_common_handle"` - Comment string `json:"comment"` - AutoIncID int64 `json:"auto_inc_id"` - AutoIdCache int64 `json:"auto_id_cache"` - AutoRandID int64 `json:"auto_rand_id"` - MaxColumnID int64 `json:"max_col_id"` - MaxIndexID int64 `json:"max_idx_id"` + Comment string `json:"comment"` + AutoIncID int64 `json:"auto_inc_id"` + AutoIdCache int64 `json:"auto_id_cache"` + AutoRandID int64 `json:"auto_rand_id"` + MaxColumnID int64 `json:"max_col_id"` + MaxIndexID int64 `json:"max_idx_id"` + MaxConstraintID int64 `json:"max_cst_id"` // UpdateTS is used to record the timestamp of updating the table's schema information. // These changing schema operations don't include 'truncate table' and 'rename table'. UpdateTS uint64 `json:"update_timestamp"` @@ -770,6 +772,27 @@ func (index *IndexInfo) HasPrefixIndex() bool { return false } +// ConstraintInfo provides meta data describing check-expression constraint. +type ConstraintInfo struct { + ID int64 `json:"id"` + Name CIStr `json:"constraint_name"` + Table CIStr `json:"tbl_name"` // Table name. + ConstraintCols []CIStr `json:"constraint_cols"` // Depended column names. + Enforced bool `json:"enforced"` + InColumn bool `json:"in_column"` // Indicate whether the constraint is column type check. + ExprString string `json:"expr_string"` + State SchemaState `json:"state"` +} + +// Clone clones ConstraintInfo. +func (ci *ConstraintInfo) Clone() *ConstraintInfo { + nci := *ci + + nci.ConstraintCols = make([]CIStr, len(ci.ConstraintCols)) + copy(nci.ConstraintCols, ci.ConstraintCols) + return &nci +} + // FKInfo provides meta data describing a foreign key constraint. type FKInfo struct { ID int64 `json:"id"` diff --git a/parser.go b/parser.go index f959bda85..704e8a7ff 100644 --- a/parser.go +++ b/parser.go @@ -10933,6 +10933,10 @@ yynewstate: Expr: yyS[yypt-2].expr, Enforced: true, } + // Keep the column type check constraint name. + if yyS[yypt-5].item != nil { + optionCheck.ConstraintName = yyS[yypt-5].item.(string) + } switch yyS[yypt-0].item.(int) { case 0: parser.yyVAL.item = []*ast.ColumnOption{optionCheck, {Tp: ast.ColumnOptionNotNull}} diff --git a/parser.y b/parser.y index ec7ee4806..d371bba10 100644 --- a/parser.y +++ b/parser.y @@ -2577,6 +2577,10 @@ ColumnOption: Expr: $4, Enforced: true, } + // Keep the column type check constraint name. + if $1 != nil { + optionCheck.ConstraintName = $1.(string) + } switch $6.(int) { case 0: $$ = []*ast.ColumnOption{optionCheck, {Tp: ast.ColumnOptionNotNull}} diff --git a/parser_test.go b/parser_test.go index 7513f2e56..53a9868db 100644 --- a/parser_test.go +++ b/parser_test.go @@ -2822,11 +2822,11 @@ func (s *testParserSuite) TestDDL(c *C) { {"ALTER TABLE ident ADD ( CONSTRAINT FOREIGN KEY ident ( EXECUTE ( 123 ) ) REFERENCES t ( a ) MATCH SIMPLE ON DELETE CASCADE ON UPDATE SET NULL )", true, "ALTER TABLE `ident` ADD COLUMN (CONSTRAINT `ident` FOREIGN KEY (`EXECUTE`(123)) REFERENCES `t`(`a`) MATCH SIMPLE ON DELETE CASCADE ON UPDATE SET NULL)"}, // for CONSTRAINT cont'd, the following tests are for another aspect of the incompatibility {"ALTER TABLE t ADD COLUMN a DATE CHECK ( a > 0 ) FIRST", true, "ALTER TABLE `t` ADD COLUMN `a` DATE CHECK(`a`>0) ENFORCED FIRST"}, - {"ALTER TABLE t ADD a1 int CONSTRAINT ident CHECK ( a1 > 1 ) REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE;", true, "ALTER TABLE `t` ADD COLUMN `a1` INT CHECK(`a1`>1) ENFORCED REFERENCES `b` ON DELETE CASCADE ON UPDATE CASCADE"}, + {"ALTER TABLE t ADD a1 int CONSTRAINT ident CHECK ( a1 > 1 ) REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE;", true, "ALTER TABLE `t` ADD COLUMN `a1` INT CONSTRAINT `ident` CHECK(`a1`>1) ENFORCED REFERENCES `b` ON DELETE CASCADE ON UPDATE CASCADE"}, {"ALTER TABLE t ADD COLUMN a DATE CONSTRAINT CHECK ( a > 0 ) FIRST", true, "ALTER TABLE `t` ADD COLUMN `a` DATE CHECK(`a`>0) ENFORCED FIRST"}, - {"ALTER TABLE t ADD a TINYBLOB CONSTRAINT ident CHECK ( 1>2 ) REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE", true, "ALTER TABLE `t` ADD COLUMN `a` TINYBLOB CHECK(1>2) ENFORCED REFERENCES `b` ON DELETE CASCADE ON UPDATE CASCADE"}, - {"ALTER TABLE t ADD a2 int CONSTRAINT ident CHECK (a2 > 1) ENFORCED", true, "ALTER TABLE `t` ADD COLUMN `a2` INT CHECK(`a2`>1) ENFORCED"}, - {"ALTER TABLE t ADD a2 int CONSTRAINT ident CHECK (a2 > 1) NOT ENFORCED", true, "ALTER TABLE `t` ADD COLUMN `a2` INT CHECK(`a2`>1) NOT ENFORCED"}, + {"ALTER TABLE t ADD a TINYBLOB CONSTRAINT ident CHECK ( 1>2 ) REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE", true, "ALTER TABLE `t` ADD COLUMN `a` TINYBLOB CONSTRAINT `ident` CHECK(1>2) ENFORCED REFERENCES `b` ON DELETE CASCADE ON UPDATE CASCADE"}, + {"ALTER TABLE t ADD a2 int CONSTRAINT ident CHECK (a2 > 1) ENFORCED", true, "ALTER TABLE `t` ADD COLUMN `a2` INT CONSTRAINT `ident` CHECK(`a2`>1) ENFORCED"}, + {"ALTER TABLE t ADD a2 int CONSTRAINT ident CHECK (a2 > 1) NOT ENFORCED", true, "ALTER TABLE `t` ADD COLUMN `a2` INT CONSTRAINT `ident` CHECK(`a2`>1) NOT ENFORCED"}, {"ALTER TABLE t ADD a2 int CONSTRAINT ident primary key REFERENCES b ON DELETE CASCADE ON UPDATE CASCADE;", false, ""}, {"ALTER TABLE t ADD a2 int CONSTRAINT ident primary key (a2))", false, ""}, {"ALTER TABLE t ADD a2 int CONSTRAINT ident unique key (a2))", false, ""},