github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/store/sqlstore/supplier.go (about)

     1  // Copyright (c) 2015-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  	"os"
    13  	"strings"
    14  	"sync"
    15  	"sync/atomic"
    16  	"time"
    17  
    18  	sq "github.com/Masterminds/squirrel"
    19  	"github.com/dyatlov/go-opengraph/opengraph"
    20  	"github.com/go-sql-driver/mysql"
    21  	"github.com/lib/pq"
    22  	"github.com/mattermost/gorp"
    23  	"github.com/mattermost/mattermost-server/v5/einterfaces"
    24  	"github.com/mattermost/mattermost-server/v5/mlog"
    25  	"github.com/mattermost/mattermost-server/v5/model"
    26  	"github.com/mattermost/mattermost-server/v5/store"
    27  	"github.com/mattermost/mattermost-server/v5/utils"
    28  )
    29  
    30  const (
    31  	INDEX_TYPE_FULL_TEXT = "full_text"
    32  	INDEX_TYPE_DEFAULT   = "default"
    33  	DB_PING_ATTEMPTS     = 18
    34  	DB_PING_TIMEOUT_SECS = 10
    35  )
    36  
    37  const (
    38  	EXIT_GENERIC_FAILURE             = 1
    39  	EXIT_CREATE_TABLE                = 100
    40  	EXIT_DB_OPEN                     = 101
    41  	EXIT_PING                        = 102
    42  	EXIT_NO_DRIVER                   = 103
    43  	EXIT_TABLE_EXISTS                = 104
    44  	EXIT_TABLE_EXISTS_MYSQL          = 105
    45  	EXIT_COLUMN_EXISTS               = 106
    46  	EXIT_DOES_COLUMN_EXISTS_POSTGRES = 107
    47  	EXIT_DOES_COLUMN_EXISTS_MYSQL    = 108
    48  	EXIT_DOES_COLUMN_EXISTS_MISSING  = 109
    49  	EXIT_CREATE_COLUMN_POSTGRES      = 110
    50  	EXIT_CREATE_COLUMN_MYSQL         = 111
    51  	EXIT_CREATE_COLUMN_MISSING       = 112
    52  	EXIT_REMOVE_COLUMN               = 113
    53  	EXIT_RENAME_COLUMN               = 114
    54  	EXIT_MAX_COLUMN                  = 115
    55  	EXIT_ALTER_COLUMN                = 116
    56  	EXIT_CREATE_INDEX_POSTGRES       = 117
    57  	EXIT_CREATE_INDEX_MYSQL          = 118
    58  	EXIT_CREATE_INDEX_FULL_MYSQL     = 119
    59  	EXIT_CREATE_INDEX_MISSING        = 120
    60  	EXIT_REMOVE_INDEX_POSTGRES       = 121
    61  	EXIT_REMOVE_INDEX_MYSQL          = 122
    62  	EXIT_REMOVE_INDEX_MISSING        = 123
    63  	EXIT_REMOVE_TABLE                = 134
    64  	EXIT_CREATE_INDEX_SQLITE         = 135
    65  	EXIT_REMOVE_INDEX_SQLITE         = 136
    66  	EXIT_TABLE_EXISTS_SQLITE         = 137
    67  	EXIT_DOES_COLUMN_EXISTS_SQLITE   = 138
    68  	EXIT_ALTER_PRIMARY_KEY           = 139
    69  )
    70  
    71  type SqlSupplierStores struct {
    72  	team                 store.TeamStore
    73  	channel              store.ChannelStore
    74  	post                 store.PostStore
    75  	user                 store.UserStore
    76  	bot                  store.BotStore
    77  	audit                store.AuditStore
    78  	cluster              store.ClusterDiscoveryStore
    79  	compliance           store.ComplianceStore
    80  	session              store.SessionStore
    81  	oauth                store.OAuthStore
    82  	system               store.SystemStore
    83  	webhook              store.WebhookStore
    84  	command              store.CommandStore
    85  	commandWebhook       store.CommandWebhookStore
    86  	preference           store.PreferenceStore
    87  	license              store.LicenseStore
    88  	token                store.TokenStore
    89  	emoji                store.EmojiStore
    90  	status               store.StatusStore
    91  	fileInfo             store.FileInfoStore
    92  	reaction             store.ReactionStore
    93  	job                  store.JobStore
    94  	userAccessToken      store.UserAccessTokenStore
    95  	plugin               store.PluginStore
    96  	channelMemberHistory store.ChannelMemberHistoryStore
    97  	role                 store.RoleStore
    98  	scheme               store.SchemeStore
    99  	TermsOfService       store.TermsOfServiceStore
   100  	group                store.GroupStore
   101  	UserTermsOfService   store.UserTermsOfServiceStore
   102  	linkMetadata         store.LinkMetadataStore
   103  }
   104  
   105  type SqlSupplier struct {
   106  	// rrCounter and srCounter should be kept first.
   107  	// See https://github.com/mattermost/mattermost-server/v5/pull/7281
   108  	rrCounter      int64
   109  	srCounter      int64
   110  	master         *gorp.DbMap
   111  	replicas       []*gorp.DbMap
   112  	searchReplicas []*gorp.DbMap
   113  	stores         SqlSupplierStores
   114  	settings       *model.SqlSettings
   115  	lockedToMaster bool
   116  	context        context.Context
   117  	license        *model.License
   118  	licenseMutex   sync.Mutex
   119  }
   120  
   121  type TraceOnAdapter struct{}
   122  
   123  func (t *TraceOnAdapter) Printf(format string, v ...interface{}) {
   124  	originalString := fmt.Sprintf(format, v...)
   125  	newString := strings.ReplaceAll(originalString, "\n", " ")
   126  	newString = strings.ReplaceAll(newString, "\t", " ")
   127  	newString = strings.ReplaceAll(newString, "\"", "")
   128  	mlog.Debug(newString)
   129  }
   130  
   131  func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInterface) *SqlSupplier {
   132  	supplier := &SqlSupplier{
   133  		rrCounter: 0,
   134  		srCounter: 0,
   135  		settings:  &settings,
   136  	}
   137  
   138  	supplier.initConnection()
   139  
   140  	supplier.stores.team = newSqlTeamStore(supplier)
   141  	supplier.stores.channel = newSqlChannelStore(supplier, metrics)
   142  	supplier.stores.post = newSqlPostStore(supplier, metrics)
   143  	supplier.stores.user = newSqlUserStore(supplier, metrics)
   144  	supplier.stores.bot = newSqlBotStore(supplier, metrics)
   145  	supplier.stores.audit = newSqlAuditStore(supplier)
   146  	supplier.stores.cluster = newSqlClusterDiscoveryStore(supplier)
   147  	supplier.stores.compliance = newSqlComplianceStore(supplier)
   148  	supplier.stores.session = newSqlSessionStore(supplier)
   149  	supplier.stores.oauth = newSqlOAuthStore(supplier)
   150  	supplier.stores.system = newSqlSystemStore(supplier)
   151  	supplier.stores.webhook = newSqlWebhookStore(supplier, metrics)
   152  	supplier.stores.command = newSqlCommandStore(supplier)
   153  	supplier.stores.commandWebhook = newSqlCommandWebhookStore(supplier)
   154  	supplier.stores.preference = newSqlPreferenceStore(supplier)
   155  	supplier.stores.license = newSqlLicenseStore(supplier)
   156  	supplier.stores.token = newSqlTokenStore(supplier)
   157  	supplier.stores.emoji = newSqlEmojiStore(supplier, metrics)
   158  	supplier.stores.status = newSqlStatusStore(supplier)
   159  	supplier.stores.fileInfo = newSqlFileInfoStore(supplier, metrics)
   160  	supplier.stores.job = newSqlJobStore(supplier)
   161  	supplier.stores.userAccessToken = newSqlUserAccessTokenStore(supplier)
   162  	supplier.stores.channelMemberHistory = newSqlChannelMemberHistoryStore(supplier)
   163  	supplier.stores.plugin = newSqlPluginStore(supplier)
   164  	supplier.stores.TermsOfService = newSqlTermsOfServiceStore(supplier, metrics)
   165  	supplier.stores.UserTermsOfService = newSqlUserTermsOfServiceStore(supplier)
   166  	supplier.stores.linkMetadata = newSqlLinkMetadataStore(supplier)
   167  	supplier.stores.reaction = newSqlReactionStore(supplier)
   168  	supplier.stores.role = newSqlRoleStore(supplier)
   169  	supplier.stores.scheme = newSqlSchemeStore(supplier)
   170  	supplier.stores.group = newSqlGroupStore(supplier)
   171  
   172  	err := supplier.GetMaster().CreateTablesIfNotExists()
   173  	if err != nil {
   174  		mlog.Critical("Error creating database tables.", mlog.Err(err))
   175  		time.Sleep(time.Second)
   176  		os.Exit(EXIT_CREATE_TABLE)
   177  	}
   178  
   179  	err = upgradeDatabase(supplier, model.CurrentVersion)
   180  	if err != nil {
   181  		mlog.Critical("Failed to upgrade database.", mlog.Err(err))
   182  		time.Sleep(time.Second)
   183  		os.Exit(EXIT_GENERIC_FAILURE)
   184  	}
   185  
   186  	supplier.stores.team.(*SqlTeamStore).createIndexesIfNotExists()
   187  	supplier.stores.channel.(*SqlChannelStore).createIndexesIfNotExists()
   188  	supplier.stores.post.(*SqlPostStore).createIndexesIfNotExists()
   189  	supplier.stores.user.(*SqlUserStore).createIndexesIfNotExists()
   190  	supplier.stores.bot.(*SqlBotStore).createIndexesIfNotExists()
   191  	supplier.stores.audit.(*SqlAuditStore).createIndexesIfNotExists()
   192  	supplier.stores.compliance.(*SqlComplianceStore).createIndexesIfNotExists()
   193  	supplier.stores.session.(*SqlSessionStore).createIndexesIfNotExists()
   194  	supplier.stores.oauth.(*SqlOAuthStore).createIndexesIfNotExists()
   195  	supplier.stores.system.(*SqlSystemStore).createIndexesIfNotExists()
   196  	supplier.stores.webhook.(*SqlWebhookStore).createIndexesIfNotExists()
   197  	supplier.stores.command.(*SqlCommandStore).createIndexesIfNotExists()
   198  	supplier.stores.commandWebhook.(*SqlCommandWebhookStore).createIndexesIfNotExists()
   199  	supplier.stores.preference.(*SqlPreferenceStore).createIndexesIfNotExists()
   200  	supplier.stores.license.(*SqlLicenseStore).createIndexesIfNotExists()
   201  	supplier.stores.token.(*SqlTokenStore).createIndexesIfNotExists()
   202  	supplier.stores.emoji.(*SqlEmojiStore).createIndexesIfNotExists()
   203  	supplier.stores.status.(*SqlStatusStore).createIndexesIfNotExists()
   204  	supplier.stores.fileInfo.(*SqlFileInfoStore).createIndexesIfNotExists()
   205  	supplier.stores.job.(*SqlJobStore).createIndexesIfNotExists()
   206  	supplier.stores.userAccessToken.(*SqlUserAccessTokenStore).createIndexesIfNotExists()
   207  	supplier.stores.plugin.(*SqlPluginStore).createIndexesIfNotExists()
   208  	supplier.stores.TermsOfService.(SqlTermsOfServiceStore).createIndexesIfNotExists()
   209  	supplier.stores.UserTermsOfService.(SqlUserTermsOfServiceStore).createIndexesIfNotExists()
   210  	supplier.stores.linkMetadata.(*SqlLinkMetadataStore).createIndexesIfNotExists()
   211  	supplier.stores.group.(*SqlGroupStore).createIndexesIfNotExists()
   212  	supplier.stores.scheme.(*SqlSchemeStore).createIndexesIfNotExists()
   213  	supplier.stores.preference.(*SqlPreferenceStore).deleteUnusedFeatures()
   214  
   215  	return supplier
   216  }
   217  
   218  func setupConnection(con_type string, dataSource string, settings *model.SqlSettings) *gorp.DbMap {
   219  	db, err := dbsql.Open(*settings.DriverName, dataSource)
   220  	if err != nil {
   221  		mlog.Critical("Failed to open SQL connection to err.", mlog.Err(err))
   222  		time.Sleep(time.Second)
   223  		os.Exit(EXIT_DB_OPEN)
   224  	}
   225  
   226  	for i := 0; i < DB_PING_ATTEMPTS; i++ {
   227  		mlog.Info("Pinging SQL", mlog.String("database", con_type))
   228  		ctx, cancel := context.WithTimeout(context.Background(), DB_PING_TIMEOUT_SECS*time.Second)
   229  		defer cancel()
   230  		err = db.PingContext(ctx)
   231  		if err == nil {
   232  			break
   233  		} else {
   234  			if i == DB_PING_ATTEMPTS-1 {
   235  				mlog.Critical("Failed to ping DB, server will exit.", mlog.Err(err))
   236  				time.Sleep(time.Second)
   237  				os.Exit(EXIT_PING)
   238  			} else {
   239  				mlog.Error("Failed to ping DB", mlog.Err(err), mlog.Int("retrying in seconds", DB_PING_TIMEOUT_SECS))
   240  				time.Sleep(DB_PING_TIMEOUT_SECS * time.Second)
   241  			}
   242  		}
   243  	}
   244  
   245  	db.SetMaxIdleConns(*settings.MaxIdleConns)
   246  	db.SetMaxOpenConns(*settings.MaxOpenConns)
   247  	db.SetConnMaxLifetime(time.Duration(*settings.ConnMaxLifetimeMilliseconds) * time.Millisecond)
   248  
   249  	var dbmap *gorp.DbMap
   250  
   251  	connectionTimeout := time.Duration(*settings.QueryTimeout) * time.Second
   252  
   253  	if *settings.DriverName == model.DATABASE_DRIVER_SQLITE {
   254  		dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.SqliteDialect{}, QueryTimeout: connectionTimeout}
   255  	} else if *settings.DriverName == model.DATABASE_DRIVER_MYSQL {
   256  		dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8MB4"}, QueryTimeout: connectionTimeout}
   257  	} else if *settings.DriverName == model.DATABASE_DRIVER_POSTGRES {
   258  		dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.PostgresDialect{}, QueryTimeout: connectionTimeout}
   259  	} else {
   260  		mlog.Critical("Failed to create dialect specific driver")
   261  		time.Sleep(time.Second)
   262  		os.Exit(EXIT_NO_DRIVER)
   263  	}
   264  
   265  	if settings.Trace != nil && *settings.Trace {
   266  		dbmap.TraceOn("sql-trace:", &TraceOnAdapter{})
   267  	}
   268  
   269  	return dbmap
   270  }
   271  
   272  func (ss *SqlSupplier) SetContext(context context.Context) {
   273  	ss.context = context
   274  }
   275  
   276  func (ss *SqlSupplier) Context() context.Context {
   277  	return ss.context
   278  }
   279  
   280  func (ss *SqlSupplier) initConnection() {
   281  	ss.master = setupConnection("master", *ss.settings.DataSource, ss.settings)
   282  
   283  	if len(ss.settings.DataSourceReplicas) > 0 {
   284  		ss.replicas = make([]*gorp.DbMap, len(ss.settings.DataSourceReplicas))
   285  		for i, replica := range ss.settings.DataSourceReplicas {
   286  			ss.replicas[i] = setupConnection(fmt.Sprintf("replica-%v", i), replica, ss.settings)
   287  		}
   288  	}
   289  
   290  	if len(ss.settings.DataSourceSearchReplicas) > 0 {
   291  		ss.searchReplicas = make([]*gorp.DbMap, len(ss.settings.DataSourceSearchReplicas))
   292  		for i, replica := range ss.settings.DataSourceSearchReplicas {
   293  			ss.searchReplicas[i] = setupConnection(fmt.Sprintf("search-replica-%v", i), replica, ss.settings)
   294  		}
   295  	}
   296  }
   297  
   298  func (ss *SqlSupplier) DriverName() string {
   299  	return *ss.settings.DriverName
   300  }
   301  
   302  func (ss *SqlSupplier) GetCurrentSchemaVersion() string {
   303  	version, _ := ss.GetMaster().SelectStr("SELECT Value FROM Systems WHERE Name='Version'")
   304  	return version
   305  }
   306  
   307  func (ss *SqlSupplier) GetDbVersion() (string, error) {
   308  	var sqlVersion string
   309  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   310  		sqlVersion = `SHOW server_version`
   311  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   312  		sqlVersion = `SELECT version()`
   313  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   314  		sqlVersion = `SELECT sqlite_version()`
   315  	} else {
   316  		return "", errors.New("Not supported driver")
   317  	}
   318  
   319  	version, err := ss.GetReplica().SelectStr(sqlVersion)
   320  	if err != nil {
   321  		return "", err
   322  	}
   323  
   324  	return version, nil
   325  
   326  }
   327  
   328  func (ss *SqlSupplier) GetMaster() *gorp.DbMap {
   329  	return ss.master
   330  }
   331  
   332  func (ss *SqlSupplier) GetSearchReplica() *gorp.DbMap {
   333  	if ss.license == nil {
   334  		return ss.GetMaster()
   335  	}
   336  
   337  	if len(ss.settings.DataSourceSearchReplicas) == 0 {
   338  		return ss.GetReplica()
   339  	}
   340  
   341  	rrNum := atomic.AddInt64(&ss.srCounter, 1) % int64(len(ss.searchReplicas))
   342  	return ss.searchReplicas[rrNum]
   343  }
   344  
   345  func (ss *SqlSupplier) GetReplica() *gorp.DbMap {
   346  	if len(ss.settings.DataSourceReplicas) == 0 || ss.lockedToMaster || ss.license == nil {
   347  		return ss.GetMaster()
   348  	}
   349  
   350  	rrNum := atomic.AddInt64(&ss.rrCounter, 1) % int64(len(ss.replicas))
   351  	return ss.replicas[rrNum]
   352  }
   353  
   354  func (ss *SqlSupplier) TotalMasterDbConnections() int {
   355  	return ss.GetMaster().Db.Stats().OpenConnections
   356  }
   357  
   358  func (ss *SqlSupplier) TotalReadDbConnections() int {
   359  	if len(ss.settings.DataSourceReplicas) == 0 {
   360  		return 0
   361  	}
   362  
   363  	count := 0
   364  	for _, db := range ss.replicas {
   365  		count = count + db.Db.Stats().OpenConnections
   366  	}
   367  
   368  	return count
   369  }
   370  
   371  func (ss *SqlSupplier) TotalSearchDbConnections() int {
   372  	if len(ss.settings.DataSourceSearchReplicas) == 0 {
   373  		return 0
   374  	}
   375  
   376  	count := 0
   377  	for _, db := range ss.searchReplicas {
   378  		count = count + db.Db.Stats().OpenConnections
   379  	}
   380  
   381  	return count
   382  }
   383  
   384  func (ss *SqlSupplier) MarkSystemRanUnitTests() {
   385  	props, err := ss.System().Get()
   386  	if err != nil {
   387  		return
   388  	}
   389  
   390  	unitTests := props[model.SYSTEM_RAN_UNIT_TESTS]
   391  	if len(unitTests) == 0 {
   392  		systemTests := &model.System{Name: model.SYSTEM_RAN_UNIT_TESTS, Value: "1"}
   393  		ss.System().Save(systemTests)
   394  	}
   395  }
   396  
   397  func (ss *SqlSupplier) DoesTableExist(tableName string) bool {
   398  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   399  		count, err := ss.GetMaster().SelectInt(
   400  			`SELECT count(relname) FROM pg_class WHERE relname=$1`,
   401  			strings.ToLower(tableName),
   402  		)
   403  
   404  		if err != nil {
   405  			mlog.Critical("Failed to check if table exists", mlog.Err(err))
   406  			time.Sleep(time.Second)
   407  			os.Exit(EXIT_TABLE_EXISTS)
   408  		}
   409  
   410  		return count > 0
   411  
   412  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   413  
   414  		count, err := ss.GetMaster().SelectInt(
   415  			`SELECT
   416  		    COUNT(0) AS table_exists
   417  			FROM
   418  			    information_schema.TABLES
   419  			WHERE
   420  			    TABLE_SCHEMA = DATABASE()
   421  			        AND TABLE_NAME = ?
   422  		    `,
   423  			tableName,
   424  		)
   425  
   426  		if err != nil {
   427  			mlog.Critical("Failed to check if table exists", mlog.Err(err))
   428  			time.Sleep(time.Second)
   429  			os.Exit(EXIT_TABLE_EXISTS_MYSQL)
   430  		}
   431  
   432  		return count > 0
   433  
   434  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   435  		count, err := ss.GetMaster().SelectInt(
   436  			`SELECT count(name) FROM sqlite_master WHERE type='table' AND name=?`,
   437  			tableName,
   438  		)
   439  
   440  		if err != nil {
   441  			mlog.Critical("Failed to check if table exists", mlog.Err(err))
   442  			time.Sleep(time.Second)
   443  			os.Exit(EXIT_TABLE_EXISTS_SQLITE)
   444  		}
   445  
   446  		return count > 0
   447  
   448  	} else {
   449  		mlog.Critical("Failed to check if column exists because of missing driver")
   450  		time.Sleep(time.Second)
   451  		os.Exit(EXIT_COLUMN_EXISTS)
   452  		return false
   453  	}
   454  }
   455  
   456  func (ss *SqlSupplier) DoesColumnExist(tableName string, columnName string) bool {
   457  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   458  		count, err := ss.GetMaster().SelectInt(
   459  			`SELECT COUNT(0)
   460  			FROM   pg_attribute
   461  			WHERE  attrelid = $1::regclass
   462  			AND    attname = $2
   463  			AND    NOT attisdropped`,
   464  			strings.ToLower(tableName),
   465  			strings.ToLower(columnName),
   466  		)
   467  
   468  		if err != nil {
   469  			if err.Error() == "pq: relation \""+strings.ToLower(tableName)+"\" does not exist" {
   470  				return false
   471  			}
   472  
   473  			mlog.Critical("Failed to check if column exists", mlog.Err(err))
   474  			time.Sleep(time.Second)
   475  			os.Exit(EXIT_DOES_COLUMN_EXISTS_POSTGRES)
   476  		}
   477  
   478  		return count > 0
   479  
   480  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   481  
   482  		count, err := ss.GetMaster().SelectInt(
   483  			`SELECT
   484  		    COUNT(0) AS column_exists
   485  		FROM
   486  		    information_schema.COLUMNS
   487  		WHERE
   488  		    TABLE_SCHEMA = DATABASE()
   489  		        AND TABLE_NAME = ?
   490  		        AND COLUMN_NAME = ?`,
   491  			tableName,
   492  			columnName,
   493  		)
   494  
   495  		if err != nil {
   496  			mlog.Critical("Failed to check if column exists", mlog.Err(err))
   497  			time.Sleep(time.Second)
   498  			os.Exit(EXIT_DOES_COLUMN_EXISTS_MYSQL)
   499  		}
   500  
   501  		return count > 0
   502  
   503  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   504  		count, err := ss.GetMaster().SelectInt(
   505  			`SELECT COUNT(*) FROM pragma_table_info(?) WHERE name=?`,
   506  			tableName,
   507  			columnName,
   508  		)
   509  
   510  		if err != nil {
   511  			mlog.Critical("Failed to check if column exists", mlog.Err(err))
   512  			time.Sleep(time.Second)
   513  			os.Exit(EXIT_DOES_COLUMN_EXISTS_SQLITE)
   514  		}
   515  
   516  		return count > 0
   517  
   518  	} else {
   519  		mlog.Critical("Failed to check if column exists because of missing driver")
   520  		time.Sleep(time.Second)
   521  		os.Exit(EXIT_DOES_COLUMN_EXISTS_MISSING)
   522  		return false
   523  	}
   524  }
   525  
   526  func (ss *SqlSupplier) DoesTriggerExist(triggerName string) bool {
   527  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   528  		count, err := ss.GetMaster().SelectInt(`
   529  			SELECT
   530  				COUNT(0)
   531  			FROM
   532  				pg_trigger
   533  			WHERE
   534  				tgname = $1
   535  		`, triggerName)
   536  
   537  		if err != nil {
   538  			mlog.Critical("Failed to check if trigger exists", mlog.Err(err))
   539  			time.Sleep(time.Second)
   540  			os.Exit(EXIT_GENERIC_FAILURE)
   541  		}
   542  
   543  		return count > 0
   544  
   545  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   546  		count, err := ss.GetMaster().SelectInt(`
   547  			SELECT
   548  				COUNT(0)
   549  			FROM
   550  				information_schema.triggers
   551  			WHERE
   552  				trigger_schema = DATABASE()
   553  			AND	trigger_name = ?
   554  		`, triggerName)
   555  
   556  		if err != nil {
   557  			mlog.Critical("Failed to check if trigger exists", mlog.Err(err))
   558  			time.Sleep(time.Second)
   559  			os.Exit(EXIT_GENERIC_FAILURE)
   560  		}
   561  
   562  		return count > 0
   563  
   564  	} else {
   565  		mlog.Critical("Failed to check if column exists because of missing driver")
   566  		time.Sleep(time.Second)
   567  		os.Exit(EXIT_GENERIC_FAILURE)
   568  		return false
   569  	}
   570  }
   571  
   572  func (ss *SqlSupplier) CreateColumnIfNotExists(tableName string, columnName string, mySqlColType string, postgresColType string, defaultValue string) bool {
   573  
   574  	if ss.DoesColumnExist(tableName, columnName) {
   575  		return false
   576  	}
   577  
   578  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   579  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + postgresColType + " DEFAULT '" + defaultValue + "'")
   580  		if err != nil {
   581  			mlog.Critical("Failed to create column", mlog.Err(err))
   582  			time.Sleep(time.Second)
   583  			os.Exit(EXIT_CREATE_COLUMN_POSTGRES)
   584  		}
   585  
   586  		return true
   587  
   588  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   589  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + mySqlColType + " DEFAULT '" + defaultValue + "'")
   590  		if err != nil {
   591  			mlog.Critical("Failed to create column", mlog.Err(err))
   592  			time.Sleep(time.Second)
   593  			os.Exit(EXIT_CREATE_COLUMN_MYSQL)
   594  		}
   595  
   596  		return true
   597  
   598  	} else {
   599  		mlog.Critical("Failed to create column because of missing driver")
   600  		time.Sleep(time.Second)
   601  		os.Exit(EXIT_CREATE_COLUMN_MISSING)
   602  		return false
   603  	}
   604  }
   605  
   606  func (ss *SqlSupplier) CreateColumnIfNotExistsNoDefault(tableName string, columnName string, mySqlColType string, postgresColType string) bool {
   607  
   608  	if ss.DoesColumnExist(tableName, columnName) {
   609  		return false
   610  	}
   611  
   612  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   613  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + postgresColType)
   614  		if err != nil {
   615  			mlog.Critical("Failed to create column", mlog.Err(err))
   616  			time.Sleep(time.Second)
   617  			os.Exit(EXIT_CREATE_COLUMN_POSTGRES)
   618  		}
   619  
   620  		return true
   621  
   622  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   623  		_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + mySqlColType)
   624  		if err != nil {
   625  			mlog.Critical("Failed to create column", mlog.Err(err))
   626  			time.Sleep(time.Second)
   627  			os.Exit(EXIT_CREATE_COLUMN_MYSQL)
   628  		}
   629  
   630  		return true
   631  
   632  	} else {
   633  		mlog.Critical("Failed to create column because of missing driver")
   634  		time.Sleep(time.Second)
   635  		os.Exit(EXIT_CREATE_COLUMN_MISSING)
   636  		return false
   637  	}
   638  }
   639  
   640  func (ss *SqlSupplier) RemoveColumnIfExists(tableName string, columnName string) bool {
   641  
   642  	if !ss.DoesColumnExist(tableName, columnName) {
   643  		return false
   644  	}
   645  
   646  	_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
   647  	if err != nil {
   648  		mlog.Critical("Failed to drop column", mlog.Err(err))
   649  		time.Sleep(time.Second)
   650  		os.Exit(EXIT_REMOVE_COLUMN)
   651  	}
   652  
   653  	return true
   654  }
   655  
   656  func (ss *SqlSupplier) RemoveTableIfExists(tableName string) bool {
   657  	if !ss.DoesTableExist(tableName) {
   658  		return false
   659  	}
   660  
   661  	_, err := ss.GetMaster().ExecNoTimeout("DROP TABLE " + tableName)
   662  	if err != nil {
   663  		mlog.Critical("Failed to drop table", mlog.Err(err))
   664  		time.Sleep(time.Second)
   665  		os.Exit(EXIT_REMOVE_TABLE)
   666  	}
   667  
   668  	return true
   669  }
   670  
   671  func (ss *SqlSupplier) RenameColumnIfExists(tableName string, oldColumnName string, newColumnName string, colType string) bool {
   672  	if !ss.DoesColumnExist(tableName, oldColumnName) {
   673  		return false
   674  	}
   675  
   676  	var err error
   677  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   678  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " CHANGE " + oldColumnName + " " + newColumnName + " " + colType)
   679  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   680  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " RENAME COLUMN " + oldColumnName + " TO " + newColumnName)
   681  	}
   682  
   683  	if err != nil {
   684  		mlog.Critical("Failed to rename column", mlog.Err(err))
   685  		time.Sleep(time.Second)
   686  		os.Exit(EXIT_RENAME_COLUMN)
   687  	}
   688  
   689  	return true
   690  }
   691  
   692  func (ss *SqlSupplier) GetMaxLengthOfColumnIfExists(tableName string, columnName string) string {
   693  	if !ss.DoesColumnExist(tableName, columnName) {
   694  		return ""
   695  	}
   696  
   697  	var result string
   698  	var err error
   699  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   700  		result, err = ss.GetMaster().SelectStr("SELECT CHARACTER_MAXIMUM_LENGTH FROM information_schema.columns WHERE table_name = '" + tableName + "' AND COLUMN_NAME = '" + columnName + "'")
   701  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   702  		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) + "'")
   703  	}
   704  
   705  	if err != nil {
   706  		mlog.Critical("Failed to get max length of column", mlog.Err(err))
   707  		time.Sleep(time.Second)
   708  		os.Exit(EXIT_MAX_COLUMN)
   709  	}
   710  
   711  	return result
   712  }
   713  
   714  func (ss *SqlSupplier) AlterColumnTypeIfExists(tableName string, columnName string, mySqlColType string, postgresColType string) bool {
   715  	if !ss.DoesColumnExist(tableName, columnName) {
   716  		return false
   717  	}
   718  
   719  	var err error
   720  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   721  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " MODIFY " + columnName + " " + mySqlColType)
   722  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   723  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + strings.ToLower(tableName) + " ALTER COLUMN " + strings.ToLower(columnName) + " TYPE " + postgresColType)
   724  	}
   725  
   726  	if err != nil {
   727  		mlog.Critical("Failed to alter column type", mlog.Err(err))
   728  		time.Sleep(time.Second)
   729  		os.Exit(EXIT_ALTER_COLUMN)
   730  	}
   731  
   732  	return true
   733  }
   734  
   735  func (ss *SqlSupplier) AlterColumnDefaultIfExists(tableName string, columnName string, mySqlColDefault *string, postgresColDefault *string) bool {
   736  	if !ss.DoesColumnExist(tableName, columnName) {
   737  		return false
   738  	}
   739  
   740  	var defaultValue string
   741  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   742  		// Some column types in MySQL cannot have defaults, so don't try to configure anything.
   743  		if mySqlColDefault == nil {
   744  			return true
   745  		}
   746  
   747  		defaultValue = *mySqlColDefault
   748  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   749  		// Postgres doesn't have the same limitation, but preserve the interface.
   750  		if postgresColDefault == nil {
   751  			return true
   752  		}
   753  
   754  		tableName = strings.ToLower(tableName)
   755  		columnName = strings.ToLower(columnName)
   756  		defaultValue = *postgresColDefault
   757  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   758  		// SQLite doesn't support altering column defaults, but we don't use this in
   759  		// production so just ignore.
   760  		return true
   761  	} else {
   762  		mlog.Critical("Failed to alter column default because of missing driver")
   763  		time.Sleep(time.Second)
   764  		os.Exit(EXIT_GENERIC_FAILURE)
   765  		return false
   766  	}
   767  
   768  	var err error
   769  	if defaultValue == "" {
   770  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ALTER COLUMN " + columnName + " DROP DEFAULT")
   771  	} else {
   772  		_, err = ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ALTER COLUMN " + columnName + " SET DEFAULT " + defaultValue)
   773  	}
   774  
   775  	if err != nil {
   776  		mlog.Critical("Failed to alter column", mlog.String("table", tableName), mlog.String("column", columnName), mlog.String("default value", defaultValue), mlog.Err(err))
   777  		time.Sleep(time.Second)
   778  		os.Exit(EXIT_GENERIC_FAILURE)
   779  		return false
   780  	}
   781  
   782  	return true
   783  }
   784  
   785  func (ss *SqlSupplier) AlterPrimaryKey(tableName string, columnNames []string) bool {
   786  	var currentPrimaryKey string
   787  	var err error
   788  	// get the current primary key as a comma separated list of columns
   789  	switch ss.DriverName() {
   790  	case model.DATABASE_DRIVER_MYSQL:
   791  		query := `
   792  			SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index) AS PK
   793  		FROM
   794  			information_schema.statistics
   795  		WHERE
   796  			table_schema = DATABASE()
   797  		AND table_name = ?
   798  		AND index_name = 'PRIMARY'
   799  		GROUP BY
   800  			index_name`
   801  		currentPrimaryKey, err = ss.GetMaster().SelectStr(query, tableName)
   802  	case model.DATABASE_DRIVER_POSTGRES:
   803  		query := `
   804  			SELECT string_agg(a.attname, ',') AS pk
   805  		FROM
   806  			pg_constraint AS c
   807  		CROSS JOIN
   808  			(SELECT unnest(conkey) FROM pg_constraint WHERE conrelid='` + strings.ToLower(tableName) + `'::REGCLASS AND contype='p') AS cols(colnum)
   809  		INNER JOIN
   810  			pg_attribute AS a ON a.attrelid = c.conrelid
   811  		AND cols.colnum = a.attnum
   812  		WHERE
   813  			c.contype = 'p'
   814  		AND c.conrelid = '` + strings.ToLower(tableName) + `'::REGCLASS`
   815  		currentPrimaryKey, err = ss.GetMaster().SelectStr(query)
   816  	case model.DATABASE_DRIVER_SQLITE:
   817  		// SQLite doesn't support altering primary key
   818  		return true
   819  	}
   820  	if err != nil {
   821  		mlog.Critical("Failed to get current primary key", mlog.String("table", tableName), mlog.Err(err))
   822  		time.Sleep(time.Second)
   823  		os.Exit(EXIT_ALTER_PRIMARY_KEY)
   824  	}
   825  
   826  	primaryKey := strings.Join(columnNames, ",")
   827  	if strings.EqualFold(currentPrimaryKey, primaryKey) {
   828  		return false
   829  	}
   830  	// alter primary key
   831  	var alterQuery string
   832  	if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   833  		alterQuery = "ALTER TABLE " + tableName + " DROP PRIMARY KEY, ADD PRIMARY KEY (" + primaryKey + ")"
   834  	} else if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   835  		alterQuery = "ALTER TABLE " + tableName + " DROP CONSTRAINT " + strings.ToLower(tableName) + "_pkey, ADD PRIMARY KEY (" + strings.ToLower(primaryKey) + ")"
   836  	}
   837  	_, err = ss.GetMaster().ExecNoTimeout(alterQuery)
   838  	if err != nil {
   839  		mlog.Critical("Failed to alter primary key", mlog.String("table", tableName), mlog.Err(err))
   840  		time.Sleep(time.Second)
   841  		os.Exit(EXIT_ALTER_PRIMARY_KEY)
   842  	}
   843  	return true
   844  }
   845  
   846  func (ss *SqlSupplier) CreateUniqueIndexIfNotExists(indexName string, tableName string, columnName string) bool {
   847  	return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_DEFAULT, true)
   848  }
   849  
   850  func (ss *SqlSupplier) CreateIndexIfNotExists(indexName string, tableName string, columnName string) bool {
   851  	return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_DEFAULT, false)
   852  }
   853  
   854  func (ss *SqlSupplier) CreateCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool {
   855  	return ss.createIndexIfNotExists(indexName, tableName, columnNames, INDEX_TYPE_DEFAULT, false)
   856  }
   857  
   858  func (ss *SqlSupplier) CreateUniqueCompositeIndexIfNotExists(indexName string, tableName string, columnNames []string) bool {
   859  	return ss.createIndexIfNotExists(indexName, tableName, columnNames, INDEX_TYPE_DEFAULT, true)
   860  }
   861  
   862  func (ss *SqlSupplier) CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) bool {
   863  	return ss.createIndexIfNotExists(indexName, tableName, []string{columnName}, INDEX_TYPE_FULL_TEXT, false)
   864  }
   865  
   866  func (ss *SqlSupplier) createIndexIfNotExists(indexName string, tableName string, columnNames []string, indexType string, unique bool) bool {
   867  
   868  	uniqueStr := ""
   869  	if unique {
   870  		uniqueStr = "UNIQUE "
   871  	}
   872  
   873  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   874  		_, errExists := ss.GetMaster().SelectStr("SELECT $1::regclass", indexName)
   875  		// It should fail if the index does not exist
   876  		if errExists == nil {
   877  			return false
   878  		}
   879  
   880  		query := ""
   881  		if indexType == INDEX_TYPE_FULL_TEXT {
   882  			if len(columnNames) != 1 {
   883  				mlog.Critical("Unable to create multi column full text index")
   884  				os.Exit(EXIT_CREATE_INDEX_POSTGRES)
   885  			}
   886  			columnName := columnNames[0]
   887  			postgresColumnNames := convertMySQLFullTextColumnsToPostgres(columnName)
   888  			query = "CREATE INDEX " + indexName + " ON " + tableName + " USING gin(to_tsvector('english', " + postgresColumnNames + "))"
   889  		} else {
   890  			query = "CREATE " + uniqueStr + "INDEX " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")"
   891  		}
   892  
   893  		_, err := ss.GetMaster().ExecNoTimeout(query)
   894  		if err != nil {
   895  			mlog.Critical("Failed to create index", mlog.Err(errExists), mlog.Err(err))
   896  			time.Sleep(time.Second)
   897  			os.Exit(EXIT_CREATE_INDEX_POSTGRES)
   898  		}
   899  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   900  
   901  		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)
   902  		if err != nil {
   903  			mlog.Critical("Failed to check index", mlog.Err(err))
   904  			time.Sleep(time.Second)
   905  			os.Exit(EXIT_CREATE_INDEX_MYSQL)
   906  		}
   907  
   908  		if count > 0 {
   909  			return false
   910  		}
   911  
   912  		fullTextIndex := ""
   913  		if indexType == INDEX_TYPE_FULL_TEXT {
   914  			fullTextIndex = " FULLTEXT "
   915  		}
   916  
   917  		_, err = ss.GetMaster().ExecNoTimeout("CREATE  " + uniqueStr + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")")
   918  		if err != nil {
   919  			mlog.Critical("Failed to create index", mlog.Err(err))
   920  			time.Sleep(time.Second)
   921  			os.Exit(EXIT_CREATE_INDEX_FULL_MYSQL)
   922  		}
   923  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   924  		_, err := ss.GetMaster().ExecNoTimeout("CREATE INDEX IF NOT EXISTS " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")")
   925  		if err != nil {
   926  			mlog.Critical("Failed to create index", mlog.Err(err))
   927  			time.Sleep(time.Second)
   928  			os.Exit(EXIT_CREATE_INDEX_SQLITE)
   929  		}
   930  	} else {
   931  		mlog.Critical("Failed to create index because of missing driver")
   932  		time.Sleep(time.Second)
   933  		os.Exit(EXIT_CREATE_INDEX_MISSING)
   934  	}
   935  
   936  	return true
   937  }
   938  
   939  func (ss *SqlSupplier) RemoveIndexIfExists(indexName string, tableName string) bool {
   940  
   941  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   942  		_, err := ss.GetMaster().SelectStr("SELECT $1::regclass", indexName)
   943  		// It should fail if the index does not exist
   944  		if err != nil {
   945  			return false
   946  		}
   947  
   948  		_, err = ss.GetMaster().ExecNoTimeout("DROP INDEX " + indexName)
   949  		if err != nil {
   950  			mlog.Critical("Failed to remove index", mlog.Err(err))
   951  			time.Sleep(time.Second)
   952  			os.Exit(EXIT_REMOVE_INDEX_POSTGRES)
   953  		}
   954  
   955  		return true
   956  	} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
   957  
   958  		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)
   959  		if err != nil {
   960  			mlog.Critical("Failed to check index", mlog.Err(err))
   961  			time.Sleep(time.Second)
   962  			os.Exit(EXIT_REMOVE_INDEX_MYSQL)
   963  		}
   964  
   965  		if count <= 0 {
   966  			return false
   967  		}
   968  
   969  		_, err = ss.GetMaster().ExecNoTimeout("DROP INDEX " + indexName + " ON " + tableName)
   970  		if err != nil {
   971  			mlog.Critical("Failed to remove index", mlog.Err(err))
   972  			time.Sleep(time.Second)
   973  			os.Exit(EXIT_REMOVE_INDEX_MYSQL)
   974  		}
   975  	} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
   976  		_, err := ss.GetMaster().ExecNoTimeout("DROP INDEX IF EXISTS " + indexName)
   977  		if err != nil {
   978  			mlog.Critical("Failed to remove index", mlog.Err(err))
   979  			time.Sleep(time.Second)
   980  			os.Exit(EXIT_REMOVE_INDEX_SQLITE)
   981  		}
   982  	} else {
   983  		mlog.Critical("Failed to create index because of missing driver")
   984  		time.Sleep(time.Second)
   985  		os.Exit(EXIT_REMOVE_INDEX_MISSING)
   986  	}
   987  
   988  	return true
   989  }
   990  
   991  func IsUniqueConstraintError(err error, indexName []string) bool {
   992  	unique := false
   993  	if pqErr, ok := err.(*pq.Error); ok && pqErr.Code == "23505" {
   994  		unique = true
   995  	}
   996  
   997  	if mysqlErr, ok := err.(*mysql.MySQLError); ok && mysqlErr.Number == 1062 {
   998  		unique = true
   999  	}
  1000  
  1001  	field := false
  1002  	for _, contain := range indexName {
  1003  		if strings.Contains(err.Error(), contain) {
  1004  			field = true
  1005  			break
  1006  		}
  1007  	}
  1008  
  1009  	return unique && field
  1010  }
  1011  
  1012  func (ss *SqlSupplier) GetAllConns() []*gorp.DbMap {
  1013  	all := make([]*gorp.DbMap, len(ss.replicas)+1)
  1014  	copy(all, ss.replicas)
  1015  	all[len(ss.replicas)] = ss.master
  1016  	return all
  1017  }
  1018  
  1019  // RecycleDBConnections closes active connections by setting the max conn lifetime
  1020  // to d, and then resets them back to their original duration.
  1021  func (ss *SqlSupplier) RecycleDBConnections(d time.Duration) {
  1022  	// Get old time.
  1023  	originalDuration := time.Duration(*ss.settings.ConnMaxLifetimeMilliseconds) * time.Millisecond
  1024  	// Set the max lifetimes for all connections.
  1025  	for _, conn := range ss.GetAllConns() {
  1026  		conn.Db.SetConnMaxLifetime(d)
  1027  	}
  1028  	// Wait for that period with an additional 2 seconds of scheduling delay.
  1029  	time.Sleep(d + 2*time.Second)
  1030  	// Reset max lifetime back to original value.
  1031  	for _, conn := range ss.GetAllConns() {
  1032  		conn.Db.SetConnMaxLifetime(originalDuration)
  1033  	}
  1034  }
  1035  
  1036  func (ss *SqlSupplier) Close() {
  1037  	ss.master.Db.Close()
  1038  	for _, replica := range ss.replicas {
  1039  		replica.Db.Close()
  1040  	}
  1041  }
  1042  
  1043  func (ss *SqlSupplier) LockToMaster() {
  1044  	ss.lockedToMaster = true
  1045  }
  1046  
  1047  func (ss *SqlSupplier) UnlockFromMaster() {
  1048  	ss.lockedToMaster = false
  1049  }
  1050  
  1051  func (ss *SqlSupplier) Team() store.TeamStore {
  1052  	return ss.stores.team
  1053  }
  1054  
  1055  func (ss *SqlSupplier) Channel() store.ChannelStore {
  1056  	return ss.stores.channel
  1057  }
  1058  
  1059  func (ss *SqlSupplier) Post() store.PostStore {
  1060  	return ss.stores.post
  1061  }
  1062  
  1063  func (ss *SqlSupplier) User() store.UserStore {
  1064  	return ss.stores.user
  1065  }
  1066  
  1067  func (ss *SqlSupplier) Bot() store.BotStore {
  1068  	return ss.stores.bot
  1069  }
  1070  
  1071  func (ss *SqlSupplier) Session() store.SessionStore {
  1072  	return ss.stores.session
  1073  }
  1074  
  1075  func (ss *SqlSupplier) Audit() store.AuditStore {
  1076  	return ss.stores.audit
  1077  }
  1078  
  1079  func (ss *SqlSupplier) ClusterDiscovery() store.ClusterDiscoveryStore {
  1080  	return ss.stores.cluster
  1081  }
  1082  
  1083  func (ss *SqlSupplier) Compliance() store.ComplianceStore {
  1084  	return ss.stores.compliance
  1085  }
  1086  
  1087  func (ss *SqlSupplier) OAuth() store.OAuthStore {
  1088  	return ss.stores.oauth
  1089  }
  1090  
  1091  func (ss *SqlSupplier) System() store.SystemStore {
  1092  	return ss.stores.system
  1093  }
  1094  
  1095  func (ss *SqlSupplier) Webhook() store.WebhookStore {
  1096  	return ss.stores.webhook
  1097  }
  1098  
  1099  func (ss *SqlSupplier) Command() store.CommandStore {
  1100  	return ss.stores.command
  1101  }
  1102  
  1103  func (ss *SqlSupplier) CommandWebhook() store.CommandWebhookStore {
  1104  	return ss.stores.commandWebhook
  1105  }
  1106  
  1107  func (ss *SqlSupplier) Preference() store.PreferenceStore {
  1108  	return ss.stores.preference
  1109  }
  1110  
  1111  func (ss *SqlSupplier) License() store.LicenseStore {
  1112  	return ss.stores.license
  1113  }
  1114  
  1115  func (ss *SqlSupplier) Token() store.TokenStore {
  1116  	return ss.stores.token
  1117  }
  1118  
  1119  func (ss *SqlSupplier) Emoji() store.EmojiStore {
  1120  	return ss.stores.emoji
  1121  }
  1122  
  1123  func (ss *SqlSupplier) Status() store.StatusStore {
  1124  	return ss.stores.status
  1125  }
  1126  
  1127  func (ss *SqlSupplier) FileInfo() store.FileInfoStore {
  1128  	return ss.stores.fileInfo
  1129  }
  1130  
  1131  func (ss *SqlSupplier) Reaction() store.ReactionStore {
  1132  	return ss.stores.reaction
  1133  }
  1134  
  1135  func (ss *SqlSupplier) Job() store.JobStore {
  1136  	return ss.stores.job
  1137  }
  1138  
  1139  func (ss *SqlSupplier) UserAccessToken() store.UserAccessTokenStore {
  1140  	return ss.stores.userAccessToken
  1141  }
  1142  
  1143  func (ss *SqlSupplier) ChannelMemberHistory() store.ChannelMemberHistoryStore {
  1144  	return ss.stores.channelMemberHistory
  1145  }
  1146  
  1147  func (ss *SqlSupplier) Plugin() store.PluginStore {
  1148  	return ss.stores.plugin
  1149  }
  1150  
  1151  func (ss *SqlSupplier) Role() store.RoleStore {
  1152  	return ss.stores.role
  1153  }
  1154  
  1155  func (ss *SqlSupplier) TermsOfService() store.TermsOfServiceStore {
  1156  	return ss.stores.TermsOfService
  1157  }
  1158  
  1159  func (ss *SqlSupplier) UserTermsOfService() store.UserTermsOfServiceStore {
  1160  	return ss.stores.UserTermsOfService
  1161  }
  1162  
  1163  func (ss *SqlSupplier) Scheme() store.SchemeStore {
  1164  	return ss.stores.scheme
  1165  }
  1166  
  1167  func (ss *SqlSupplier) Group() store.GroupStore {
  1168  	return ss.stores.group
  1169  }
  1170  
  1171  func (ss *SqlSupplier) LinkMetadata() store.LinkMetadataStore {
  1172  	return ss.stores.linkMetadata
  1173  }
  1174  
  1175  func (ss *SqlSupplier) DropAllTables() {
  1176  	ss.master.TruncateTables()
  1177  }
  1178  
  1179  func (ss *SqlSupplier) getQueryBuilder() sq.StatementBuilderType {
  1180  	builder := sq.StatementBuilder.PlaceholderFormat(sq.Question)
  1181  	if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
  1182  		builder = builder.PlaceholderFormat(sq.Dollar)
  1183  	}
  1184  	return builder
  1185  }
  1186  
  1187  func (ss *SqlSupplier) CheckIntegrity() <-chan model.IntegrityCheckResult {
  1188  	results := make(chan model.IntegrityCheckResult)
  1189  	go CheckRelationalIntegrity(ss, results)
  1190  	return results
  1191  }
  1192  
  1193  func (ss *SqlSupplier) UpdateLicense(license *model.License) {
  1194  	ss.licenseMutex.Lock()
  1195  	defer ss.licenseMutex.Unlock()
  1196  	ss.license = license
  1197  }
  1198  
  1199  type mattermConverter struct{}
  1200  
  1201  func (me mattermConverter) ToDb(val interface{}) (interface{}, error) {
  1202  
  1203  	switch t := val.(type) {
  1204  	case model.StringMap:
  1205  		return model.MapToJson(t), nil
  1206  	case map[string]string:
  1207  		return model.MapToJson(model.StringMap(t)), nil
  1208  	case model.StringArray:
  1209  		return model.ArrayToJson(t), nil
  1210  	case model.StringInterface:
  1211  		return model.StringInterfaceToJson(t), nil
  1212  	case map[string]interface{}:
  1213  		return model.StringInterfaceToJson(model.StringInterface(t)), nil
  1214  	case JSONSerializable:
  1215  		return t.ToJson(), nil
  1216  	case *opengraph.OpenGraph:
  1217  		return json.Marshal(t)
  1218  	}
  1219  
  1220  	return val, nil
  1221  }
  1222  
  1223  func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) {
  1224  	switch target.(type) {
  1225  	case *model.StringMap:
  1226  		binder := func(holder, target interface{}) error {
  1227  			s, ok := holder.(*string)
  1228  			if !ok {
  1229  				return errors.New(utils.T("store.sql.convert_string_map"))
  1230  			}
  1231  			b := []byte(*s)
  1232  			return json.Unmarshal(b, target)
  1233  		}
  1234  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1235  	case *map[string]string:
  1236  		binder := func(holder, target interface{}) error {
  1237  			s, ok := holder.(*string)
  1238  			if !ok {
  1239  				return errors.New(utils.T("store.sql.convert_string_map"))
  1240  			}
  1241  			b := []byte(*s)
  1242  			return json.Unmarshal(b, target)
  1243  		}
  1244  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1245  	case *model.StringArray:
  1246  		binder := func(holder, target interface{}) error {
  1247  			s, ok := holder.(*string)
  1248  			if !ok {
  1249  				return errors.New(utils.T("store.sql.convert_string_array"))
  1250  			}
  1251  			b := []byte(*s)
  1252  			return json.Unmarshal(b, target)
  1253  		}
  1254  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1255  	case *model.StringInterface:
  1256  		binder := func(holder, target interface{}) error {
  1257  			s, ok := holder.(*string)
  1258  			if !ok {
  1259  				return errors.New(utils.T("store.sql.convert_string_interface"))
  1260  			}
  1261  			b := []byte(*s)
  1262  			return json.Unmarshal(b, target)
  1263  		}
  1264  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1265  	case *map[string]interface{}:
  1266  		binder := func(holder, target interface{}) error {
  1267  			s, ok := holder.(*string)
  1268  			if !ok {
  1269  				return errors.New(utils.T("store.sql.convert_string_interface"))
  1270  			}
  1271  			b := []byte(*s)
  1272  			return json.Unmarshal(b, target)
  1273  		}
  1274  		return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
  1275  	}
  1276  
  1277  	return gorp.CustomScanner{}, false
  1278  }
  1279  
  1280  type JSONSerializable interface {
  1281  	ToJson() string
  1282  }
  1283  
  1284  func convertMySQLFullTextColumnsToPostgres(columnNames string) string {
  1285  	columns := strings.Split(columnNames, ", ")
  1286  	concatenatedColumnNames := ""
  1287  	for i, c := range columns {
  1288  		concatenatedColumnNames += c
  1289  		if i < len(columns)-1 {
  1290  			concatenatedColumnNames += " || ' ' || "
  1291  		}
  1292  	}
  1293  
  1294  	return concatenatedColumnNames
  1295  }