github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/store/sqlstore/supplier.go (about)

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