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

Fix/2802 support for mysql invisible attribute #3140

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sql/mysql/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ const (
currentTS = "current_timestamp"
defaultGen = "default_generated"
autoIncrement = "auto_increment"
invisible = "INVISIBLE"

virtual = "VIRTUAL"
stored = "STORED"
Expand Down
64 changes: 48 additions & 16 deletions sql/mysql/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ func (i *inspect) addColumn(s *schema.Schema, rows *sql.Rows) error {
if err != nil {
return err
}
// The column has an expression default value,
// and it is handled in Driver.addColumn.
if attr.autoinc {
a := &AutoIncrement{}
if !sqlx.Has(t.Attrs, a) {
Expand All @@ -307,6 +309,9 @@ func (i *inspect) addColumn(s *schema.Schema, rows *sql.Rows) error {
if attr.onUpdate != "" {
c.Attrs = append(c.Attrs, &OnUpdate{A: attr.onUpdate})
}
if attr.invisible {
c.Attrs = append(c.Attrs, &Invisible{})
}
if x := expr.String; x != "" {
if !i.Maria() {
x = unescape(x)
Expand Down Expand Up @@ -519,33 +524,56 @@ type extraAttr struct {
onUpdate string
generatedType string
defaultGenerated bool
invisible bool
}

var (
reGenerateType = regexp.MustCompile(`(?i)^(stored|persistent|virtual) generated$`)
reTimeOnUpdate = regexp.MustCompile(`(?i)^(?:default_generated )?on update (current_timestamp(?:\(\d?\))?)$`)
reTimeOnUpdate = regexp.MustCompile(`(?i)^(?:default_generated )?on update (current_timestamp(?:\(\d?\))?)$`)
reGenerateType = regexp.MustCompile(`(?i)^(virtual|stored|persistent)( generated)?|generated always as \((.*)\) (stored|virtual|persistent)$`)
reAutoIncrement = regexp.MustCompile(`(?i)\bauto_increment\b`)
reDefaultGen = regexp.MustCompile(`(?i)\bDEFAULT_GENERATED\b`)
reInvisible = regexp.MustCompile(`(?i)\bINVISIBLE\b`)
)

// parseExtra returns a parsed version of the EXTRA column
// from the INFORMATION_SCHEMA.COLUMNS table.
func parseExtra(extra string) (*extraAttr, error) {
attr := &extraAttr{}
switch el := strings.ToLower(extra); {
case el == "", el == "null":
case el == defaultGen:

if extra == "" || strings.ToLower(extra) == "null" {
return attr, nil
}

if reDefaultGen.MatchString(extra) {
attr.defaultGenerated = true
// The column has an expression default value,
// and it is handled in Driver.addColumn.
case el == autoIncrement:
}

if reAutoIncrement.MatchString(extra) {
attr.autoinc = true
case reTimeOnUpdate.MatchString(extra):
attr.onUpdate = reTimeOnUpdate.FindStringSubmatch(extra)[1]
case reGenerateType.MatchString(extra):
attr.generatedType = reGenerateType.FindStringSubmatch(extra)[1]
default:
return nil, fmt.Errorf("unknown extra column attribute %q", extra)
}
return attr, nil
}

if reInvisible.MatchString(extra) {
attr.invisible = true
}

if match := reTimeOnUpdate.FindStringSubmatch(extra); match != nil {
attr.onUpdate = match[1]
}

if match := reGenerateType.FindStringSubmatch(extra); match != nil {
if match[1] != "" {
attr.generatedType = strings.ToUpper(match[1])
} else if match[4] != "" {
attr.generatedType = strings.ToUpper(match[4])
}

}

if attr.defaultGenerated || attr.autoinc || attr.invisible || attr.onUpdate != "" || attr.generatedType != "" {
return attr, nil
}

return nil, fmt.Errorf("unknown extra column attribute %q", extra)
}

// showCreate sets and fixes schema elements that require information from
Expand Down Expand Up @@ -837,6 +865,10 @@ type (
V int64
}

Invisible struct {
schema.Attr
}

// CreateOptions attribute for describing extra options used with CREATE TABLE.
CreateOptions struct {
schema.Attr
Expand Down
23 changes: 15 additions & 8 deletions sql/mysql/inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,14 +506,16 @@ func TestDriver_InspectTable(t *testing.T) {
m.ExpectQuery(queryColumns).
WithArgs("public", "users").
WillReturnRows(sqltest.Rows(`
+------------+-------------+-------------+----------------+-------------+------------+----------------+-------------------+--------------------+----------------+--------------------------------------+
| TABLE_NAME | COLUMN_NAME | COLUMN_TYPE | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA | CHARACTER_SET_NAME | COLLATION_NAME | GENERATION_EXPRESSION |
+------------+-------------+-------------+----------------+-------------+------------+----------------+-------------------+--------------------+----------------+--------------------------------------+
| users | c1 | int | | NO | | NULL | | NULL | NULL | |
| users | c2 | int | | NO | | NULL | VIRTUAL GENERATED | NULL | NULL | ` + "(`c1` * `c1`)" + ` |
| users | c3 | int | | NO | | NULL | STORED GENERATED | NULL | NULL | ` + "(`c1` + `c2`)" + ` |
| users | c4 | varchar(20) | | NO | | NULL | STORED GENERATED | NULL | NULL | concat(_latin1\'\\\'\',_latin1\'"\') |
+------------+-------------+-------------+----------------+-------------+------------+----------------+-------------------+--------------------+----------------+--------------------------------------+
+------------+-------------+-------------+----------------+-------------+------------+--------------------------------------------+-----------------------------+--------------------+----------------+--------------------------------------+
| TABLE_NAME | COLUMN_NAME | COLUMN_TYPE | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA | CHARACTER_SET_NAME | COLLATION_NAME | GENERATION_EXPRESSION |
+------------+-------------+-------------+----------------+-------------+------------+--------------------------------------------+-----------------------------+--------------------+----------------+--------------------------------------+
| users | c1 | int | | NO | | NULL | | NULL | NULL | |
| users | c2 | int | | NO | | NULL | VIRTUAL GENERATED | NULL | NULL | ` + "(`c1` * `c1`)" + ` |
| users | c3 | int | | NO | | NULL | STORED GENERATED | NULL | NULL | ` + "(`c1` + `c2`)" + ` |
| users | c4 | varchar(20) | | NO | | NULL | STORED GENERATED | NULL | NULL | concat(_latin1\'\\\'\',_latin1\'"\') |
| users | c5 | varchar(50) | | NO | | NULL | STORED GENERATED INVISIBLE | NULL | NULL |` + "`char_length(`email`)`" + ` |
| users | c6 | varchar(20) | | NO | | concat(_latin1\'Hello \',` + "`name`" + `) | DEFAULT_GENERATED INVISIBLE | NULL | NULL | NULL |
+------------+-------------+-------------+----------------+-------------+------------+--------------------------------------------+-----------------------------+--------------------+----------------+--------------------------------------+
`))
m.noIndexes()
m.noFKs()
Expand All @@ -526,6 +528,11 @@ func TestDriver_InspectTable(t *testing.T) {
{Name: "c2", Type: &schema.ColumnType{Raw: "int", Type: &schema.IntegerType{T: "int"}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: "(`c1` * `c1`)", Type: "VIRTUAL"}}},
{Name: "c3", Type: &schema.ColumnType{Raw: "int", Type: &schema.IntegerType{T: "int"}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: "(`c1` + `c2`)", Type: "STORED"}}},
{Name: "c4", Type: &schema.ColumnType{Raw: "varchar(20)", Type: &schema.StringType{T: "varchar", Size: 20}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: "concat(_latin1'\\'',_latin1'\"')", Type: "STORED"}}},
{Name: "c5", Type: &schema.ColumnType{Raw: "varchar(50)", Type: &schema.StringType{T: "varchar", Size: 50}}, Attrs: []schema.Attr{
&Invisible{},
&schema.GeneratedExpr{Expr: "`char_length(`email`)`", Type: "STORED"},
}},
{Name: "c6", Type: &schema.ColumnType{Raw: "varchar(20)", Type: &schema.StringType{T: "varchar", Size: 20}}, Attrs: []schema.Attr{&Invisible{}}, Default: &schema.RawExpr{X: "(concat(_latin1'Hello ',`name`))"}},
}, t.Columns)
},
},
Expand Down
3 changes: 3 additions & 0 deletions sql/mysql/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,9 @@ func (s *state) column(b *sqlx.Builder, t *schema.Table, c *schema.Column) error
if a.V > 0 && !sqlx.Has(t.Attrs, &AutoIncrement{}) {
t.Attrs = append(t.Attrs, a)
}
case *Invisible:
b.P("INVISIBLE")

default:
s.attr(b, a)
}
Expand Down
12 changes: 12 additions & 0 deletions sql/mysql/sqlspec.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@ func convertColumn(spec *sqlspec.Column, _ *schema.Table) (*schema.Column, error
c.AddAttrs(&AutoIncrement{})
}
}
if attr, ok := spec.Attr("invisible"); ok {
b, err := attr.Bool()
if err != nil {
return nil, err
}
if b {
c.AddAttrs(&Invisible{})
}
}
if err := specutil.ConvertGenExpr(spec.Remain(), c, storedOrVirtual); err != nil {
return nil, err
}
Expand Down Expand Up @@ -384,6 +393,9 @@ func columnSpec(c *schema.Column, t *schema.Table) (*sqlspec.Column, error) {
if sqlx.Has(c.Attrs, &AutoIncrement{}) {
spec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.BoolAttr("auto_increment", true))
}
if sqlx.Has(c.Attrs, &Invisible{}) {
spec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.BoolAttr("invisible", true))
}
if x := (schema.GeneratedExpr{}); sqlx.Has(c.Attrs, &x) {
spec.Extra.Children = append(spec.Extra.Children, specutil.FromGenExpr(x, storedOrVirtual))
}
Expand Down
55 changes: 54 additions & 1 deletion sql/mysql/sqlspec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,25 @@ func TestSQLSpec(t *testing.T) {
column "price1" {
null = false
type = int


}
column "price2" {
null = false
type = int
auto_increment = true
}
column "price_deprecated" {
null = false
type = int
invisible = true

}
column "account_name" {
null = false
type = varchar(32)
default = "unknown"

}
column "account_type" {
null = false
Expand Down Expand Up @@ -151,6 +160,15 @@ schema "schema" {
},
Attrs: []schema.Attr{&AutoIncrement{}},
},
{
Name: "price_deprecated",
Type: &schema.ColumnType{
Type: &schema.IntegerType{
T: TypeInt,
},
},
Attrs: []schema.Attr{&Invisible{}},
},
{
Name: "account_name",
Type: &schema.ColumnType{
Expand Down Expand Up @@ -269,7 +287,7 @@ schema "schema" {
{
Symbol: "accounts",
Table: exp.Tables[0],
Columns: []*schema.Column{exp.Tables[0].Columns[4]},
Columns: []*schema.Column{exp.Tables[0].Columns[5]},
RefTable: exp.Tables[1],
RefColumns: []*schema.Column{exp.Tables[1].Columns[0]},
OnDelete: schema.SetNull,
Expand Down Expand Up @@ -522,6 +540,41 @@ schema "test" {
`
require.EqualValues(t, expected, string(buf))
}
func TestMarshalSpec_Invisible(t *testing.T) {
s := &schema.Schema{
Name: "test",
Tables: []*schema.Table{
{
Name: "users",
Columns: []*schema.Column{
{
Name: "id",
Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}},
Attrs: []schema.Attr{
&Invisible{},
},
},
},
},
},
}
s.Tables[0].Schema = s
buf, err := MarshalSpec(s, hclState)
require.NoError(t, err)
const expected = `table "users" {
schema = schema.test
column "id" {
null = false
type = bigint
invisible = true
}
}
schema "test" {
}
`
require.EqualValues(t, expected, string(buf))
}


func TestMarshalSpec_Check(t *testing.T) {
s := schema.New("test").
Expand Down