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