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