github.com/mad-app/mattermost-server@v5.11.1+incompatible/store/sqlstore/supplier.go (about)

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