github.com/lologarithm/mattermost-server@v5.3.2-0.20181002060438-c82a84ed765b+incompatible/store/sqlstore/supplier.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  	"context"
     8  	dbsql "database/sql"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	sqltrace "log"
    13  	"os"
    14  	"strings"
    15  	"sync/atomic"
    16  	"time"
    17  
    18  	"github.com/go-sql-driver/mysql"
    19  	"github.com/lib/pq"
    20  	"github.com/mattermost/gorp"
    21  	"github.com/mattermost/mattermost-server/einterfaces"
    22  	"github.com/mattermost/mattermost-server/mlog"
    23  	"github.com/mattermost/mattermost-server/model"
    24  	"github.com/mattermost/mattermost-server/store"
    25  	"github.com/mattermost/mattermost-server/utils"
    26  )
    27  
    28  const (
    29  	INDEX_TYPE_FULL_TEXT = "full_text"
    30  	INDEX_TYPE_DEFAULT   = "default"
    31  	DB_PING_ATTEMPTS     = 18
    32  	DB_PING_TIMEOUT_SECS = 10
    33  )
    34  
    35  const (
    36  	EXIT_GENERIC_FAILURE             = 1
    37  	EXIT_CREATE_TABLE                = 100
    38  	EXIT_DB_OPEN                     = 101
    39  	EXIT_PING                        = 102
    40  	EXIT_NO_DRIVER                   = 103
    41  	EXIT_TABLE_EXISTS                = 104
    42  	EXIT_TABLE_EXISTS_MYSQL          = 105
    43  	EXIT_COLUMN_EXISTS               = 106
    44  	EXIT_DOES_COLUMN_EXISTS_POSTGRES = 107
    45  	EXIT_DOES_COLUMN_EXISTS_MYSQL    = 108
    46  	EXIT_DOES_COLUMN_EXISTS_MISSING  = 109
    47  	EXIT_CREATE_COLUMN_POSTGRES      = 110
    48  	EXIT_CREATE_COLUMN_MYSQL         = 111
    49  	EXIT_CREATE_COLUMN_MISSING       = 112
    50  	EXIT_REMOVE_COLUMN               = 113
    51  	EXIT_RENAME_COLUMN               = 114
    52  	EXIT_MAX_COLUMN                  = 115
    53  	EXIT_ALTER_COLUMN                = 116
    54  	EXIT_CREATE_INDEX_POSTGRES       = 117
    55  	EXIT_CREATE_INDEX_MYSQL          = 118
    56  	EXIT_CREATE_INDEX_FULL_MYSQL     = 119
    57  	EXIT_CREATE_INDEX_MISSING        = 120
    58  	EXIT_REMOVE_INDEX_POSTGRES       = 121
    59  	EXIT_REMOVE_INDEX_MYSQL          = 122
    60  	EXIT_REMOVE_INDEX_MISSING        = 123
    61  	EXIT_REMOVE_TABLE                = 134
    62  	EXIT_CREATE_INDEX_SQLITE         = 135
    63  	EXIT_REMOVE_INDEX_SQLITE         = 136
    64  	EXIT_TABLE_EXISTS_SQLITE         = 137
    65  	EXIT_DOES_COLUMN_EXISTS_SQLITE   = 138
    66  )
    67  
    68  type SqlSupplierOldStores struct {
    69  	team                 store.TeamStore
    70  	channel              store.ChannelStore
    71  	post                 store.PostStore
    72  	user                 store.UserStore
    73  	audit                store.AuditStore
    74  	cluster              store.ClusterDiscoveryStore
    75  	compliance           store.ComplianceStore
    76  	session              store.SessionStore
    77  	oauth                store.OAuthStore
    78  	system               store.SystemStore
    79  	webhook              store.WebhookStore
    80  	command              store.CommandStore
    81  	commandWebhook       store.CommandWebhookStore
    82  	preference           store.PreferenceStore
    83  	license              store.LicenseStore
    84  	token                store.TokenStore
    85  	emoji                store.EmojiStore
    86  	status               store.StatusStore
    87  	fileInfo             store.FileInfoStore
    88  	reaction             store.ReactionStore
    89  	job                  store.JobStore
    90  	userAccessToken      store.UserAccessTokenStore
    91  	plugin               store.PluginStore
    92  	channelMemberHistory store.ChannelMemberHistoryStore
    93  	role                 store.RoleStore
    94  	scheme               store.SchemeStore
    95  	serviceTerms         store.ServiceTermsStore
    96  }
    97  
    98  type SqlSupplier struct {
    99  	// rrCounter and srCounter should be kept first.
   100  	// See https://github.com/mattermost/mattermost-server/pull/7281
   101  	rrCounter      int64
   102  	srCounter      int64
   103  	next           store.LayeredStoreSupplier
   104  	master         *gorp.DbMap
   105  	replicas       []*gorp.DbMap
   106  	searchReplicas []*gorp.DbMap
   107  	oldStores      SqlSupplierOldStores
   108  	settings       *model.SqlSettings
   109  	lockedToMaster bool
   110  }
   111  
   112  func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInterface) *SqlSupplier {
   113  	supplier := &SqlSupplier{
   114  		rrCounter: 0,
   115  		srCounter: 0,
   116  		settings:  &settings,
   117  	}
   118  
   119  	supplier.initConnection()
   120  
   121  	enableExperimentalPublicChannelsMaterialization := true
   122  	if settings.EnablePublicChannelsMaterialization != nil && !*settings.EnablePublicChannelsMaterialization {
   123  		enableExperimentalPublicChannelsMaterialization = false
   124  	}
   125  
   126  	supplier.oldStores.team = NewSqlTeamStore(supplier)
   127  	supplier.oldStores.channel = NewSqlChannelStoreExperimental(supplier, metrics, enableExperimentalPublicChannelsMaterialization)
   128  	supplier.oldStores.post = NewSqlPostStore(supplier, metrics)
   129  	supplier.oldStores.user = NewSqlUserStore(supplier, metrics)
   130  	supplier.oldStores.audit = NewSqlAuditStore(supplier)
   131  	supplier.oldStores.cluster = NewSqlClusterDiscoveryStore(supplier)
   132  	supplier.oldStores.compliance = NewSqlComplianceStore(supplier)
   133  	supplier.oldStores.session = NewSqlSessionStore(supplier)
   134  	supplier.oldStores.oauth = NewSqlOAuthStore(supplier)
   135  	supplier.oldStores.system = NewSqlSystemStore(supplier)
   136  	supplier.oldStores.webhook = NewSqlWebhookStore(supplier, metrics)
   137  	supplier.oldStores.command = NewSqlCommandStore(supplier)
   138  	supplier.oldStores.commandWebhook = NewSqlCommandWebhookStore(supplier)
   139  	supplier.oldStores.preference = NewSqlPreferenceStore(supplier)
   140  	supplier.oldStores.license = NewSqlLicenseStore(supplier)
   141  	supplier.oldStores.token = NewSqlTokenStore(supplier)
   142  	supplier.oldStores.emoji = NewSqlEmojiStore(supplier, metrics)
   143  	supplier.oldStores.status = NewSqlStatusStore(supplier)
   144  	supplier.oldStores.fileInfo = NewSqlFileInfoStore(supplier, metrics)
   145  	supplier.oldStores.job = NewSqlJobStore(supplier)
   146  	supplier.oldStores.userAccessToken = NewSqlUserAccessTokenStore(supplier)
   147  	supplier.oldStores.channelMemberHistory = NewSqlChannelMemberHistoryStore(supplier)
   148  	supplier.oldStores.plugin = NewSqlPluginStore(supplier)
   149  	supplier.oldStores.serviceTerms = NewSqlTermStore(supplier, metrics)
   150  
   151  	initSqlSupplierReactions(supplier)
   152  	initSqlSupplierRoles(supplier)
   153  	initSqlSupplierSchemes(supplier)
   154  
   155  	err := supplier.GetMaster().CreateTablesIfNotExists()
   156  	if err != nil {
   157  		mlog.Critical(fmt.Sprintf("Error creating database tables: %v", err))
   158  		time.Sleep(time.Second)
   159  		os.Exit(EXIT_CREATE_TABLE)
   160  	}
   161  
   162  	UpgradeDatabase(supplier)
   163  
   164  	supplier.oldStores.team.(*SqlTeamStore).CreateIndexesIfNotExists()
   165  	supplier.oldStores.channel.(*SqlChannelStoreExperimental).CreateIndexesIfNotExists()
   166  	supplier.oldStores.post.(*SqlPostStore).CreateIndexesIfNotExists()
   167  	supplier.oldStores.user.(*SqlUserStore).CreateIndexesIfNotExists()
   168  	supplier.oldStores.audit.(*SqlAuditStore).CreateIndexesIfNotExists()
   169  	supplier.oldStores.compliance.(*SqlComplianceStore).CreateIndexesIfNotExists()
   170  	supplier.oldStores.session.(*SqlSessionStore).CreateIndexesIfNotExists()
   171  	supplier.oldStores.oauth.(*SqlOAuthStore).CreateIndexesIfNotExists()
   172  	supplier.oldStores.system.(*SqlSystemStore).CreateIndexesIfNotExists()
   173  	supplier.oldStores.webhook.(*SqlWebhookStore).CreateIndexesIfNotExists()
   174  	supplier.oldStores.command.(*SqlCommandStore).CreateIndexesIfNotExists()
   175  	supplier.oldStores.commandWebhook.(*SqlCommandWebhookStore).CreateIndexesIfNotExists()
   176  	supplier.oldStores.preference.(*SqlPreferenceStore).CreateIndexesIfNotExists()
   177  	supplier.oldStores.license.(*SqlLicenseStore).CreateIndexesIfNotExists()
   178  	supplier.oldStores.token.(*SqlTokenStore).CreateIndexesIfNotExists()
   179  	supplier.oldStores.emoji.(*SqlEmojiStore).CreateIndexesIfNotExists()
   180  	supplier.oldStores.status.(*SqlStatusStore).CreateIndexesIfNotExists()
   181  	supplier.oldStores.fileInfo.(*SqlFileInfoStore).CreateIndexesIfNotExists()
   182  	supplier.oldStores.job.(*SqlJobStore).CreateIndexesIfNotExists()
   183  	supplier.oldStores.userAccessToken.(*SqlUserAccessTokenStore).CreateIndexesIfNotExists()
   184  	supplier.oldStores.plugin.(*SqlPluginStore).CreateIndexesIfNotExists()
   185  	supplier.oldStores.serviceTerms.(SqlServiceTermsStore).CreateIndexesIfNotExists()
   186  
   187  	supplier.oldStores.preference.(*SqlPreferenceStore).DeleteUnusedFeatures()
   188  
   189  	return supplier
   190  }
   191  
   192  func (s *SqlSupplier) SetChainNext(next store.LayeredStoreSupplier) {
   193  	s.next = next
   194  }
   195  
   196  func (s *SqlSupplier) Next() store.LayeredStoreSupplier {
   197  	return s.next
   198  }
   199  
   200  func setupConnection(con_type string, dataSource string, settings *model.SqlSettings) *gorp.DbMap {
   201  	db, err := dbsql.Open(*settings.DriverName, dataSource)
   202  	if err != nil {
   203  		mlog.Critical(fmt.Sprintf("Failed to open SQL connection to err:%v", err.Error()))
   204  		time.Sleep(time.Second)
   205  		os.Exit(EXIT_DB_OPEN)
   206  	}
   207  
   208  	for i := 0; i < DB_PING_ATTEMPTS; i++ {
   209  		mlog.Info(fmt.Sprintf("Pinging SQL %v database", con_type))
   210  		ctx, cancel := context.WithTimeout(context.Background(), DB_PING_TIMEOUT_SECS*time.Second)
   211  		defer cancel()
   212  		err = db.PingContext(ctx)
   213  		if err == nil {
   214  			break
   215  		} else {
   216  			if i == DB_PING_ATTEMPTS-1 {
   217  				mlog.Critical(fmt.Sprintf("Failed to ping DB, server will exit err=%v", err))
   218  				time.Sleep(time.Second)
   219  				os.Exit(EXIT_PING)
   220  			} else {
   221  				mlog.Error(fmt.Sprintf("Failed to ping DB retrying in %v seconds err=%v", DB_PING_TIMEOUT_SECS, err))
   222  				time.Sleep(DB_PING_TIMEOUT_SECS * time.Second)
   223  			}
   224  		}
   225  	}
   226  
   227  	db.SetMaxIdleConns(*settings.MaxIdleConns)
   228  	db.SetMaxOpenConns(*settings.MaxOpenConns)
   229  	db.SetConnMaxLifetime(time.Duration(*settings.ConnMaxLifetimeMilliseconds) * time.Millisecond)
   230  
   231  	var dbmap *gorp.DbMap
   232  
   233  	connectionTimeout := time.Duration(*settings.QueryTimeout) * time.Second
   234  
   235  	if *settings.DriverName == model.DATABASE_DRIVER_SQLITE {
   236  		dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.SqliteDialect{}, QueryTimeout: connectionTimeout}
   237  	} else if *settings.DriverName == model.DATABASE_DRIVER_MYSQL {
   238  		dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8MB4"}, QueryTimeout: connectionTimeout}
   239  	} else if *settings.DriverName == model.DATABASE_DRIVER_POSTGRES {
   240  		dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.PostgresDialect{}, QueryTimeout: connectionTimeout}
   241  	} else {
   242  		mlog.Critical("Failed to create dialect specific driver")
   243  		time.Sleep(time.Second)
   244  		os.Exit(EXIT_NO_DRIVER)
   245  	}
   246  
   247  	if settings.Trace {
   248  		dbmap.TraceOn("", sqltrace.New(os.Stdout, "sql-trace:", sqltrace.Lmicroseconds))
   249  	}
   250  
   251  	return dbmap
   252  }
   253  
   254  func (s *SqlSupplier) initConnection() {
   255  	s.master = setupConnection("master", *s.settings.DataSource, s.settings)
   256  
   257  	if len(s.settings.DataSourceReplicas) > 0 {
   258  		s.replicas = make([]*gorp.DbMap, len(s.settings.DataSourceReplicas))
   259  		for i, replica := range s.settings.DataSourceReplicas {
   260  			s.replicas[i] = setupConnection(fmt.Sprintf("replica-%v", i), replica, s.settings)
   261  		}
   262  	}
   263  
   264  	if len(s.settings.DataSourceSearchReplicas) > 0 {
   265  		s.searchReplicas = make([]*gorp.DbMap, len(s.settings.DataSourceSearchReplicas))
   266  		for i, replica := range s.settings.DataSourceSearchReplicas {
   267  			s.searchReplicas[i] = setupConnection(fmt.Sprintf("search-replica-%v", i), replica, s.settings)
   268  		}
   269  	}
   270  }
   271  
   272  func (ss *SqlSupplier) DriverName() string {
   273  	return *ss.settings.DriverName
   274  }
   275  
   276  func (ss *SqlSupplier) GetCurrentSchemaVersion() string {
   277  	version, _ := ss.GetMaster().SelectStr("SELECT Value FROM Systems WHERE Name='Version'")
   278  	return version
   279  }
   280  
   281  func (ss *SqlSupplier) GetMaster() *gorp.DbMap {
   282  	return ss.master
   283  }
   284  
   285  func (ss *SqlSupplier) GetSearchReplica() *gorp.DbMap {
   286  	if len(ss.settings.DataSourceSearchReplicas) == 0 {
   287  		return ss.GetReplica()
   288  	}
   289  
   290  	rrNum := atomic.AddInt64(&ss.srCounter, 1) % int64(len(ss.searchReplicas))
   291  	return ss.searchReplicas[rrNum]
   292  }
   293  
   294  func (ss *SqlSupplier) GetReplica() *gorp.DbMap {
   295  	if len(ss.settings.DataSourceReplicas) == 0 || ss.lockedToMaster {
   296  		return ss.GetMaster()
   297  	}
   298  
   299  	rrNum := atomic.AddInt64(&ss.rrCounter, 1) % int64(len(ss.replicas))
   300  	return ss.replicas[rrNum]
   301  }
   302  
   303  func (ss *SqlSupplier) TotalMasterDbConnections() int {
   304  	return ss.GetMaster().Db.Stats().OpenConnections
   305  }
   306  
   307  func (ss *SqlSupplier) TotalReadDbConnections() int {
   308  	if len(ss.settings.DataSourceReplicas) == 0 {
   309  		return 0
   310  	}
   311  
   312  	count := 0
   313  	for _, db := range ss.replicas {
   314  		count = count + db.Db.Stats().OpenConnections
   315  	}
   316  
   317  	return count
   318  }
   319  
   320  func (ss *SqlSupplier) TotalSearchDbConnections() int {
   321  	if len(ss.settings.DataSourceSearchReplicas) == 0 {
   322  		return 0
   323  	}
   324  
   325  	count := 0
   326  	for _, db := range ss.searchReplicas {
   327  		count = count + db.Db.Stats().OpenConnections
   328  	}
   329  
   330  	return count
   331  }
   332  
   333  func (ss *SqlSupplier) MarkSystemRanUnitTests() {
   334  	if result := <-ss.System().Get(); result.Err == nil {
   335  		props := result.Data.(model.StringMap)
   336  		unitTests := props[model.SYSTEM_RAN_UNIT_TESTS]
   337  		if len(unitTests) == 0 {
   338  			systemTests := &model.System{Name: model.SYSTEM_RAN_UNIT_TESTS, Value: "1"}
   339  			<-ss.System().Save(systemTests)
   340  		}
   341  	}
   342  }
   343  
   344  func (ss *SqlSupplier) DoesTableExist(tableName string) bool {
   345  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   346  		count, err := ss.GetMaster().SelectInt(
   347  			`SELECT count(relname) FROM pg_class WHERE relname=$1`,
   348  			strings.ToLower(tableName),
   349  		)
   350  
   351  		if err != nil {
   352  			mlog.Critical(fmt.Sprintf("Failed to check if table exists %v", err))
   353  			time.Sleep(time.Second)
   354  			os.Exit(EXIT_TABLE_EXISTS)
   355  		}
   356  
   357  		return count > 0
   358  
   359  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   360  
   361  		count, err := ss.GetMaster().SelectInt(
   362  			`SELECT
   363  		    COUNT(0) AS table_exists
   364  			FROM
   365  			    information_schema.TABLES
   366  			WHERE
   367  			    TABLE_SCHEMA = DATABASE()
   368  			        AND TABLE_NAME = ?
   369  		    `,
   370  			tableName,
   371  		)
   372  
   373  		if err != nil {
   374  			mlog.Critical(fmt.Sprintf("Failed to check if table exists %v", err))
   375  			time.Sleep(time.Second)
   376  			os.Exit(EXIT_TABLE_EXISTS_MYSQL)
   377  		}
   378  
   379  		return count > 0
   380  
   381  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   382  		count, err := ss.GetMaster().SelectInt(
   383  			`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
   384  			tableName,
   385  		)
   386  
   387  		if err != nil {
   388  			mlog.Critical(fmt.Sprintf("Failed to check if table exists %v", err))
   389  			time.Sleep(time.Second)
   390  			os.Exit(EXIT_TABLE_EXISTS_SQLITE)
   391  		}
   392  
   393  		return count > 0
   394  
   395  	} else {
   396  		mlog.Critical("Failed to check if column exists because of missing driver")
   397  		time.Sleep(time.Second)
   398  		os.Exit(EXIT_COLUMN_EXISTS)
   399  		return false
   400  	}
   401  }
   402  
   403  func (ss *SqlSupplier) DoesColumnExist(tableName string, columnName string) bool {
   404  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   405  		count, err := ss.GetMaster().SelectInt(
   406  			`SELECT COUNT(0)
   407  			FROM   pg_attribute
   408  			WHERE  attrelid = $1::regclass
   409  			AND    attname = $2
   410  			AND    NOT attisdropped`,
   411  			strings.ToLower(tableName),
   412  			strings.ToLower(columnName),
   413  		)
   414  
   415  		if err != nil {
   416  			if err.Error() == "pq: relation \""+strings.ToLower(tableName)+"\" does not exist" {
   417  				return false
   418  			}
   419  
   420  			mlog.Critical(fmt.Sprintf("Failed to check if column exists %v", err))
   421  			time.Sleep(time.Second)
   422  			os.Exit(EXIT_DOES_COLUMN_EXISTS_POSTGRES)
   423  		}
   424  
   425  		return count > 0
   426  
   427  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   428  
   429  		count, err := ss.GetMaster().SelectInt(
   430  			`SELECT
   431  		    COUNT(0) AS column_exists
   432  		FROM
   433  		    information_schema.COLUMNS
   434  		WHERE
   435  		    TABLE_SCHEMA = DATABASE()
   436  		        AND TABLE_NAME = ?
   437  		        AND COLUMN_NAME = ?`,
   438  			tableName,
   439  			columnName,
   440  		)
   441  
   442  		if err != nil {
   443  			mlog.Critical(fmt.Sprintf("Failed to check if column exists %v", err))
   444  			time.Sleep(time.Second)
   445  			os.Exit(EXIT_DOES_COLUMN_EXISTS_MYSQL)
   446  		}
   447  
   448  		return count > 0
   449  
   450  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   451  		count, err := ss.GetMaster().SelectInt(
   452  			`SELECT COUNT(*) FROM pragma_table_info(?) WHERE name=?`,
   453  			tableName,
   454  			columnName,
   455  		)
   456  
   457  		if err != nil {
   458  			mlog.Critical(fmt.Sprintf("Failed to check if column exists %v", err))
   459  			time.Sleep(time.Second)
   460  			os.Exit(EXIT_DOES_COLUMN_EXISTS_SQLITE)
   461  		}
   462  
   463  		return count > 0
   464  
   465  	} else {
   466  		mlog.Critical("Failed to check if column exists because of missing driver")
   467  		time.Sleep(time.Second)
   468  		os.Exit(EXIT_DOES_COLUMN_EXISTS_MISSING)
   469  		return false
   470  	}
   471  }
   472  
   473  func (ss *SqlSupplier) DoesTriggerExist(triggerName string) bool {
   474  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   475  		count, err := ss.GetMaster().SelectInt(`
   476  			SELECT
   477  				COUNT(0)
   478  			FROM
   479  				pg_trigger
   480  			WHERE
   481  				tgname = $1
   482  		`, triggerName)
   483  
   484  		if err != nil {
   485  			mlog.Critical(fmt.Sprintf("Failed to check if trigger exists %v", err))
   486  			time.Sleep(time.Second)
   487  			os.Exit(EXIT_GENERIC_FAILURE)
   488  		}
   489  
   490  		return count > 0
   491  
   492  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   493  		count, err := ss.GetMaster().SelectInt(`
   494  			SELECT
   495  				COUNT(0)
   496  			FROM
   497  				information_schema.triggers
   498  			WHERE
   499  				trigger_schema = DATABASE()
   500  			AND	trigger_name = ?
   501  		`, triggerName)
   502  
   503  		if err != nil {
   504  			mlog.Critical(fmt.Sprintf("Failed to check if trigger exists %v", err))
   505  			time.Sleep(time.Second)
   506  			os.Exit(EXIT_GENERIC_FAILURE)
   507  		}
   508  
   509  		return count > 0
   510  
   511  	} else {
   512  		mlog.Critical("Failed to check if column exists because of missing driver")
   513  		time.Sleep(time.Second)
   514  		os.Exit(EXIT_GENERIC_FAILURE)
   515  		return false
   516  	}
   517  }
   518  
   519  func (ss *SqlSupplier) CreateColumnIfNotExists(tableName string, columnName string, mySqlColType string, postgresColType string, defaultValue string) bool {
   520  
   521  	if ss.DoesColumnExist(tableName, columnName) {
   522  		return false
   523  	}
   524  
   525  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   526  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + postgresColType + " DEFAULT '" + defaultValue + "'")
   527  		if err != nil {
   528  			mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
   529  			time.Sleep(time.Second)
   530  			os.Exit(EXIT_CREATE_COLUMN_POSTGRES)
   531  		}
   532  
   533  		return true
   534  
   535  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   536  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + mySqlColType + " DEFAULT '" + defaultValue + "'")
   537  		if err != nil {
   538  			mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
   539  			time.Sleep(time.Second)
   540  			os.Exit(EXIT_CREATE_COLUMN_MYSQL)
   541  		}
   542  
   543  		return true
   544  
   545  	} else {
   546  		mlog.Critical("Failed to create column because of missing driver")
   547  		time.Sleep(time.Second)
   548  		os.Exit(EXIT_CREATE_COLUMN_MISSING)
   549  		return false
   550  	}
   551  }
   552  
   553  func (ss *SqlSupplier) CreateColumnIfNotExistsNoDefault(tableName string, columnName string, mySqlColType string, postgresColType string) bool {
   554  
   555  	if ss.DoesColumnExist(tableName, columnName) {
   556  		return false
   557  	}
   558  
   559  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   560  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + postgresColType)
   561  		if err != nil {
   562  			mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
   563  			time.Sleep(time.Second)
   564  			os.Exit(EXIT_CREATE_COLUMN_POSTGRES)
   565  		}
   566  
   567  		return true
   568  
   569  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   570  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + mySqlColType)
   571  		if err != nil {
   572  			mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
   573  			time.Sleep(time.Second)
   574  			os.Exit(EXIT_CREATE_COLUMN_MYSQL)
   575  		}
   576  
   577  		return true
   578  
   579  	} else {
   580  		mlog.Critical("Failed to create column because of missing driver")
   581  		time.Sleep(time.Second)
   582  		os.Exit(EXIT_CREATE_COLUMN_MISSING)
   583  		return false
   584  	}
   585  }
   586  
   587  func (ss *SqlSupplier) RemoveColumnIfExists(tableName string, columnName string) bool {
   588  
   589  	if !ss.DoesColumnExist(tableName, columnName) {
   590  		return false
   591  	}
   592  
   593  	_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
   594  	if err != nil {
   595  		mlog.Critical(fmt.Sprintf("Failed to drop column %v", err))
   596  		time.Sleep(time.Second)
   597  		os.Exit(EXIT_REMOVE_COLUMN)
   598  	}
   599  
   600  	return true
   601  }
   602  
   603  func (ss *SqlSupplier) RemoveTableIfExists(tableName string) bool {
   604  	if !ss.DoesTableExist(tableName) {
   605  		return false
   606  	}
   607  
   608  	_, err := ss.GetMaster().ExecNoTimeout("DROP TABLE " + tableName)
   609  	if err != nil {
   610  		mlog.Critical(fmt.Sprintf("Failed to drop table %v", err))
   611  		time.Sleep(time.Second)
   612  		os.Exit(EXIT_REMOVE_TABLE)
   613  	}
   614  
   615  	return true
   616  }
   617  
   618  func (ss *SqlSupplier) RenameColumnIfExists(tableName string, oldColumnName string, newColumnName string, colType string) bool {
   619  	if !ss.DoesColumnExist(tableName, oldColumnName) {
   620  		return false
   621  	}
   622  
   623  	var err error
   624  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   625  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " CHANGE " + oldColumnName + " " + newColumnName + " " + colType)
   626  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   627  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " RENAME COLUMN " + oldColumnName + " TO " + newColumnName)
   628  	}
   629  
   630  	if err != nil {
   631  		mlog.Critical(fmt.Sprintf("Failed to rename column %v", err))
   632  		time.Sleep(time.Second)
   633  		os.Exit(EXIT_RENAME_COLUMN)
   634  	}
   635  
   636  	return true
   637  }
   638  
   639  func (ss *SqlSupplier) GetMaxLengthOfColumnIfExists(tableName string, columnName string) string {
   640  	if !ss.DoesColumnExist(tableName, columnName) {
   641  		return ""
   642  	}
   643  
   644  	var result string
   645  	var err error
   646  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   647  		result, err = ss.GetMaster().SelectStr("SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.columns WHERE table_name = '" + tableName + "' AND COLUMN_NAME = '" + columnName + "'")
   648  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   649  		result, err = ss.GetMaster().SelectStr("SELECT character_maximum_length FROM information_schema.columns WHERE table_name = '" + strings.ToLower(tableName) + "' AND column_name = '" + strings.ToLower(columnName) + "'")
   650  	}
   651  
   652  	if err != nil {
   653  		mlog.Critical(fmt.Sprintf("Failed to get max length of column %v", err))
   654  		time.Sleep(time.Second)
   655  		os.Exit(EXIT_MAX_COLUMN)
   656  	}
   657  
   658  	return result
   659  }
   660  
   661  func (ss *SqlSupplier) AlterColumnTypeIfExists(tableName string, columnName string, mySqlColType string, postgresColType string) bool {
   662  	if !ss.DoesColumnExist(tableName, columnName) {
   663  		return false
   664  	}
   665  
   666  	var err error
   667  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   668  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " MODIFY " + columnName + " " + mySqlColType)
   669  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   670  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + strings.ToLower(tableName) + " ALTER COLUMN " + strings.ToLower(columnName) + " TYPE " + postgresColType)
   671  	}
   672  
   673  	if err != nil {
   674  		mlog.Critical(fmt.Sprintf("Failed to alter column type %v", err))
   675  		time.Sleep(time.Second)
   676  		os.Exit(EXIT_ALTER_COLUMN)
   677  	}
   678  
   679  	return true
   680  }
   681  
   682  func (ss *SqlSupplier) CreateUniqueIndexIfNotExists(indexName string, tableName string, columnName string) bool {
   683  	return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_DEFAULT, true)
   684  }
   685  
   686  func (ss *SqlSupplier) CreateIndexIfNotExists(indexName string, tableName string, columnName string) bool {
   687  	return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_DEFAULT, false)
   688  }
   689  
   690  func (ss *SqlSupplier) CreateCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool {
   691  	return ss.createIndexIfNotExists(indexName, tableName, columnNames, INDEX_TYPE_DEFAULT, false)
   692  }
   693  
   694  func (ss *SqlSupplier) CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) bool {
   695  	return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_FULL_TEXT, false)
   696  }
   697  
   698  func (ss *SqlSupplier) createIndexIfNotExists(indexName string, tableName string, columnNames []string, indexType string, unique bool) bool {
   699  
   700  	uniqueStr := ""
   701  	if unique {
   702  		uniqueStr = "UNIQUE "
   703  	}
   704  
   705  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   706  		_, errExists := ss.GetMaster().SelectStr("SELECT $1::regclass", indexName)
   707  		// It should fail if the index does not exist
   708  		if errExists == nil {
   709  			return false
   710  		}
   711  
   712  		query := ""
   713  		if indexType == INDEX_TYPE_FULL_TEXT {
   714  			if len(columnNames) != 1 {
   715  				mlog.Critical("Unable to create multi column full text index")
   716  				os.Exit(EXIT_CREATE_INDEX_POSTGRES)
   717  			}
   718  			columnName := columnNames[0]
   719  			postgresColumnNames := convertMySQLFullTextColumnsToPostgres(columnName)
   720  			query = "CREATE INDEX " + indexName + " ON " + tableName + " USING gin(to_tsvector('english', " + postgresColumnNames + "))"
   721  		} else {
   722  			query = "CREATE " + uniqueStr + "INDEX " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")"
   723  		}
   724  
   725  		_, err := ss.GetMaster().ExecNoTimeout(query)
   726  		if err != nil {
   727  			mlog.Critical(fmt.Sprintf("Failed to create index %v, %v", errExists, err))
   728  			time.Sleep(time.Second)
   729  			os.Exit(EXIT_CREATE_INDEX_POSTGRES)
   730  		}
   731  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   732  
   733  		count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName)
   734  		if err != nil {
   735  			mlog.Critical(fmt.Sprintf("Failed to check index %v", err))
   736  			time.Sleep(time.Second)
   737  			os.Exit(EXIT_CREATE_INDEX_MYSQL)
   738  		}
   739  
   740  		if count > 0 {
   741  			return false
   742  		}
   743  
   744  		fullTextIndex := ""
   745  		if indexType == INDEX_TYPE_FULL_TEXT {
   746  			fullTextIndex = " FULLTEXT "
   747  		}
   748  
   749  		_, err = ss.GetMaster().ExecNoTimeout("CREATE  " + uniqueStr + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")")
   750  		if err != nil {
   751  			mlog.Critical(fmt.Sprintf("Failed to create index %v", err))
   752  			time.Sleep(time.Second)
   753  			os.Exit(EXIT_CREATE_INDEX_FULL_MYSQL)
   754  		}
   755  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   756  		_, err := ss.GetMaster().ExecNoTimeout("CREATE INDEX IF NOT EXISTS " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")")
   757  		if err != nil {
   758  			mlog.Critical(fmt.Sprintf("Failed to create index %v", err))
   759  			time.Sleep(time.Second)
   760  			os.Exit(EXIT_CREATE_INDEX_SQLITE)
   761  		}
   762  	} else {
   763  		mlog.Critical("Failed to create index because of missing driver")
   764  		time.Sleep(time.Second)
   765  		os.Exit(EXIT_CREATE_INDEX_MISSING)
   766  	}
   767  
   768  	return true
   769  }
   770  
   771  func (ss *SqlSupplier) RemoveIndexIfExists(indexName string, tableName string) bool {
   772  
   773  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   774  		_, err := ss.GetMaster().SelectStr("SELECT $1::regclass", indexName)
   775  		// It should fail if the index does not exist
   776  		if err != nil {
   777  			return false
   778  		}
   779  
   780  		_, err = ss.GetMaster().ExecNoTimeout("DROP INDEX " + indexName)
   781  		if err != nil {
   782  			mlog.Critical(fmt.Sprintf("Failed to remove index %v", err))
   783  			time.Sleep(time.Second)
   784  			os.Exit(EXIT_REMOVE_INDEX_POSTGRES)
   785  		}
   786  
   787  		return true
   788  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   789  
   790  		count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName)
   791  		if err != nil {
   792  			mlog.Critical(fmt.Sprintf("Failed to check index %v", err))
   793  			time.Sleep(time.Second)
   794  			os.Exit(EXIT_REMOVE_INDEX_MYSQL)
   795  		}
   796  
   797  		if count <= 0 {
   798  			return false
   799  		}
   800  
   801  		_, err = ss.GetMaster().ExecNoTimeout("DROP INDEX " + indexName + " ON " + tableName)
   802  		if err != nil {
   803  			mlog.Critical(fmt.Sprintf("Failed to remove index %v", err))
   804  			time.Sleep(time.Second)
   805  			os.Exit(EXIT_REMOVE_INDEX_MYSQL)
   806  		}
   807  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   808  		_, err := ss.GetMaster().ExecNoTimeout("DROP INDEX IF EXISTS " + indexName)
   809  		if err != nil {
   810  			mlog.Critical(fmt.Sprintf("Failed to remove index %v", err))
   811  			time.Sleep(time.Second)
   812  			os.Exit(EXIT_REMOVE_INDEX_SQLITE)
   813  		}
   814  	} else {
   815  		mlog.Critical("Failed to create index because of missing driver")
   816  		time.Sleep(time.Second)
   817  		os.Exit(EXIT_REMOVE_INDEX_MISSING)
   818  	}
   819  
   820  	return true
   821  }
   822  
   823  func IsUniqueConstraintError(err error, indexName []string) bool {
   824  	unique := false
   825  	if pqErr, ok := err.(*pq.Error); ok && pqErr.Code == "23505" {
   826  		unique = true
   827  	}
   828  
   829  	if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1062 {
   830  		unique = true
   831  	}
   832  
   833  	field := false
   834  	for _, contain := range indexName {
   835  		if strings.Contains(err.Error(), contain) {
   836  			field = true
   837  			break
   838  		}
   839  	}
   840  
   841  	return unique && field
   842  }
   843  
   844  func (ss *SqlSupplier) GetAllConns() []*gorp.DbMap {
   845  	all := make([]*gorp.DbMap, len(ss.replicas)+1)
   846  	copy(all, ss.replicas)
   847  	all[len(ss.replicas)] = ss.master
   848  	return all
   849  }
   850  
   851  func (ss *SqlSupplier) Close() {
   852  	mlog.Info("Closing SqlStore")
   853  	ss.master.Db.Close()
   854  	for _, replica := range ss.replicas {
   855  		replica.Db.Close()
   856  	}
   857  }
   858  
   859  func (ss *SqlSupplier) LockToMaster() {
   860  	ss.lockedToMaster = true
   861  }
   862  
   863  func (ss *SqlSupplier) UnlockFromMaster() {
   864  	ss.lockedToMaster = false
   865  }
   866  
   867  func (ss *SqlSupplier) Team() store.TeamStore {
   868  	return ss.oldStores.team
   869  }
   870  
   871  func (ss *SqlSupplier) Channel() store.ChannelStore {
   872  	return ss.oldStores.channel
   873  }
   874  
   875  func (ss *SqlSupplier) Post() store.PostStore {
   876  	return ss.oldStores.post
   877  }
   878  
   879  func (ss *SqlSupplier) User() store.UserStore {
   880  	return ss.oldStores.user
   881  }
   882  
   883  func (ss *SqlSupplier) Session() store.SessionStore {
   884  	return ss.oldStores.session
   885  }
   886  
   887  func (ss *SqlSupplier) Audit() store.AuditStore {
   888  	return ss.oldStores.audit
   889  }
   890  
   891  func (ss *SqlSupplier) ClusterDiscovery() store.ClusterDiscoveryStore {
   892  	return ss.oldStores.cluster
   893  }
   894  
   895  func (ss *SqlSupplier) Compliance() store.ComplianceStore {
   896  	return ss.oldStores.compliance
   897  }
   898  
   899  func (ss *SqlSupplier) OAuth() store.OAuthStore {
   900  	return ss.oldStores.oauth
   901  }
   902  
   903  func (ss *SqlSupplier) System() store.SystemStore {
   904  	return ss.oldStores.system
   905  }
   906  
   907  func (ss *SqlSupplier) Webhook() store.WebhookStore {
   908  	return ss.oldStores.webhook
   909  }
   910  
   911  func (ss *SqlSupplier) Command() store.CommandStore {
   912  	return ss.oldStores.command
   913  }
   914  
   915  func (ss *SqlSupplier) CommandWebhook() store.CommandWebhookStore {
   916  	return ss.oldStores.commandWebhook
   917  }
   918  
   919  func (ss *SqlSupplier) Preference() store.PreferenceStore {
   920  	return ss.oldStores.preference
   921  }
   922  
   923  func (ss *SqlSupplier) License() store.LicenseStore {
   924  	return ss.oldStores.license
   925  }
   926  
   927  func (ss *SqlSupplier) Token() store.TokenStore {
   928  	return ss.oldStores.token
   929  }
   930  
   931  func (ss *SqlSupplier) Emoji() store.EmojiStore {
   932  	return ss.oldStores.emoji
   933  }
   934  
   935  func (ss *SqlSupplier) Status() store.StatusStore {
   936  	return ss.oldStores.status
   937  }
   938  
   939  func (ss *SqlSupplier) FileInfo() store.FileInfoStore {
   940  	return ss.oldStores.fileInfo
   941  }
   942  
   943  func (ss *SqlSupplier) Reaction() store.ReactionStore {
   944  	return ss.oldStores.reaction
   945  }
   946  
   947  func (ss *SqlSupplier) Job() store.JobStore {
   948  	return ss.oldStores.job
   949  }
   950  
   951  func (ss *SqlSupplier) UserAccessToken() store.UserAccessTokenStore {
   952  	return ss.oldStores.userAccessToken
   953  }
   954  
   955  func (ss *SqlSupplier) ChannelMemberHistory() store.ChannelMemberHistoryStore {
   956  	return ss.oldStores.channelMemberHistory
   957  }
   958  
   959  func (ss *SqlSupplier) Plugin() store.PluginStore {
   960  	return ss.oldStores.plugin
   961  }
   962  
   963  func (ss *SqlSupplier) Role() store.RoleStore {
   964  	return ss.oldStores.role
   965  }
   966  
   967  func (ss *SqlSupplier) ServiceTerms() store.ServiceTermsStore {
   968  	return ss.oldStores.serviceTerms
   969  }
   970  
   971  func (ss *SqlSupplier) Scheme() store.SchemeStore {
   972  	return ss.oldStores.scheme
   973  }
   974  
   975  func (ss *SqlSupplier) DropAllTables() {
   976  	ss.master.TruncateTables()
   977  }
   978  
   979  type mattermConverter struct{}
   980  
   981  func (me mattermConverter) ToDb(val interface{}) (interface{}, error) {
   982  
   983  	switch t := val.(type) {
   984  	case model.StringMap:
   985  		return model.MapToJson(t), nil
   986  	case map[string]string:
   987  		return model.MapToJson(model.StringMap(t)), nil
   988  	case model.StringArray:
   989  		return model.ArrayToJson(t), nil
   990  	case model.StringInterface:
   991  		return model.StringInterfaceToJson(t), nil
   992  	case map[string]interface{}:
   993  		return model.StringInterfaceToJson(model.StringInterface(t)), nil
   994  	}
   995  
   996  	return val, nil
   997  }
   998  
   999  func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) {
  1000  	switch target.(type) {
  1001  	case *model.StringMap:
  1002  		binder := func(holder, target interface{}) error {
  1003  			s, ok := holder.(*string)
  1004  			if !ok {
  1005  				return errors.New(utils.T("store.sql.convert_string_map"))
  1006  			}
  1007  			b := []byte(*s)
  1008  			return json.Unmarshal(b, target)
  1009  		}
  1010  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1011  	case *map[string]string:
  1012  		binder := func(holder, target interface{}) error {
  1013  			s, ok := holder.(*string)
  1014  			if !ok {
  1015  				return errors.New(utils.T("store.sql.convert_string_map"))
  1016  			}
  1017  			b := []byte(*s)
  1018  			return json.Unmarshal(b, target)
  1019  		}
  1020  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1021  	case *model.StringArray:
  1022  		binder := func(holder, target interface{}) error {
  1023  			s, ok := holder.(*string)
  1024  			if !ok {
  1025  				return errors.New(utils.T("store.sql.convert_string_array"))
  1026  			}
  1027  			b := []byte(*s)
  1028  			return json.Unmarshal(b, target)
  1029  		}
  1030  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1031  	case *model.StringInterface:
  1032  		binder := func(holder, target interface{}) error {
  1033  			s, ok := holder.(*string)
  1034  			if !ok {
  1035  				return errors.New(utils.T("store.sql.convert_string_interface"))
  1036  			}
  1037  			b := []byte(*s)
  1038  			return json.Unmarshal(b, target)
  1039  		}
  1040  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1041  	case *map[string]interface{}:
  1042  		binder := func(holder, target interface{}) error {
  1043  			s, ok := holder.(*string)
  1044  			if !ok {
  1045  				return errors.New(utils.T("store.sql.convert_string_interface"))
  1046  			}
  1047  			b := []byte(*s)
  1048  			return json.Unmarshal(b, target)
  1049  		}
  1050  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1051  	}
  1052  
  1053  	return gorp.CustomScanner{}, false
  1054  }
  1055  
  1056  func convertMySQLFullTextColumnsToPostgres(columnNames string) string {
  1057  	columns := strings.Split(columnNames, ", ")
  1058  	concatenatedColumnNames := ""
  1059  	for i, c := range columns {
  1060  		concatenatedColumnNames += c
  1061  		if i < len(columns)-1 {
  1062  			concatenatedColumnNames += " || ' ' || "
  1063  		}
  1064  	}
  1065  
  1066  	return concatenatedColumnNames
  1067  }