Skip to content

Commit

Permalink
Updates migrations to check collation/charset before trying to fix it (
Browse files Browse the repository at this point in the history
…mattermost-community#4325)

* Updates migrations to check collation/charset before trying to fix it

* Update server/services/store/sqlstore/data_migrations.go

Co-authored-by: Doug Lauder <[email protected]>

Co-authored-by: Scott Bishel <[email protected]>
Co-authored-by: Doug Lauder <[email protected]>
  • Loading branch information
3 people authored Dec 13, 2022
1 parent 5d82fb8 commit f2d98f9
Showing 1 changed file with 29 additions and 8 deletions.
37 changes: 29 additions & 8 deletions server/services/store/sqlstore/data_migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ func (s *SQLStore) RunFixCollationsAndCharsetsMigration() error {
collation = "utf8mb4_general_ci"
charSet = "utf8mb4"
} else {
collation, charSet, err = s.getCollationAndCharset()
collation, charSet, err = s.getCollationAndCharset("Channels")
if err != nil {
return err
}
Expand All @@ -677,8 +677,27 @@ func (s *SQLStore) RunFixCollationsAndCharsetsMigration() error {

merr := merror.New()

// alter each table; this is idempotent
// alter each table if there is a collation or charset mismatch
for _, name := range tableNames {
tableCollation, tableCharSet, err := s.getCollationAndCharset(name)
if err != nil {
return err
}

if collation == tableCollation && charSet == tableCharSet {
// nothing to do
continue
}

s.logger.Warn(
"found collation/charset mismatch, fixing table",
mlog.String("tableName", name),
mlog.String("tableCollation", tableCollation),
mlog.String("tableCharSet", tableCharSet),
mlog.String("collation", collation),
mlog.String("charSet", charSet),
)

sql := fmt.Sprintf("ALTER TABLE %s CONVERT TO CHARACTER SET '%s' COLLATE '%s'", name, charSet, collation)
result, err := s.db.Exec(sql)
if err != nil {
Expand Down Expand Up @@ -731,33 +750,35 @@ func (s *SQLStore) getFocalBoardTableNames() ([]string, error) {
return names, nil
}

func (s *SQLStore) getCollationAndCharset() (string, string, error) {
func (s *SQLStore) getCollationAndCharset(tableName string) (string, string, error) {
if s.dbType != model.MysqlDBType {
return "", "", newErrInvalidDBType("getCollationAndCharset requires MySQL")
}

query := s.getQueryBuilder(s.db).
Select("table_collation").
From("information_schema.tables").
Where(sq.Eq{"table_name": "Channels"}).
Where(sq.Eq{"table_name": tableName}).
Where("table_schema=(SELECT DATABASE())")

row := query.QueryRow()

var collation string
err := row.Scan(&collation)
if err != nil {
return "", "", fmt.Errorf("error fetching collation: %w", err)
return "", "", fmt.Errorf("error fetching collation for table %s: %w", tableName, err)
}

// obtains the charset from the first column that has it set
query = s.getQueryBuilder(s.db).
Select("CHARACTER_SET_NAME").
From("information_schema.columns").
Where(sq.Eq{
"table_name": "Channels",
"COLUMN_NAME": "Name",
"table_name": tableName,
}).
Where("table_schema=(SELECT DATABASE())")
Where("table_schema=(SELECT DATABASE())").
Where(sq.NotEq{"CHARACTER_SET_NAME": "NULL"}).
Limit(1)

row = query.QueryRow()

Expand Down

0 comments on commit f2d98f9

Please sign in to comment.