github.com/keys-pub/mattermost-server@v4.10.10+incompatible/store/sqlstore/upgrade.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "os" 10 "strings" 11 "time" 12 13 "github.com/mattermost/mattermost-server/mlog" 14 "github.com/mattermost/mattermost-server/model" 15 ) 16 17 const ( 18 VERSION_4_10_0 = "4.10.0" 19 VERSION_4_9_0 = "4.9.0" 20 VERSION_4_8_1 = "4.8.1" 21 VERSION_4_8_0 = "4.8.0" 22 VERSION_4_7_2 = "4.7.2" 23 VERSION_4_7_1 = "4.7.1" 24 VERSION_4_7_0 = "4.7.0" 25 VERSION_4_6_0 = "4.6.0" 26 VERSION_4_5_0 = "4.5.0" 27 VERSION_4_4_0 = "4.4.0" 28 VERSION_4_3_0 = "4.3.0" 29 VERSION_4_2_0 = "4.2.0" 30 VERSION_4_1_0 = "4.1.0" 31 VERSION_4_0_0 = "4.0.0" 32 VERSION_3_10_0 = "3.10.0" 33 VERSION_3_9_0 = "3.9.0" 34 VERSION_3_8_0 = "3.8.0" 35 VERSION_3_7_0 = "3.7.0" 36 VERSION_3_6_0 = "3.6.0" 37 VERSION_3_5_0 = "3.5.0" 38 VERSION_3_4_0 = "3.4.0" 39 VERSION_3_3_0 = "3.3.0" 40 VERSION_3_2_0 = "3.2.0" 41 VERSION_3_1_0 = "3.1.0" 42 VERSION_3_0_0 = "3.0.0" 43 OLDEST_SUPPORTED_VERSION = VERSION_3_0_0 44 ) 45 46 const ( 47 EXIT_VERSION_SAVE_MISSING = 1001 48 EXIT_TOO_OLD = 1002 49 EXIT_VERSION_SAVE = 1003 50 EXIT_THEME_MIGRATION = 1004 51 ) 52 53 func UpgradeDatabase(sqlStore SqlStore) { 54 55 UpgradeDatabaseToVersion31(sqlStore) 56 UpgradeDatabaseToVersion32(sqlStore) 57 UpgradeDatabaseToVersion33(sqlStore) 58 UpgradeDatabaseToVersion34(sqlStore) 59 UpgradeDatabaseToVersion35(sqlStore) 60 UpgradeDatabaseToVersion36(sqlStore) 61 UpgradeDatabaseToVersion37(sqlStore) 62 UpgradeDatabaseToVersion38(sqlStore) 63 UpgradeDatabaseToVersion39(sqlStore) 64 UpgradeDatabaseToVersion310(sqlStore) 65 UpgradeDatabaseToVersion40(sqlStore) 66 UpgradeDatabaseToVersion41(sqlStore) 67 UpgradeDatabaseToVersion42(sqlStore) 68 UpgradeDatabaseToVersion43(sqlStore) 69 UpgradeDatabaseToVersion44(sqlStore) 70 UpgradeDatabaseToVersion45(sqlStore) 71 UpgradeDatabaseToVersion46(sqlStore) 72 UpgradeDatabaseToVersion47(sqlStore) 73 UpgradeDatabaseToVersion471(sqlStore) 74 UpgradeDatabaseToVersion472(sqlStore) 75 UpgradeDatabaseToVersion48(sqlStore) 76 UpgradeDatabaseToVersion481(sqlStore) 77 UpgradeDatabaseToVersion49(sqlStore) 78 UpgradeDatabaseToVersion410(sqlStore) 79 80 // If the SchemaVersion is empty this this is the first time it has ran 81 // so lets set it to the current version. 82 if sqlStore.GetCurrentSchemaVersion() == "" { 83 if result := <-sqlStore.System().SaveOrUpdate(&model.System{Name: "Version", Value: model.CurrentVersion}); result.Err != nil { 84 mlog.Critical(result.Err.Error()) 85 time.Sleep(time.Second) 86 os.Exit(EXIT_VERSION_SAVE_MISSING) 87 } 88 89 mlog.Info(fmt.Sprintf("The database schema has been set to version %v", model.CurrentVersion)) 90 } 91 92 // If we're not on the current version then it's too old to be upgraded 93 if sqlStore.GetCurrentSchemaVersion() != model.CurrentVersion { 94 mlog.Critical(fmt.Sprintf("Database schema version %v is no longer supported. This Mattermost server supports automatic upgrades from schema version %v through schema version %v. Downgrades are not supported. Please manually upgrade to at least version %v before continuing", sqlStore.GetCurrentSchemaVersion(), OLDEST_SUPPORTED_VERSION, model.CurrentVersion, OLDEST_SUPPORTED_VERSION)) 95 time.Sleep(time.Second) 96 os.Exit(EXIT_TOO_OLD) 97 } 98 } 99 100 func saveSchemaVersion(sqlStore SqlStore, version string) { 101 if result := <-sqlStore.System().Update(&model.System{Name: "Version", Value: version}); result.Err != nil { 102 mlog.Critical(result.Err.Error()) 103 time.Sleep(time.Second) 104 os.Exit(EXIT_VERSION_SAVE) 105 } 106 107 mlog.Warn(fmt.Sprintf("The database schema has been upgraded to version %v", version)) 108 } 109 110 func shouldPerformUpgrade(sqlStore SqlStore, currentSchemaVersion string, expectedSchemaVersion string) bool { 111 if sqlStore.GetCurrentSchemaVersion() == currentSchemaVersion { 112 mlog.Warn(fmt.Sprintf("The database schema version of %v appears to be out of date", currentSchemaVersion)) 113 mlog.Warn(fmt.Sprintf("Attempting to upgrade the database schema version to %v", expectedSchemaVersion)) 114 115 return true 116 } 117 118 return false 119 } 120 121 func UpgradeDatabaseToVersion31(sqlStore SqlStore) { 122 if shouldPerformUpgrade(sqlStore, VERSION_3_0_0, VERSION_3_1_0) { 123 sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "") 124 saveSchemaVersion(sqlStore, VERSION_3_1_0) 125 } 126 } 127 128 func UpgradeDatabaseToVersion32(sqlStore SqlStore) { 129 if shouldPerformUpgrade(sqlStore, VERSION_3_1_0, VERSION_3_2_0) { 130 sqlStore.CreateColumnIfNotExists("TeamMembers", "DeleteAt", "bigint(20)", "bigint", "0") 131 132 saveSchemaVersion(sqlStore, VERSION_3_2_0) 133 } 134 } 135 136 func themeMigrationFailed(err error) { 137 mlog.Critical(fmt.Sprintf("Failed to migrate User.ThemeProps to Preferences table %v", err)) 138 time.Sleep(time.Second) 139 os.Exit(EXIT_THEME_MIGRATION) 140 } 141 142 func UpgradeDatabaseToVersion33(sqlStore SqlStore) { 143 if shouldPerformUpgrade(sqlStore, VERSION_3_2_0, VERSION_3_3_0) { 144 if sqlStore.DoesColumnExist("Users", "ThemeProps") { 145 params := map[string]interface{}{ 146 "Category": model.PREFERENCE_CATEGORY_THEME, 147 "Name": "", 148 } 149 150 transaction, err := sqlStore.GetMaster().Begin() 151 if err != nil { 152 themeMigrationFailed(err) 153 } 154 155 // increase size of Value column of Preferences table to match the size of the ThemeProps column 156 if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES { 157 if _, err := transaction.Exec("ALTER TABLE Preferences ALTER COLUMN Value TYPE varchar(2000)"); err != nil { 158 themeMigrationFailed(err) 159 } 160 } else if sqlStore.DriverName() == model.DATABASE_DRIVER_MYSQL { 161 if _, err := transaction.Exec("ALTER TABLE Preferences MODIFY Value text"); err != nil { 162 themeMigrationFailed(err) 163 } 164 } 165 166 // copy data across 167 if _, err := transaction.Exec( 168 `INSERT INTO 169 Preferences(UserId, Category, Name, Value) 170 SELECT 171 Id, '`+model.PREFERENCE_CATEGORY_THEME+`', '', ThemeProps 172 FROM 173 Users 174 WHERE 175 Users.ThemeProps != 'null'`, params); err != nil { 176 themeMigrationFailed(err) 177 } 178 179 // delete old data 180 if _, err := transaction.Exec("ALTER TABLE Users DROP COLUMN ThemeProps"); err != nil { 181 themeMigrationFailed(err) 182 } 183 184 if err := transaction.Commit(); err != nil { 185 themeMigrationFailed(err) 186 } 187 188 // rename solarized_* code themes to solarized-* to match client changes in 3.0 189 var data model.Preferences 190 if _, err := sqlStore.GetMaster().Select(&data, "SELECT * FROM Preferences WHERE Category = '"+model.PREFERENCE_CATEGORY_THEME+"' AND Value LIKE '%solarized_%'"); err == nil { 191 for i := range data { 192 data[i].Value = strings.Replace(data[i].Value, "solarized_", "solarized-", -1) 193 } 194 195 sqlStore.Preference().Save(&data) 196 } 197 } 198 199 sqlStore.CreateColumnIfNotExists("OAuthApps", "IsTrusted", "tinyint(1)", "boolean", "0") 200 sqlStore.CreateColumnIfNotExists("OAuthApps", "IconURL", "varchar(512)", "varchar(512)", "") 201 sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ClientId", "varchar(26)", "varchar(26)", "") 202 sqlStore.CreateColumnIfNotExists("OAuthAccessData", "UserId", "varchar(26)", "varchar(26)", "") 203 sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ExpiresAt", "bigint", "bigint", "0") 204 205 if sqlStore.DoesColumnExist("OAuthAccessData", "AuthCode") { 206 sqlStore.RemoveIndexIfExists("idx_oauthaccessdata_auth_code", "OAuthAccessData") 207 sqlStore.RemoveColumnIfExists("OAuthAccessData", "AuthCode") 208 } 209 210 sqlStore.RemoveColumnIfExists("Users", "LastActivityAt") 211 sqlStore.RemoveColumnIfExists("Users", "LastPingAt") 212 213 sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "TriggerWhen", "tinyint", "integer", "0") 214 215 saveSchemaVersion(sqlStore, VERSION_3_3_0) 216 } 217 } 218 219 func UpgradeDatabaseToVersion34(sqlStore SqlStore) { 220 if shouldPerformUpgrade(sqlStore, VERSION_3_3_0, VERSION_3_4_0) { 221 sqlStore.CreateColumnIfNotExists("Status", "Manual", "BOOLEAN", "BOOLEAN", "0") 222 sqlStore.CreateColumnIfNotExists("Status", "ActiveChannel", "varchar(26)", "varchar(26)", "") 223 224 saveSchemaVersion(sqlStore, VERSION_3_4_0) 225 } 226 } 227 228 func UpgradeDatabaseToVersion35(sqlStore SqlStore) { 229 if shouldPerformUpgrade(sqlStore, VERSION_3_4_0, VERSION_3_5_0) { 230 sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user' WHERE Roles = ''") 231 sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user system_admin' WHERE Roles = 'system_admin'") 232 sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user' WHERE Roles = ''") 233 sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user team_admin' WHERE Roles = 'admin'") 234 sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user' WHERE Roles = ''") 235 sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user channel_admin' WHERE Roles = 'admin'") 236 237 // The rest of the migration from Filenames -> FileIds is done lazily in api.GetFileInfosForPost 238 sqlStore.CreateColumnIfNotExists("Posts", "FileIds", "varchar(150)", "varchar(150)", "[]") 239 240 // Increase maximum length of the Channel table Purpose column. 241 if sqlStore.GetMaxLengthOfColumnIfExists("Channels", "Purpose") != "250" { 242 sqlStore.AlterColumnTypeIfExists("Channels", "Purpose", "varchar(250)", "varchar(250)") 243 } 244 245 sqlStore.Session().RemoveAllSessions() 246 247 saveSchemaVersion(sqlStore, VERSION_3_5_0) 248 } 249 } 250 251 func UpgradeDatabaseToVersion36(sqlStore SqlStore) { 252 if shouldPerformUpgrade(sqlStore, VERSION_3_5_0, VERSION_3_6_0) { 253 sqlStore.CreateColumnIfNotExists("Posts", "HasReactions", "tinyint", "boolean", "0") 254 255 // Create Team Description column 256 sqlStore.CreateColumnIfNotExists("Teams", "Description", "varchar(255)", "varchar(255)", "") 257 258 // Add a Position column to users. 259 sqlStore.CreateColumnIfNotExists("Users", "Position", "varchar(64)", "varchar(64)", "") 260 261 // Remove ActiveChannel column from Status 262 sqlStore.RemoveColumnIfExists("Status", "ActiveChannel") 263 264 saveSchemaVersion(sqlStore, VERSION_3_6_0) 265 } 266 } 267 268 func UpgradeDatabaseToVersion37(sqlStore SqlStore) { 269 if shouldPerformUpgrade(sqlStore, VERSION_3_6_0, VERSION_3_7_0) { 270 // Add EditAt column to Posts 271 sqlStore.CreateColumnIfNotExists("Posts", "EditAt", " bigint", " bigint", "0") 272 273 saveSchemaVersion(sqlStore, VERSION_3_7_0) 274 } 275 } 276 277 func UpgradeDatabaseToVersion38(sqlStore SqlStore) { 278 if shouldPerformUpgrade(sqlStore, VERSION_3_7_0, VERSION_3_8_0) { 279 // Add the IsPinned column to posts. 280 sqlStore.CreateColumnIfNotExists("Posts", "IsPinned", "boolean", "boolean", "0") 281 282 saveSchemaVersion(sqlStore, VERSION_3_8_0) 283 } 284 } 285 286 func UpgradeDatabaseToVersion39(sqlStore SqlStore) { 287 if shouldPerformUpgrade(sqlStore, VERSION_3_8_0, VERSION_3_9_0) { 288 sqlStore.CreateColumnIfNotExists("OAuthAccessData", "Scope", "varchar(128)", "varchar(128)", model.DEFAULT_SCOPE) 289 sqlStore.RemoveTableIfExists("PasswordRecovery") 290 291 saveSchemaVersion(sqlStore, VERSION_3_9_0) 292 } 293 } 294 295 func UpgradeDatabaseToVersion310(sqlStore SqlStore) { 296 if shouldPerformUpgrade(sqlStore, VERSION_3_9_0, VERSION_3_10_0) { 297 saveSchemaVersion(sqlStore, VERSION_3_10_0) 298 } 299 } 300 301 func UpgradeDatabaseToVersion40(sqlStore SqlStore) { 302 if shouldPerformUpgrade(sqlStore, VERSION_3_10_0, VERSION_4_0_0) { 303 saveSchemaVersion(sqlStore, VERSION_4_0_0) 304 } 305 } 306 307 func UpgradeDatabaseToVersion41(sqlStore SqlStore) { 308 if shouldPerformUpgrade(sqlStore, VERSION_4_0_0, VERSION_4_1_0) { 309 // Increase maximum length of the Users table Roles column. 310 if sqlStore.GetMaxLengthOfColumnIfExists("Users", "Roles") != "256" { 311 sqlStore.AlterColumnTypeIfExists("Users", "Roles", "varchar(256)", "varchar(256)") 312 } 313 314 sqlStore.RemoveTableIfExists("JobStatuses") 315 316 saveSchemaVersion(sqlStore, VERSION_4_1_0) 317 } 318 } 319 320 func UpgradeDatabaseToVersion42(sqlStore SqlStore) { 321 if shouldPerformUpgrade(sqlStore, VERSION_4_1_0, VERSION_4_2_0) { 322 saveSchemaVersion(sqlStore, VERSION_4_2_0) 323 } 324 } 325 326 func UpgradeDatabaseToVersion43(sqlStore SqlStore) { 327 if shouldPerformUpgrade(sqlStore, VERSION_4_2_0, VERSION_4_3_0) { 328 saveSchemaVersion(sqlStore, VERSION_4_3_0) 329 } 330 } 331 332 func UpgradeDatabaseToVersion44(sqlStore SqlStore) { 333 if shouldPerformUpgrade(sqlStore, VERSION_4_3_0, VERSION_4_4_0) { 334 // Add the IsActive column to UserAccessToken. 335 sqlStore.CreateColumnIfNotExists("UserAccessTokens", "IsActive", "boolean", "boolean", "1") 336 337 saveSchemaVersion(sqlStore, VERSION_4_4_0) 338 } 339 } 340 341 func UpgradeDatabaseToVersion45(sqlStore SqlStore) { 342 if shouldPerformUpgrade(sqlStore, VERSION_4_4_0, VERSION_4_5_0) { 343 saveSchemaVersion(sqlStore, VERSION_4_5_0) 344 } 345 } 346 347 func UpgradeDatabaseToVersion46(sqlStore SqlStore) { 348 if shouldPerformUpgrade(sqlStore, VERSION_4_5_0, VERSION_4_6_0) { 349 sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "Username", "varchar(64)", "varchar(64)", "") 350 sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "") 351 saveSchemaVersion(sqlStore, VERSION_4_6_0) 352 } 353 } 354 355 func UpgradeDatabaseToVersion47(sqlStore SqlStore) { 356 if shouldPerformUpgrade(sqlStore, VERSION_4_6_0, VERSION_4_7_0) { 357 sqlStore.AlterColumnTypeIfExists("Users", "Position", "varchar(128)", "varchar(128)") 358 sqlStore.AlterColumnTypeIfExists("OAuthAuthData", "State", "varchar(1024)", "varchar(1024)") 359 sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email") 360 sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Username") 361 saveSchemaVersion(sqlStore, VERSION_4_7_0) 362 } 363 } 364 365 // If any new instances started with 4.7, they would have the bad Email column on the 366 // ChannelMemberHistory table. So for those cases we need to do an upgrade between 367 // 4.7.0 and 4.7.1 368 func UpgradeDatabaseToVersion471(sqlStore SqlStore) { 369 if shouldPerformUpgrade(sqlStore, VERSION_4_7_0, VERSION_4_7_1) { 370 sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email") 371 saveSchemaVersion(sqlStore, VERSION_4_7_1) 372 } 373 } 374 375 func UpgradeDatabaseToVersion472(sqlStore SqlStore) { 376 if shouldPerformUpgrade(sqlStore, VERSION_4_7_1, VERSION_4_7_2) { 377 sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels") 378 saveSchemaVersion(sqlStore, VERSION_4_7_2) 379 } 380 } 381 382 func UpgradeDatabaseToVersion48(sqlStore SqlStore) { 383 if shouldPerformUpgrade(sqlStore, VERSION_4_7_2, VERSION_4_8_0) { 384 saveSchemaVersion(sqlStore, VERSION_4_8_0) 385 } 386 } 387 388 func UpgradeDatabaseToVersion481(sqlStore SqlStore) { 389 if shouldPerformUpgrade(sqlStore, VERSION_4_8_0, VERSION_4_8_1) { 390 sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels") 391 saveSchemaVersion(sqlStore, VERSION_4_8_1) 392 } 393 } 394 395 func UpgradeDatabaseToVersion49(sqlStore SqlStore) { 396 // This version of Mattermost includes an App-Layer migration which migrates from hard-coded roles configured by 397 // a number of parameters in `config.json` to a `Roles` table in the database. The migration code can be seen 398 // in the file `app/app.go` in the function `DoAdvancedPermissionsMigration()`. 399 400 if shouldPerformUpgrade(sqlStore, VERSION_4_8_1, VERSION_4_9_0) { 401 sqlStore.CreateColumnIfNotExists("Teams", "LastTeamIconUpdate", "bigint", "bigint", "0") 402 defaultTimezone := model.DefaultUserTimezone() 403 defaultTimezoneValue, err := json.Marshal(defaultTimezone) 404 if err != nil { 405 mlog.Critical(fmt.Sprint(err)) 406 } 407 sqlStore.CreateColumnIfNotExists("Users", "Timezone", "varchar(256)", "varchar(256)", string(defaultTimezoneValue)) 408 sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels") 409 saveSchemaVersion(sqlStore, VERSION_4_9_0) 410 } 411 } 412 413 func UpgradeDatabaseToVersion410(sqlStore SqlStore) { 414 if shouldPerformUpgrade(sqlStore, VERSION_4_9_0, VERSION_4_10_0) { 415 416 sqlStore.RemoveIndexIfExists("Name_2", "Channels") 417 sqlStore.RemoveIndexIfExists("Name_2", "Emoji") 418 sqlStore.RemoveIndexIfExists("ClientId_2", "OAuthAccessData") 419 420 saveSchemaVersion(sqlStore, VERSION_4_10_0) 421 sqlStore.GetMaster().Exec("UPDATE Users SET AuthData=LOWER(AuthData) WHERE AuthService = 'saml'") 422 } 423 }