You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

database.go 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package setting
  5. import (
  6. "errors"
  7. "fmt"
  8. "net/url"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "strings"
  13. "time"
  14. )
  15. var (
  16. // SupportedDatabases includes all supported databases type
  17. SupportedDatabases = []string{"MySQL", "PostgreSQL", "MSSQL"}
  18. dbTypes = map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3"}
  19. // EnableSQLite3 use SQLite3, set by build flag
  20. EnableSQLite3 bool
  21. // Database holds the database settings
  22. Database = struct {
  23. Type string
  24. Host string
  25. Name string
  26. User string
  27. Passwd string
  28. SSLMode string
  29. Path string
  30. LogSQL bool
  31. Charset string
  32. Timeout int // seconds
  33. UseSQLite3 bool
  34. UseMySQL bool
  35. UseMSSQL bool
  36. UsePostgreSQL bool
  37. DBConnectRetries int
  38. DBConnectBackoff time.Duration
  39. MaxIdleConns int
  40. ConnMaxLifetime time.Duration
  41. IterateBufferSize int
  42. }{
  43. Timeout: 500,
  44. MaxIdleConns: 0,
  45. ConnMaxLifetime: 3 * time.Second,
  46. }
  47. )
  48. // GetDBTypeByName returns the dataase type as it defined on XORM according the given name
  49. func GetDBTypeByName(name string) string {
  50. return dbTypes[name]
  51. }
  52. // InitDBConfig loads the database settings
  53. func InitDBConfig() {
  54. sec := Cfg.Section("database")
  55. Database.Type = sec.Key("DB_TYPE").String()
  56. switch Database.Type {
  57. case "sqlite3":
  58. Database.UseSQLite3 = true
  59. case "mysql":
  60. Database.UseMySQL = true
  61. case "postgres":
  62. Database.UsePostgreSQL = true
  63. case "mssql":
  64. Database.UseMSSQL = true
  65. }
  66. Database.Host = sec.Key("HOST").String()
  67. Database.Name = sec.Key("NAME").String()
  68. Database.User = sec.Key("USER").String()
  69. if len(Database.Passwd) == 0 {
  70. Database.Passwd = sec.Key("PASSWD").String()
  71. }
  72. Database.SSLMode = sec.Key("SSL_MODE").MustString("disable")
  73. Database.Charset = sec.Key("CHARSET").In("utf8", []string{"utf8", "utf8mb4"})
  74. Database.Path = sec.Key("PATH").MustString(filepath.Join(AppDataPath, "gitea.db"))
  75. Database.Timeout = sec.Key("SQLITE_TIMEOUT").MustInt(500)
  76. Database.MaxIdleConns = sec.Key("MAX_IDLE_CONNS").MustInt(0)
  77. Database.ConnMaxLifetime = sec.Key("CONN_MAX_LIFE_TIME").MustDuration(3 * time.Second)
  78. Database.IterateBufferSize = sec.Key("ITERATE_BUFFER_SIZE").MustInt(50)
  79. Database.LogSQL = sec.Key("LOG_SQL").MustBool(true)
  80. Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10)
  81. Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second)
  82. }
  83. // DBConnStr returns database connection string
  84. func DBConnStr() (string, error) {
  85. connStr := ""
  86. var Param = "?"
  87. if strings.Contains(Database.Name, Param) {
  88. Param = "&"
  89. }
  90. switch Database.Type {
  91. case "mysql":
  92. connType := "tcp"
  93. if Database.Host[0] == '/' { // looks like a unix socket
  94. connType = "unix"
  95. }
  96. tls := Database.SSLMode
  97. if tls == "disable" { // allow (Postgres-inspired) default value to work in MySQL
  98. tls = "false"
  99. }
  100. connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%scharset=%s&parseTime=true&tls=%s",
  101. Database.User, Database.Passwd, connType, Database.Host, Database.Name, Param, Database.Charset, tls)
  102. case "postgres":
  103. connStr = getPostgreSQLConnectionString(Database.Host, Database.User, Database.Passwd, Database.Name, Param, Database.SSLMode)
  104. case "mssql":
  105. host, port := ParseMSSQLHostPort(Database.Host)
  106. connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, Database.Name, Database.User, Database.Passwd)
  107. case "sqlite3":
  108. if !EnableSQLite3 {
  109. return "", errors.New("this binary version does not build support for SQLite3")
  110. }
  111. if err := os.MkdirAll(path.Dir(Database.Path), os.ModePerm); err != nil {
  112. return "", fmt.Errorf("Failed to create directories: %v", err)
  113. }
  114. connStr = fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", Database.Path, Database.Timeout)
  115. default:
  116. return "", fmt.Errorf("Unknown database type: %s", Database.Type)
  117. }
  118. return connStr, nil
  119. }
  120. // parsePostgreSQLHostPort parses given input in various forms defined in
  121. // https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
  122. // and returns proper host and port number.
  123. func parsePostgreSQLHostPort(info string) (string, string) {
  124. host, port := "127.0.0.1", "5432"
  125. if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
  126. idx := strings.LastIndex(info, ":")
  127. host = info[:idx]
  128. port = info[idx+1:]
  129. } else if len(info) > 0 {
  130. host = info
  131. }
  132. return host, port
  133. }
  134. func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) {
  135. host, port := parsePostgreSQLHostPort(dbHost)
  136. if host[0] == '/' { // looks like a unix socket
  137. connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
  138. url.PathEscape(dbUser), url.PathEscape(dbPasswd), port, dbName, dbParam, dbsslMode, host)
  139. } else {
  140. connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
  141. url.PathEscape(dbUser), url.PathEscape(dbPasswd), host, port, dbName, dbParam, dbsslMode)
  142. }
  143. return
  144. }
  145. // ParseMSSQLHostPort splits the host into host and port
  146. func ParseMSSQLHostPort(info string) (string, string) {
  147. host, port := "127.0.0.1", "1433"
  148. if strings.Contains(info, ":") {
  149. host = strings.Split(info, ":")[0]
  150. port = strings.Split(info, ":")[1]
  151. } else if strings.Contains(info, ",") {
  152. host = strings.Split(info, ",")[0]
  153. port = strings.TrimSpace(strings.Split(info, ",")[1])
  154. } else if len(info) > 0 {
  155. host = info
  156. }
  157. return host, port
  158. }