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