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  }