github.com/hahmadia/mattermost-server@v5.11.1+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  	"database/sql"
     8  	"encoding/json"
     9  	"fmt"
    10  	"os"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/blang/semver"
    15  	"github.com/pkg/errors"
    16  
    17  	"github.com/mattermost/mattermost-server/mlog"
    18  	"github.com/mattermost/mattermost-server/model"
    19  	"github.com/mattermost/mattermost-server/services/timezones"
    20  )
    21  
    22  const (
    23  	VERSION_5_11_0           = "5.11.0"
    24  	VERSION_5_10_0           = "5.10.0"
    25  	VERSION_5_9_0            = "5.9.0"
    26  	VERSION_5_8_0            = "5.8.0"
    27  	VERSION_5_7_0            = "5.7.0"
    28  	VERSION_5_6_0            = "5.6.0"
    29  	VERSION_5_5_0            = "5.5.0"
    30  	VERSION_5_4_0            = "5.4.0"
    31  	VERSION_5_3_0            = "5.3.0"
    32  	VERSION_5_2_0            = "5.2.0"
    33  	VERSION_5_1_0            = "5.1.0"
    34  	VERSION_5_0_0            = "5.0.0"
    35  	VERSION_4_10_0           = "4.10.0"
    36  	VERSION_4_9_0            = "4.9.0"
    37  	VERSION_4_8_1            = "4.8.1"
    38  	VERSION_4_8_0            = "4.8.0"
    39  	VERSION_4_7_2            = "4.7.2"
    40  	VERSION_4_7_1            = "4.7.1"
    41  	VERSION_4_7_0            = "4.7.0"
    42  	VERSION_4_6_0            = "4.6.0"
    43  	VERSION_4_5_0            = "4.5.0"
    44  	VERSION_4_4_0            = "4.4.0"
    45  	VERSION_4_3_0            = "4.3.0"
    46  	VERSION_4_2_0            = "4.2.0"
    47  	VERSION_4_1_0            = "4.1.0"
    48  	VERSION_4_0_0            = "4.0.0"
    49  	VERSION_3_10_0           = "3.10.0"
    50  	VERSION_3_9_0            = "3.9.0"
    51  	VERSION_3_8_0            = "3.8.0"
    52  	VERSION_3_7_0            = "3.7.0"
    53  	VERSION_3_6_0            = "3.6.0"
    54  	VERSION_3_5_0            = "3.5.0"
    55  	VERSION_3_4_0            = "3.4.0"
    56  	VERSION_3_3_0            = "3.3.0"
    57  	VERSION_3_2_0            = "3.2.0"
    58  	VERSION_3_1_0            = "3.1.0"
    59  	VERSION_3_0_0            = "3.0.0"
    60  	OLDEST_SUPPORTED_VERSION = VERSION_3_0_0
    61  )
    62  
    63  const (
    64  	EXIT_VERSION_SAVE                   = 1003
    65  	EXIT_THEME_MIGRATION                = 1004
    66  	EXIT_TEAM_INVITEID_MIGRATION_FAILED = 1006
    67  )
    68  
    69  // UpgradeDatabase attempts to migrate the schema to the latest supported version.
    70  // The value of model.CurrentVersion is accepted as a parameter for unit testing, but it is not
    71  // used to stop migrations at that version.
    72  func UpgradeDatabase(sqlStore SqlStore, currentModelVersionString string) error {
    73  	currentModelVersion, err := semver.Parse(currentModelVersionString)
    74  	if err != nil {
    75  		return errors.Wrapf(err, "failed to parse current model version %s", currentModelVersionString)
    76  	}
    77  
    78  	nextUnsupportedMajorVersion := semver.Version{
    79  		Major: currentModelVersion.Major + 1,
    80  	}
    81  
    82  	oldestSupportedVersion, err := semver.Parse(OLDEST_SUPPORTED_VERSION)
    83  	if err != nil {
    84  		return errors.Wrapf(err, "failed to parse oldest supported version %s", OLDEST_SUPPORTED_VERSION)
    85  	}
    86  
    87  	var currentSchemaVersion *semver.Version
    88  	currentSchemaVersionString := sqlStore.GetCurrentSchemaVersion()
    89  	if currentSchemaVersionString != "" {
    90  		currentSchemaVersion, err = semver.New(currentSchemaVersionString)
    91  		if err != nil {
    92  			return errors.Wrapf(err, "failed to parse database schema version %s", currentSchemaVersionString)
    93  		}
    94  	}
    95  
    96  	// Assume a fresh database if no schema version has been recorded.
    97  	if currentSchemaVersion == nil {
    98  		if result := <-sqlStore.System().SaveOrUpdate(&model.System{Name: "Version", Value: currentModelVersion.String()}); result.Err != nil {
    99  			return errors.Wrap(err, "failed to initialize schema version for fresh database")
   100  		}
   101  
   102  		currentSchemaVersion = &currentModelVersion
   103  		mlog.Info(fmt.Sprintf("The database schema has been set to version %s", *currentSchemaVersion))
   104  		return nil
   105  	}
   106  
   107  	// Upgrades prior to the oldest supported version are not supported.
   108  	if currentSchemaVersion.LT(oldestSupportedVersion) {
   109  		return errors.Errorf("Database schema version %s is no longer supported. This Mattermost server supports automatic upgrades from schema version %s through schema version %s. Please manually upgrade to at least version %s before continuing.", *currentSchemaVersion, oldestSupportedVersion, currentModelVersion, oldestSupportedVersion)
   110  	}
   111  
   112  	// Allow forwards compatibility only within the same major version.
   113  	if currentSchemaVersion.GTE(nextUnsupportedMajorVersion) {
   114  		return errors.Errorf("Database schema version %s is not supported. This Mattermost server supports only >=%s, <%s. Please upgrade to at least version %s before continuing.", *currentSchemaVersion, currentModelVersion, nextUnsupportedMajorVersion, nextUnsupportedMajorVersion)
   115  	} else if currentSchemaVersion.GT(currentModelVersion) {
   116  		mlog.Warn(fmt.Sprintf("The database schema with version %s is newer than Mattermost version %s.", currentSchemaVersion, currentModelVersion))
   117  	}
   118  
   119  	// Otherwise, apply any necessary migrations. Note that these methods currently invoke
   120  	// os.Exit instead of returning an error.
   121  	UpgradeDatabaseToVersion31(sqlStore)
   122  	UpgradeDatabaseToVersion32(sqlStore)
   123  	UpgradeDatabaseToVersion33(sqlStore)
   124  	UpgradeDatabaseToVersion34(sqlStore)
   125  	UpgradeDatabaseToVersion35(sqlStore)
   126  	UpgradeDatabaseToVersion36(sqlStore)
   127  	UpgradeDatabaseToVersion37(sqlStore)
   128  	UpgradeDatabaseToVersion38(sqlStore)
   129  	UpgradeDatabaseToVersion39(sqlStore)
   130  	UpgradeDatabaseToVersion310(sqlStore)
   131  	UpgradeDatabaseToVersion40(sqlStore)
   132  	UpgradeDatabaseToVersion41(sqlStore)
   133  	UpgradeDatabaseToVersion42(sqlStore)
   134  	UpgradeDatabaseToVersion43(sqlStore)
   135  	UpgradeDatabaseToVersion44(sqlStore)
   136  	UpgradeDatabaseToVersion45(sqlStore)
   137  	UpgradeDatabaseToVersion46(sqlStore)
   138  	UpgradeDatabaseToVersion47(sqlStore)
   139  	UpgradeDatabaseToVersion471(sqlStore)
   140  	UpgradeDatabaseToVersion472(sqlStore)
   141  	UpgradeDatabaseToVersion48(sqlStore)
   142  	UpgradeDatabaseToVersion481(sqlStore)
   143  	UpgradeDatabaseToVersion49(sqlStore)
   144  	UpgradeDatabaseToVersion410(sqlStore)
   145  	UpgradeDatabaseToVersion50(sqlStore)
   146  	UpgradeDatabaseToVersion51(sqlStore)
   147  	UpgradeDatabaseToVersion52(sqlStore)
   148  	UpgradeDatabaseToVersion53(sqlStore)
   149  	UpgradeDatabaseToVersion54(sqlStore)
   150  	UpgradeDatabaseToVersion55(sqlStore)
   151  	UpgradeDatabaseToVersion56(sqlStore)
   152  	UpgradeDatabaseToVersion57(sqlStore)
   153  	UpgradeDatabaseToVersion58(sqlStore)
   154  	UpgradeDatabaseToVersion59(sqlStore)
   155  	UpgradeDatabaseToVersion510(sqlStore)
   156  	UpgradeDatabaseToVersion511(sqlStore)
   157  
   158  	return nil
   159  }
   160  
   161  func saveSchemaVersion(sqlStore SqlStore, version string) {
   162  	if result := <-sqlStore.System().SaveOrUpdate(&model.System{Name: "Version", Value: version}); result.Err != nil {
   163  		mlog.Critical(result.Err.Error())
   164  		time.Sleep(time.Second)
   165  		os.Exit(EXIT_VERSION_SAVE)
   166  	}
   167  
   168  	mlog.Warn(fmt.Sprintf("The database schema has been upgraded to version %v", version))
   169  }
   170  
   171  func shouldPerformUpgrade(sqlStore SqlStore, currentSchemaVersion string, expectedSchemaVersion string) bool {
   172  	if sqlStore.GetCurrentSchemaVersion() == currentSchemaVersion {
   173  		mlog.Warn(fmt.Sprintf("Attempting to upgrade the database schema version from %s to %v", currentSchemaVersion, expectedSchemaVersion))
   174  
   175  		return true
   176  	}
   177  
   178  	return false
   179  }
   180  
   181  func UpgradeDatabaseToVersion31(sqlStore SqlStore) {
   182  	if shouldPerformUpgrade(sqlStore, VERSION_3_0_0, VERSION_3_1_0) {
   183  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "")
   184  		saveSchemaVersion(sqlStore, VERSION_3_1_0)
   185  	}
   186  }
   187  
   188  func UpgradeDatabaseToVersion32(sqlStore SqlStore) {
   189  	if shouldPerformUpgrade(sqlStore, VERSION_3_1_0, VERSION_3_2_0) {
   190  		sqlStore.CreateColumnIfNotExists("TeamMembers", "DeleteAt", "bigint(20)", "bigint", "0")
   191  
   192  		saveSchemaVersion(sqlStore, VERSION_3_2_0)
   193  	}
   194  }
   195  
   196  func themeMigrationFailed(err error) {
   197  	mlog.Critical(fmt.Sprintf("Failed to migrate User.ThemeProps to Preferences table %v", err))
   198  	time.Sleep(time.Second)
   199  	os.Exit(EXIT_THEME_MIGRATION)
   200  }
   201  
   202  func UpgradeDatabaseToVersion33(sqlStore SqlStore) {
   203  	if shouldPerformUpgrade(sqlStore, VERSION_3_2_0, VERSION_3_3_0) {
   204  		if sqlStore.DoesColumnExist("Users", "ThemeProps") {
   205  			params := map[string]interface{}{
   206  				"Category": model.PREFERENCE_CATEGORY_THEME,
   207  				"Name":     "",
   208  			}
   209  
   210  			transaction, err := sqlStore.GetMaster().Begin()
   211  			if err != nil {
   212  				themeMigrationFailed(err)
   213  			}
   214  			defer finalizeTransaction(transaction)
   215  
   216  			// increase size of Value column of Preferences table to match the size of the ThemeProps column
   217  			if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   218  				if _, err := transaction.Exec("ALTER TABLE Preferences ALTER COLUMN Value TYPE varchar(2000)"); err != nil {
   219  					themeMigrationFailed(err)
   220  					return
   221  				}
   222  			} else if sqlStore.DriverName() == model.DATABASE_DRIVER_MYSQL {
   223  				if _, err := transaction.Exec("ALTER TABLE Preferences MODIFY Value text"); err != nil {
   224  					themeMigrationFailed(err)
   225  					return
   226  				}
   227  			}
   228  
   229  			// copy data across
   230  			if _, err := transaction.Exec(
   231  				`INSERT INTO
   232  					Preferences(UserId, Category, Name, Value)
   233  				SELECT
   234  					Id, '`+model.PREFERENCE_CATEGORY_THEME+`', '', ThemeProps
   235  				FROM
   236  					Users
   237  				WHERE
   238  					Users.ThemeProps != 'null'`, params); err != nil {
   239  				themeMigrationFailed(err)
   240  				return
   241  			}
   242  
   243  			// delete old data
   244  			if _, err := transaction.Exec("ALTER TABLE Users DROP COLUMN ThemeProps"); err != nil {
   245  				themeMigrationFailed(err)
   246  				return
   247  			}
   248  
   249  			if err := transaction.Commit(); err != nil {
   250  				themeMigrationFailed(err)
   251  				return
   252  			}
   253  
   254  			// rename solarized_* code themes to solarized-* to match client changes in 3.0
   255  			var data model.Preferences
   256  			if _, err := sqlStore.GetMaster().Select(&data, "SELECT * FROM Preferences WHERE Category = '"+model.PREFERENCE_CATEGORY_THEME+"' AND Value LIKE '%solarized_%'"); err == nil {
   257  				for i := range data {
   258  					data[i].Value = strings.Replace(data[i].Value, "solarized_", "solarized-", -1)
   259  				}
   260  
   261  				sqlStore.Preference().Save(&data)
   262  			}
   263  		}
   264  
   265  		sqlStore.CreateColumnIfNotExists("OAuthApps", "IsTrusted", "tinyint(1)", "boolean", "0")
   266  		sqlStore.CreateColumnIfNotExists("OAuthApps", "IconURL", "varchar(512)", "varchar(512)", "")
   267  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ClientId", "varchar(26)", "varchar(26)", "")
   268  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "UserId", "varchar(26)", "varchar(26)", "")
   269  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "ExpiresAt", "bigint", "bigint", "0")
   270  
   271  		if sqlStore.DoesColumnExist("OAuthAccessData", "AuthCode") {
   272  			sqlStore.RemoveIndexIfExists("idx_oauthaccessdata_auth_code", "OAuthAccessData")
   273  			sqlStore.RemoveColumnIfExists("OAuthAccessData", "AuthCode")
   274  		}
   275  
   276  		sqlStore.RemoveColumnIfExists("Users", "LastActivityAt")
   277  		sqlStore.RemoveColumnIfExists("Users", "LastPingAt")
   278  
   279  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "TriggerWhen", "tinyint", "integer", "0")
   280  
   281  		saveSchemaVersion(sqlStore, VERSION_3_3_0)
   282  	}
   283  }
   284  
   285  func UpgradeDatabaseToVersion34(sqlStore SqlStore) {
   286  	if shouldPerformUpgrade(sqlStore, VERSION_3_3_0, VERSION_3_4_0) {
   287  		sqlStore.CreateColumnIfNotExists("Status", "Manual", "BOOLEAN", "BOOLEAN", "0")
   288  		sqlStore.CreateColumnIfNotExists("Status", "ActiveChannel", "varchar(26)", "varchar(26)", "")
   289  
   290  		saveSchemaVersion(sqlStore, VERSION_3_4_0)
   291  	}
   292  }
   293  
   294  func UpgradeDatabaseToVersion35(sqlStore SqlStore) {
   295  	if shouldPerformUpgrade(sqlStore, VERSION_3_4_0, VERSION_3_5_0) {
   296  		sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user' WHERE Roles = ''")
   297  		sqlStore.GetMaster().Exec("UPDATE Users SET Roles = 'system_user system_admin' WHERE Roles = 'system_admin'")
   298  		sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user' WHERE Roles = ''")
   299  		sqlStore.GetMaster().Exec("UPDATE TeamMembers SET Roles = 'team_user team_admin' WHERE Roles = 'admin'")
   300  		sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user' WHERE Roles = ''")
   301  		sqlStore.GetMaster().Exec("UPDATE ChannelMembers SET Roles = 'channel_user channel_admin' WHERE Roles = 'admin'")
   302  
   303  		// The rest of the migration from Filenames -> FileIds is done lazily in api.GetFileInfosForPost
   304  		sqlStore.CreateColumnIfNotExists("Posts", "FileIds", "varchar(150)", "varchar(150)", "[]")
   305  
   306  		// Increase maximum length of the Channel table Purpose column.
   307  		if sqlStore.GetMaxLengthOfColumnIfExists("Channels", "Purpose") != "250" {
   308  			sqlStore.AlterColumnTypeIfExists("Channels", "Purpose", "varchar(250)", "varchar(250)")
   309  		}
   310  
   311  		sqlStore.Session().RemoveAllSessions()
   312  
   313  		saveSchemaVersion(sqlStore, VERSION_3_5_0)
   314  	}
   315  }
   316  
   317  func UpgradeDatabaseToVersion36(sqlStore SqlStore) {
   318  	if shouldPerformUpgrade(sqlStore, VERSION_3_5_0, VERSION_3_6_0) {
   319  		sqlStore.CreateColumnIfNotExists("Posts", "HasReactions", "tinyint", "boolean", "0")
   320  
   321  		// Create Team Description column
   322  		sqlStore.CreateColumnIfNotExists("Teams", "Description", "varchar(255)", "varchar(255)", "")
   323  
   324  		// Add a Position column to users.
   325  		sqlStore.CreateColumnIfNotExists("Users", "Position", "varchar(64)", "varchar(64)", "")
   326  
   327  		// Remove ActiveChannel column from Status
   328  		sqlStore.RemoveColumnIfExists("Status", "ActiveChannel")
   329  
   330  		saveSchemaVersion(sqlStore, VERSION_3_6_0)
   331  	}
   332  }
   333  
   334  func UpgradeDatabaseToVersion37(sqlStore SqlStore) {
   335  	if shouldPerformUpgrade(sqlStore, VERSION_3_6_0, VERSION_3_7_0) {
   336  		// Add EditAt column to Posts
   337  		sqlStore.CreateColumnIfNotExists("Posts", "EditAt", " bigint", " bigint", "0")
   338  
   339  		saveSchemaVersion(sqlStore, VERSION_3_7_0)
   340  	}
   341  }
   342  
   343  func UpgradeDatabaseToVersion38(sqlStore SqlStore) {
   344  	if shouldPerformUpgrade(sqlStore, VERSION_3_7_0, VERSION_3_8_0) {
   345  		// Add the IsPinned column to posts.
   346  		sqlStore.CreateColumnIfNotExists("Posts", "IsPinned", "boolean", "boolean", "0")
   347  
   348  		saveSchemaVersion(sqlStore, VERSION_3_8_0)
   349  	}
   350  }
   351  
   352  func UpgradeDatabaseToVersion39(sqlStore SqlStore) {
   353  	if shouldPerformUpgrade(sqlStore, VERSION_3_8_0, VERSION_3_9_0) {
   354  		sqlStore.CreateColumnIfNotExists("OAuthAccessData", "Scope", "varchar(128)", "varchar(128)", model.DEFAULT_SCOPE)
   355  		sqlStore.RemoveTableIfExists("PasswordRecovery")
   356  
   357  		saveSchemaVersion(sqlStore, VERSION_3_9_0)
   358  	}
   359  }
   360  
   361  func UpgradeDatabaseToVersion310(sqlStore SqlStore) {
   362  	if shouldPerformUpgrade(sqlStore, VERSION_3_9_0, VERSION_3_10_0) {
   363  		saveSchemaVersion(sqlStore, VERSION_3_10_0)
   364  	}
   365  }
   366  
   367  func UpgradeDatabaseToVersion40(sqlStore SqlStore) {
   368  	if shouldPerformUpgrade(sqlStore, VERSION_3_10_0, VERSION_4_0_0) {
   369  		saveSchemaVersion(sqlStore, VERSION_4_0_0)
   370  	}
   371  }
   372  
   373  func UpgradeDatabaseToVersion41(sqlStore SqlStore) {
   374  	if shouldPerformUpgrade(sqlStore, VERSION_4_0_0, VERSION_4_1_0) {
   375  		// Increase maximum length of the Users table Roles column.
   376  		if sqlStore.GetMaxLengthOfColumnIfExists("Users", "Roles") != "256" {
   377  			sqlStore.AlterColumnTypeIfExists("Users", "Roles", "varchar(256)", "varchar(256)")
   378  		}
   379  
   380  		sqlStore.RemoveTableIfExists("JobStatuses")
   381  
   382  		saveSchemaVersion(sqlStore, VERSION_4_1_0)
   383  	}
   384  }
   385  
   386  func UpgradeDatabaseToVersion42(sqlStore SqlStore) {
   387  	if shouldPerformUpgrade(sqlStore, VERSION_4_1_0, VERSION_4_2_0) {
   388  		saveSchemaVersion(sqlStore, VERSION_4_2_0)
   389  	}
   390  }
   391  
   392  func UpgradeDatabaseToVersion43(sqlStore SqlStore) {
   393  	if shouldPerformUpgrade(sqlStore, VERSION_4_2_0, VERSION_4_3_0) {
   394  		saveSchemaVersion(sqlStore, VERSION_4_3_0)
   395  	}
   396  }
   397  
   398  func UpgradeDatabaseToVersion44(sqlStore SqlStore) {
   399  	if shouldPerformUpgrade(sqlStore, VERSION_4_3_0, VERSION_4_4_0) {
   400  		// Add the IsActive column to UserAccessToken.
   401  		sqlStore.CreateColumnIfNotExists("UserAccessTokens", "IsActive", "boolean", "boolean", "1")
   402  
   403  		saveSchemaVersion(sqlStore, VERSION_4_4_0)
   404  	}
   405  }
   406  
   407  func UpgradeDatabaseToVersion45(sqlStore SqlStore) {
   408  	if shouldPerformUpgrade(sqlStore, VERSION_4_4_0, VERSION_4_5_0) {
   409  		saveSchemaVersion(sqlStore, VERSION_4_5_0)
   410  	}
   411  }
   412  
   413  func UpgradeDatabaseToVersion46(sqlStore SqlStore) {
   414  	if shouldPerformUpgrade(sqlStore, VERSION_4_5_0, VERSION_4_6_0) {
   415  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "Username", "varchar(64)", "varchar(64)", "")
   416  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "")
   417  		saveSchemaVersion(sqlStore, VERSION_4_6_0)
   418  	}
   419  }
   420  
   421  func UpgradeDatabaseToVersion47(sqlStore SqlStore) {
   422  	if shouldPerformUpgrade(sqlStore, VERSION_4_6_0, VERSION_4_7_0) {
   423  		sqlStore.AlterColumnTypeIfExists("Users", "Position", "varchar(128)", "varchar(128)")
   424  		sqlStore.AlterColumnTypeIfExists("OAuthAuthData", "State", "varchar(1024)", "varchar(1024)")
   425  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email")
   426  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Username")
   427  		saveSchemaVersion(sqlStore, VERSION_4_7_0)
   428  	}
   429  }
   430  
   431  // If any new instances started with 4.7, they would have the bad Email column on the
   432  // ChannelMemberHistory table. So for those cases we need to do an upgrade between
   433  // 4.7.0 and 4.7.1
   434  func UpgradeDatabaseToVersion471(sqlStore SqlStore) {
   435  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_0, VERSION_4_7_1) {
   436  		sqlStore.RemoveColumnIfExists("ChannelMemberHistory", "Email")
   437  		saveSchemaVersion(sqlStore, VERSION_4_7_1)
   438  	}
   439  }
   440  
   441  func UpgradeDatabaseToVersion472(sqlStore SqlStore) {
   442  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_1, VERSION_4_7_2) {
   443  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   444  		saveSchemaVersion(sqlStore, VERSION_4_7_2)
   445  	}
   446  }
   447  
   448  func UpgradeDatabaseToVersion48(sqlStore SqlStore) {
   449  	if shouldPerformUpgrade(sqlStore, VERSION_4_7_2, VERSION_4_8_0) {
   450  		saveSchemaVersion(sqlStore, VERSION_4_8_0)
   451  	}
   452  }
   453  
   454  func UpgradeDatabaseToVersion481(sqlStore SqlStore) {
   455  	if shouldPerformUpgrade(sqlStore, VERSION_4_8_0, VERSION_4_8_1) {
   456  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   457  		saveSchemaVersion(sqlStore, VERSION_4_8_1)
   458  	}
   459  }
   460  
   461  func UpgradeDatabaseToVersion49(sqlStore SqlStore) {
   462  	// This version of Mattermost includes an App-Layer migration which migrates from hard-coded roles configured by
   463  	// a number of parameters in `config.json` to a `Roles` table in the database. The migration code can be seen
   464  	// in the file `app/app.go` in the function `DoAdvancedPermissionsMigration()`.
   465  
   466  	if shouldPerformUpgrade(sqlStore, VERSION_4_8_1, VERSION_4_9_0) {
   467  		sqlStore.CreateColumnIfNotExists("Teams", "LastTeamIconUpdate", "bigint", "bigint", "0")
   468  		defaultTimezone := timezones.DefaultUserTimezone()
   469  		defaultTimezoneValue, err := json.Marshal(defaultTimezone)
   470  		if err != nil {
   471  			mlog.Critical(fmt.Sprint(err))
   472  		}
   473  		sqlStore.CreateColumnIfNotExists("Users", "Timezone", "varchar(256)", "varchar(256)", string(defaultTimezoneValue))
   474  		sqlStore.RemoveIndexIfExists("idx_channels_displayname", "Channels")
   475  		saveSchemaVersion(sqlStore, VERSION_4_9_0)
   476  	}
   477  }
   478  
   479  func UpgradeDatabaseToVersion410(sqlStore SqlStore) {
   480  	if shouldPerformUpgrade(sqlStore, VERSION_4_9_0, VERSION_4_10_0) {
   481  
   482  		sqlStore.RemoveIndexIfExists("Name_2", "Channels")
   483  		sqlStore.RemoveIndexIfExists("Name_2", "Emoji")
   484  		sqlStore.RemoveIndexIfExists("ClientId_2", "OAuthAccessData")
   485  
   486  		saveSchemaVersion(sqlStore, VERSION_4_10_0)
   487  		sqlStore.GetMaster().Exec("UPDATE Users SET AuthData=LOWER(AuthData) WHERE AuthService = 'saml'")
   488  	}
   489  }
   490  
   491  func UpgradeDatabaseToVersion50(sqlStore SqlStore) {
   492  	// This version of Mattermost includes an App-Layer migration which migrates from hard-coded emojis configured
   493  	// in `config.json` to a `Permission` in the database. The migration code can be seen
   494  	// in the file `app/app.go` in the function `DoEmojisPermissionsMigration()`.
   495  
   496  	// This version of Mattermost also includes a online-migration which migrates some roles from the `Roles` columns of
   497  	// TeamMember and ChannelMember rows to the new SchemeAdmin and SchemeUser columns. If you need to downgrade to a
   498  	// version of Mattermost prior to 5.0, you should take your server offline and run the following SQL statements
   499  	// prior to launching the downgraded version:
   500  	//
   501  	//    UPDATE Teams SET SchemeId = NULL;
   502  	//    UPDATE Channels SET SchemeId = NULL;
   503  	//    UPDATE TeamMembers SET Roles = CONCAT(Roles, ' team_user'), SchemeUser = NULL where SchemeUser = 1;
   504  	//    UPDATE TeamMembers SET Roles = CONCAT(Roles, ' team_admin'), SchemeAdmin = NULL where SchemeAdmin = 1;
   505  	//    UPDATE ChannelMembers SET Roles = CONCAT(Roles, ' channel_user'), SchemeUser = NULL where SchemeUser = 1;
   506  	//    UPDATE ChannelMembers SET Roles = CONCAT(Roles, ' channel_admin'), SchemeAdmin = NULL where SchemeAdmin = 1;
   507  	//    DELETE from Systems WHERE Name = 'migration_advanced_permissions_phase_2';
   508  
   509  	if shouldPerformUpgrade(sqlStore, VERSION_4_10_0, VERSION_5_0_0) {
   510  
   511  		sqlStore.CreateColumnIfNotExistsNoDefault("Teams", "SchemeId", "varchar(26)", "varchar(26)")
   512  		sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "SchemeId", "varchar(26)", "varchar(26)")
   513  
   514  		sqlStore.CreateColumnIfNotExistsNoDefault("TeamMembers", "SchemeUser", "boolean", "boolean")
   515  		sqlStore.CreateColumnIfNotExistsNoDefault("TeamMembers", "SchemeAdmin", "boolean", "boolean")
   516  		sqlStore.CreateColumnIfNotExistsNoDefault("ChannelMembers", "SchemeUser", "boolean", "boolean")
   517  		sqlStore.CreateColumnIfNotExistsNoDefault("ChannelMembers", "SchemeAdmin", "boolean", "boolean")
   518  
   519  		sqlStore.CreateColumnIfNotExists("Roles", "BuiltIn", "boolean", "boolean", "0")
   520  		sqlStore.GetMaster().Exec("UPDATE Roles SET BuiltIn=true")
   521  		sqlStore.GetMaster().Exec("UPDATE Roles SET SchemeManaged=false WHERE Name NOT IN ('system_user', 'system_admin', 'team_user', 'team_admin', 'channel_user', 'channel_admin')")
   522  		sqlStore.CreateColumnIfNotExists("IncomingWebhooks", "ChannelLocked", "boolean", "boolean", "0")
   523  
   524  		sqlStore.RemoveIndexIfExists("idx_channels_txt", "Channels")
   525  
   526  		saveSchemaVersion(sqlStore, VERSION_5_0_0)
   527  	}
   528  }
   529  
   530  func UpgradeDatabaseToVersion51(sqlStore SqlStore) {
   531  	if shouldPerformUpgrade(sqlStore, VERSION_5_0_0, VERSION_5_1_0) {
   532  		saveSchemaVersion(sqlStore, VERSION_5_1_0)
   533  	}
   534  }
   535  
   536  func UpgradeDatabaseToVersion52(sqlStore SqlStore) {
   537  	if shouldPerformUpgrade(sqlStore, VERSION_5_1_0, VERSION_5_2_0) {
   538  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "Username", "varchar(64)", "varchar(64)", "")
   539  		sqlStore.CreateColumnIfNotExists("OutgoingWebhooks", "IconURL", "varchar(1024)", "varchar(1024)", "")
   540  		saveSchemaVersion(sqlStore, VERSION_5_2_0)
   541  	}
   542  }
   543  
   544  func UpgradeDatabaseToVersion53(sqlStore SqlStore) {
   545  	if shouldPerformUpgrade(sqlStore, VERSION_5_2_0, VERSION_5_3_0) {
   546  		saveSchemaVersion(sqlStore, VERSION_5_3_0)
   547  	}
   548  }
   549  
   550  func UpgradeDatabaseToVersion54(sqlStore SqlStore) {
   551  	if shouldPerformUpgrade(sqlStore, VERSION_5_3_0, VERSION_5_4_0) {
   552  		sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "Description", "varchar(500)", "varchar(500)")
   553  		sqlStore.AlterColumnTypeIfExists("IncomingWebhooks", "Description", "varchar(500)", "varchar(500)")
   554  		if err := sqlStore.Channel().MigratePublicChannels(); err != nil {
   555  			mlog.Critical("Failed to migrate PublicChannels table", mlog.Err(err))
   556  			time.Sleep(time.Second)
   557  			os.Exit(EXIT_GENERIC_FAILURE)
   558  		}
   559  		saveSchemaVersion(sqlStore, VERSION_5_4_0)
   560  	}
   561  }
   562  
   563  func UpgradeDatabaseToVersion55(sqlStore SqlStore) {
   564  	if shouldPerformUpgrade(sqlStore, VERSION_5_4_0, VERSION_5_5_0) {
   565  		saveSchemaVersion(sqlStore, VERSION_5_5_0)
   566  	}
   567  }
   568  
   569  func UpgradeDatabaseToVersion56(sqlStore SqlStore) {
   570  	if shouldPerformUpgrade(sqlStore, VERSION_5_5_0, VERSION_5_6_0) {
   571  		sqlStore.CreateColumnIfNotExists("PluginKeyValueStore", "ExpireAt", "bigint(20)", "bigint", "0")
   572  
   573  		// migrating user's accepted terms of service data into the new table
   574  		sqlStore.GetMaster().Exec("INSERT INTO UserTermsOfService SELECT Id, AcceptedTermsOfServiceId as TermsOfServiceId, :CreateAt FROM Users WHERE AcceptedTermsOfServiceId != \"\" AND AcceptedTermsOfServiceId IS NOT NULL", map[string]interface{}{"CreateAt": model.GetMillis()})
   575  
   576  		if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   577  			sqlStore.RemoveIndexIfExists("idx_users_email_lower", "lower(Email)")
   578  			sqlStore.RemoveIndexIfExists("idx_users_username_lower", "lower(Username)")
   579  			sqlStore.RemoveIndexIfExists("idx_users_nickname_lower", "lower(Nickname)")
   580  			sqlStore.RemoveIndexIfExists("idx_users_firstname_lower", "lower(FirstName)")
   581  			sqlStore.RemoveIndexIfExists("idx_users_lastname_lower", "lower(LastName)")
   582  		}
   583  
   584  		saveSchemaVersion(sqlStore, VERSION_5_6_0)
   585  	}
   586  
   587  }
   588  
   589  func UpgradeDatabaseToVersion57(sqlStore SqlStore) {
   590  	if shouldPerformUpgrade(sqlStore, VERSION_5_6_0, VERSION_5_7_0) {
   591  		saveSchemaVersion(sqlStore, VERSION_5_7_0)
   592  	}
   593  }
   594  
   595  func getRole(sqlStore SqlStore, name string) (*model.Role, error) {
   596  	var dbRole Role
   597  
   598  	if err := sqlStore.GetReplica().SelectOne(&dbRole, "SELECT * from Roles WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil {
   599  		if err == sql.ErrNoRows {
   600  			return nil, errors.Wrapf(err, "failed to find role %s", name)
   601  		} else {
   602  			return nil, errors.Wrapf(err, "failed to query role %s", name)
   603  		}
   604  	}
   605  
   606  	return dbRole.ToModel(), nil
   607  }
   608  
   609  func saveRole(sqlStore SqlStore, role *model.Role) error {
   610  	dbRole := NewRoleFromModel(role)
   611  
   612  	dbRole.UpdateAt = model.GetMillis()
   613  	if rowsChanged, err := sqlStore.GetMaster().Update(dbRole); err != nil {
   614  		return errors.Wrap(err, "failed to update role")
   615  	} else if rowsChanged != 1 {
   616  		return errors.New("found no role to update")
   617  	}
   618  
   619  	return nil
   620  }
   621  
   622  func UpgradeDatabaseToVersion58(sqlStore SqlStore) {
   623  	if shouldPerformUpgrade(sqlStore, VERSION_5_7_0, VERSION_5_8_0) {
   624  		// idx_channels_txt was removed in `UpgradeDatabaseToVersion50`, but merged as part of
   625  		// v5.1, so the migration wouldn't apply to anyone upgrading from v5.0. Remove it again to
   626  		// bring the upgraded (from v5.0) and fresh install schemas back in sync.
   627  		sqlStore.RemoveIndexIfExists("idx_channels_txt", "Channels")
   628  
   629  		// Fix column types and defaults where gorp converged on a different schema value than the
   630  		// original migration.
   631  		sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "Description", "text", "VARCHAR(500)")
   632  		sqlStore.AlterColumnTypeIfExists("IncomingWebhooks", "Description", "text", "VARCHAR(500)")
   633  		sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "IconURL", "text", "VARCHAR(1024)")
   634  		sqlStore.AlterColumnDefaultIfExists("OutgoingWebhooks", "Username", model.NewString("NULL"), model.NewString(""))
   635  		sqlStore.AlterColumnDefaultIfExists("OutgoingWebhooks", "IconURL", nil, model.NewString(""))
   636  		sqlStore.AlterColumnDefaultIfExists("PluginKeyValueStore", "ExpireAt", model.NewString("NULL"), model.NewString("NULL"))
   637  
   638  		saveSchemaVersion(sqlStore, VERSION_5_8_0)
   639  	}
   640  }
   641  
   642  func UpgradeDatabaseToVersion59(sqlStore SqlStore) {
   643  	if shouldPerformUpgrade(sqlStore, VERSION_5_8_0, VERSION_5_9_0) {
   644  		saveSchemaVersion(sqlStore, VERSION_5_9_0)
   645  	}
   646  }
   647  
   648  func UpgradeDatabaseToVersion510(sqlStore SqlStore) {
   649  	if shouldPerformUpgrade(sqlStore, VERSION_5_9_0, VERSION_5_10_0) {
   650  		sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "GroupConstrained", "tinyint(4)", "boolean")
   651  		sqlStore.CreateColumnIfNotExistsNoDefault("Teams", "GroupConstrained", "tinyint(4)", "boolean")
   652  
   653  		saveSchemaVersion(sqlStore, VERSION_5_10_0)
   654  	}
   655  }
   656  
   657  func UpgradeDatabaseToVersion511(sqlStore SqlStore) {
   658  	if shouldPerformUpgrade(sqlStore, VERSION_5_10_0, VERSION_5_11_0) {
   659  		// Enforce all teams have an InviteID set
   660  		var teams []*model.Team
   661  		if _, err := sqlStore.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE InviteId = ''"); err != nil {
   662  			mlog.Error("Error fetching Teams without InviteID: " + err.Error())
   663  		} else {
   664  			for _, team := range teams {
   665  				team.InviteId = model.NewId()
   666  				if res := <-sqlStore.Team().Update(team); res.Err != nil {
   667  					mlog.Error("Error updating Team InviteIDs: " + res.Err.Error())
   668  				}
   669  			}
   670  		}
   671  
   672  		saveSchemaVersion(sqlStore, VERSION_5_11_0)
   673  	}
   674  }