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