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