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