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 }