diff --git a/doc/requirements-and-limitations.md b/doc/requirements-and-limitations.md index c961706..e12f3f0 100644 --- a/doc/requirements-and-limitations.md +++ b/doc/requirements-and-limitations.md @@ -28,7 +28,9 @@ The `SUPER` privilege is required for `STOP SLAVE`, `START SLAVE` operations. Th - MySQL 5.7 generated columns are not supported. They may be supported in the future. -- MySQL 5.7 `JSON` columns are not supported. They are likely to be supported shortly. +- MySQL 5.7 `POINT` column type is not supported. + +- MySQL 5.7 `JSON` columns are supported but not as part of `PRIMARY KEY` - The two _before_ & _after_ tables must share a `PRIMARY KEY` or other `UNIQUE KEY`. This key will be used by `gh-ost` to iterate through the table rows when copying. [Read more](shared-key.md) - The migration key must not include columns with NULL values. This means either: diff --git a/go/logic/inspect.go b/go/logic/inspect.go index 5049193..b0088d5 100644 --- a/go/logic/inspect.go +++ b/go/logic/inspect.go @@ -545,6 +545,11 @@ func (this *Inspector) applyColumnTypes(databaseName, tableName string, columnsL columnsList.GetColumn(columnName).Type = sql.DateTimeColumnType } } + if strings.Contains(columnType, "json") { + for _, columnsList := range columnsLists { + columnsList.GetColumn(columnName).Type = sql.JSONColumnType + } + } if strings.HasPrefix(columnType, "enum") { for _, columnsList := range columnsLists { columnsList.GetColumn(columnName).Type = sql.EnumColumnType diff --git a/go/sql/builder.go b/go/sql/builder.go index 3bf9964..251a874 100644 --- a/go/sql/builder.go +++ b/go/sql/builder.go @@ -38,6 +38,8 @@ func buildColumnsPreparedValues(columns *ColumnList) []string { var token string if column.timezoneConversion != nil { token = fmt.Sprintf("convert_tz(?, '%s', '%s')", column.timezoneConversion.ToTimezone, "+00:00") + } else if column.Type == JSONColumnType { + token = "convert(? using utf8mb4)" } else { token = "?" } @@ -106,6 +108,8 @@ func BuildSetPreparedClause(columns *ColumnList) (result string, err error) { var setToken string if column.timezoneConversion != nil { setToken = fmt.Sprintf("%s=convert_tz(?, '%s', '%s')", EscapeName(column.Name), column.timezoneConversion.ToTimezone, "+00:00") + } else if column.Type == JSONColumnType { + setToken = fmt.Sprintf("%s=convert(? using utf8mb4)", EscapeName(column.Name)) } else { setToken = fmt.Sprintf("%s=?", EscapeName(column.Name)) } diff --git a/go/sql/types.go b/go/sql/types.go index 9f4f8e7..fd6b01d 100644 --- a/go/sql/types.go +++ b/go/sql/types.go @@ -20,6 +20,7 @@ const ( DateTimeColumnType = iota EnumColumnType = iota MediumIntColumnType = iota + JSONColumnType = iota ) const maxMediumintUnsigned int32 = 16777215 diff --git a/localtests/json57/create.sql b/localtests/json57/create.sql new file mode 100644 index 0000000..83dfe79 --- /dev/null +++ b/localtests/json57/create.sql @@ -0,0 +1,21 @@ +drop table if exists gh_ost_test; +create table gh_ost_test ( + id int auto_increment, + j json, + primary key(id) +) auto_increment=1; + +drop event if exists gh_ost_test; +delimiter ;; +create event gh_ost_test + on schedule every 1 second + starts current_timestamp + ends current_timestamp + interval 60 second + on completion not preserve + enable + do +begin + insert into gh_ost_test values (null, '"sometext"'); + insert into gh_ost_test values (null, '{"key":"val"}'); + insert into gh_ost_test values (null, '{"is-it": true, "count": 3, "elements": []}'); +end ;; diff --git a/localtests/json57dml/create.sql b/localtests/json57dml/create.sql new file mode 100644 index 0000000..da8cd57 --- /dev/null +++ b/localtests/json57dml/create.sql @@ -0,0 +1,27 @@ +drop table if exists gh_ost_test; +create table gh_ost_test ( + id int auto_increment, + i int not null, + updated tinyint not null default 0, + j json, + primary key(id) +) auto_increment=1; + +drop event if exists gh_ost_test; +delimiter ;; +create event gh_ost_test + on schedule every 1 second + starts current_timestamp + ends current_timestamp + interval 60 second + on completion not preserve + enable + do +begin + insert into gh_ost_test (id, i, j) values (null, 11, '"sometext"'); + insert into gh_ost_test (id, i, j) values (null, 13, '{"key":"val"}'); + insert into gh_ost_test (id, i, j) values (null, 17, '{"is-it": true, "count": 3, "elements": []}'); + + update gh_ost_test set j = '{"updated": 11}', updated = 1 where i = 11 and updated = 0; + update gh_ost_test set j = json_set(j, '$.count', 13, '$.id', id), updated = 1 where i = 13 and updated = 0; + delete from gh_ost_test where i = 17; +end ;;