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