Updates migrations to check collation/charset before trying to fix it (#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 <wiggin77@warpmail.net>

Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>
Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
This commit is contained in:
Miguel de la Cruz 2022-12-13 20:28:57 +01:00 committed by GitHub
parent 5d82fb8181
commit f2d98f940f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -663,7 +663,7 @@ func (s *SQLStore) RunFixCollationsAndCharsetsMigration() error {
collation = "utf8mb4_general_ci" collation = "utf8mb4_general_ci"
charSet = "utf8mb4" charSet = "utf8mb4"
} else { } else {
collation, charSet, err = s.getCollationAndCharset() collation, charSet, err = s.getCollationAndCharset("Channels")
if err != nil { if err != nil {
return err return err
} }
@ -677,8 +677,27 @@ func (s *SQLStore) RunFixCollationsAndCharsetsMigration() error {
merr := merror.New() merr := merror.New()
// alter each table; this is idempotent // alter each table if there is a collation or charset mismatch
for _, name := range tableNames { 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) sql := fmt.Sprintf("ALTER TABLE %s CONVERT TO CHARACTER SET '%s' COLLATE '%s'", name, charSet, collation)
result, err := s.db.Exec(sql) result, err := s.db.Exec(sql)
if err != nil { if err != nil {
@ -731,7 +750,7 @@ func (s *SQLStore) getFocalBoardTableNames() ([]string, error) {
return names, nil return names, nil
} }
func (s *SQLStore) getCollationAndCharset() (string, string, error) { func (s *SQLStore) getCollationAndCharset(tableName string) (string, string, error) {
if s.dbType != model.MysqlDBType { if s.dbType != model.MysqlDBType {
return "", "", newErrInvalidDBType("getCollationAndCharset requires MySQL") return "", "", newErrInvalidDBType("getCollationAndCharset requires MySQL")
} }
@ -739,7 +758,7 @@ func (s *SQLStore) getCollationAndCharset() (string, string, error) {
query := s.getQueryBuilder(s.db). query := s.getQueryBuilder(s.db).
Select("table_collation"). Select("table_collation").
From("information_schema.tables"). From("information_schema.tables").
Where(sq.Eq{"table_name": "Channels"}). Where(sq.Eq{"table_name": tableName}).
Where("table_schema=(SELECT DATABASE())") Where("table_schema=(SELECT DATABASE())")
row := query.QueryRow() row := query.QueryRow()
@ -747,17 +766,19 @@ func (s *SQLStore) getCollationAndCharset() (string, string, error) {
var collation string var collation string
err := row.Scan(&collation) err := row.Scan(&collation)
if err != nil { 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). query = s.getQueryBuilder(s.db).
Select("CHARACTER_SET_NAME"). Select("CHARACTER_SET_NAME").
From("information_schema.columns"). From("information_schema.columns").
Where(sq.Eq{ Where(sq.Eq{
"table_name": "Channels", "table_name": tableName,
"COLUMN_NAME": "Name",
}). }).
Where("table_schema=(SELECT DATABASE())") Where("table_schema=(SELECT DATABASE())").
Where(sq.NotEq{"CHARACTER_SET_NAME": "NULL"}).
Limit(1)
row = query.QueryRow() row = query.QueryRow()