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