Skip to content

Commit

Permalink
Merge pull request #8275 from planetscale/online-ddl-vrepl-enum-to-va…
Browse files Browse the repository at this point in the history
…rchar

Online DDL/Vreplication suite: support ENUM->VARCHAR/TEXT type change
  • Loading branch information
shlomi-noach authored Jun 15, 2021
2 parents c86fd3e + 516f2df commit c5bdbc6
Show file tree
Hide file tree
Showing 18 changed files with 737 additions and 354 deletions.
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ github.com/spyzhov/ajson v0.4.2 h1:JMByd/jZApPKDvNsmO90X2WWGbmT2ahDFp73QhZbg3s=
github.com/spyzhov/ajson v0.4.2/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id, i, e2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
change e e2 varchar(32) not null default ''
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id, i, e
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
drop table if exists onlineddl_test;
create table onlineddl_test (
id int auto_increment,
i int not null,
e enum('red', 'green', 'blue', 'orange') null default null collate 'utf8_bin',
primary key(id)
) auto_increment=1;

insert into onlineddl_test values (null, 7, 'red');

drop event if exists onlineddl_test;
delimiter ;;
create event onlineddl_test
on schedule every 1 second
starts current_timestamp
ends current_timestamp + interval 60 second
on completion not preserve
enable
do
begin
insert into onlineddl_test values (null, 11, 'red');
insert into onlineddl_test values (null, 13, 'green');
insert into onlineddl_test values (null, 17, 'blue');
set @last_insert_id := last_insert_id();
update onlineddl_test set e='orange' where id = @last_insert_id;
end ;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
change e e varchar(32) not null default ''
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
drop table if exists onlineddl_test;
create table onlineddl_test (
id int auto_increment,
i int not null,
e enum('red', 'green', 'blue', 'orange') null default null collate 'utf8_bin',
primary key(id)
) auto_increment=1;

insert into onlineddl_test values (null, 7, 'red');

drop event if exists onlineddl_test;
delimiter ;;
create event onlineddl_test
on schedule every 1 second
starts current_timestamp
ends current_timestamp + interval 60 second
on completion not preserve
enable
do
begin
insert into onlineddl_test values (null, 11, 'red');
insert into onlineddl_test values (null, 13, 'green');
insert into onlineddl_test values (null, 17, 'blue');
set @last_insert_id := last_insert_id();
update onlineddl_test set e='orange' where id = @last_insert_id;
end ;;
631 changes: 326 additions & 305 deletions go/vt/proto/binlogdata/binlogdata.pb.go

Large diffs are not rendered by default.

154 changes: 154 additions & 0 deletions go/vt/proto/binlogdata/binlogdata_vtproto.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions go/vt/schema/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ package schema
import (
"fmt"
"regexp"
"strconv"
"strings"

"vitess.io/vitess/go/textutil"
"vitess.io/vitess/go/vt/sqlparser"
)

Expand Down Expand Up @@ -51,6 +53,8 @@ var (
}
createTableRegexp = regexp.MustCompile(`(?s)(?i)(CREATE\s+TABLE\s+)` + "`" + `([^` + "`" + `]+)` + "`" + `(\s*[(].*$)`)
revertStatementRegexp = regexp.MustCompile(`(?i)^revert\s+([\S]*)$`)

enumValuesRegexp = regexp.MustCompile("(?i)^enum[(](.*)[)]$")
)

// ReplaceTableNameInCreateTableStatement returns a modified CREATE TABLE statement, such that the table name is replaced with given name.
Expand Down Expand Up @@ -101,3 +105,35 @@ func legacyParseRevertUUID(sql string) (uuid string, err error) {
}
return uuid, nil
}

// ParseEnumValues parses the comma delimited part of an enum column definition
func ParseEnumValues(enumColumnType string) string {
if submatch := enumValuesRegexp.FindStringSubmatch(enumColumnType); len(submatch) > 0 {
return submatch[1]
}
return enumColumnType
}

// ParseEnumTokens parses the comma delimited part of an enum column definition and
// returns the (unquoted) text values
func ParseEnumTokens(enumValues string) []string {
enumValues = ParseEnumValues(enumValues)
tokens := textutil.SplitDelimitedList(enumValues)
for i := range tokens {
if strings.HasPrefix(tokens[i], `'`) && strings.HasSuffix(tokens[i], `'`) {
tokens[i] = strings.Trim(tokens[i], `'`)
}
}
return tokens
}

// ParseEnumTokensMap parses the comma delimited part of an enum column definition
// and returns a map where ["1"] is the first token, and ["<n>"] is th elast token
func ParseEnumTokensMap(enumValues string) map[string]string {
tokens := ParseEnumTokens(enumValues)
tokensMap := map[string]string{}
for i, token := range tokens {
tokensMap[strconv.Itoa(i+1)] = token
}
return tokensMap
}
55 changes: 55 additions & 0 deletions go/vt/schema/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,58 @@ func TestLegacyParseRevertUUID(t *testing.T) {
assert.Error(t, err)
}
}

func TestParseEnumValues(t *testing.T) {
{
inputs := []string{
`enum('x-small','small','medium','large','x-large')`,
`ENUM('x-small','small','medium','large','x-large')`,
`'x-small','small','medium','large','x-large'`,
}
for _, input := range inputs {
enumValues := ParseEnumValues(input)
assert.Equal(t, `'x-small','small','medium','large','x-large'`, enumValues)
}
}
{
inputs := []string{
``,
`abc`,
`func('x-small','small','medium','large','x-large')`,
}
for _, input := range inputs {
enumValues := ParseEnumValues(input)
assert.Equal(t, input, enumValues)
}
}
}

func TestParseEnumTokens(t *testing.T) {
inputs := []string{
`enum('x-small','small','medium','large','x-large')`,
`'x-small','small','medium','large','x-large'`,
}
for _, input := range inputs {
enumTokens := ParseEnumTokens(input)
expect := []string{"x-small", "small", "medium", "large", "x-large"}
assert.Equal(t, expect, enumTokens)
}
}

func TestParseEnumTokensMap(t *testing.T) {
inputs := []string{
`enum('x-small','small','medium','large','x-large')`,
`'x-small','small','medium','large','x-large'`,
}
for _, input := range inputs {
enumTokensMap := ParseEnumTokensMap(input)
expect := map[string]string{
"1": "x-small",
"2": "small",
"3": "medium",
"4": "large",
"5": "x-large",
}
assert.Equal(t, expect, enumTokensMap)
}
}
Loading

0 comments on commit c5bdbc6

Please sign in to comment.