PageRenderTime 1491ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Godeps/_workspace/src/github.com/astaxie/beego/orm/db_alias.go

https://gitlab.com/kumarsiva07/beefer
Go | 292 lines | 219 code | 40 blank | 33 comment | 47 complexity | 9acde51e84f2fa82b4781ac5f34ff2fc MD5 | raw file
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package orm
  15. import (
  16. "database/sql"
  17. "fmt"
  18. "reflect"
  19. "sync"
  20. "time"
  21. )
  22. // database driver constant int.
  23. type DriverType int
  24. const (
  25. _ DriverType = iota // int enum type
  26. DR_MySQL // mysql
  27. DR_Sqlite // sqlite
  28. DR_Oracle // oracle
  29. DR_Postgres // pgsql
  30. )
  31. // database driver string.
  32. type driver string
  33. // get type constant int of current driver..
  34. func (d driver) Type() DriverType {
  35. a, _ := dataBaseCache.get(string(d))
  36. return a.Driver
  37. }
  38. // get name of current driver
  39. func (d driver) Name() string {
  40. return string(d)
  41. }
  42. // check driver iis implemented Driver interface or not.
  43. var _ Driver = new(driver)
  44. var (
  45. dataBaseCache = &_dbCache{cache: make(map[string]*alias)}
  46. drivers = map[string]DriverType{
  47. "mysql": DR_MySQL,
  48. "postgres": DR_Postgres,
  49. "sqlite3": DR_Sqlite,
  50. }
  51. dbBasers = map[DriverType]dbBaser{
  52. DR_MySQL: newdbBaseMysql(),
  53. DR_Sqlite: newdbBaseSqlite(),
  54. DR_Oracle: newdbBaseMysql(),
  55. DR_Postgres: newdbBasePostgres(),
  56. }
  57. )
  58. // database alias cacher.
  59. type _dbCache struct {
  60. mux sync.RWMutex
  61. cache map[string]*alias
  62. }
  63. // add database alias with original name.
  64. func (ac *_dbCache) add(name string, al *alias) (added bool) {
  65. ac.mux.Lock()
  66. defer ac.mux.Unlock()
  67. if _, ok := ac.cache[name]; ok == false {
  68. ac.cache[name] = al
  69. added = true
  70. }
  71. return
  72. }
  73. // get database alias if cached.
  74. func (ac *_dbCache) get(name string) (al *alias, ok bool) {
  75. ac.mux.RLock()
  76. defer ac.mux.RUnlock()
  77. al, ok = ac.cache[name]
  78. return
  79. }
  80. // get default alias.
  81. func (ac *_dbCache) getDefault() (al *alias) {
  82. al, _ = ac.get("default")
  83. return
  84. }
  85. type alias struct {
  86. Name string
  87. Driver DriverType
  88. DriverName string
  89. DataSource string
  90. MaxIdleConns int
  91. MaxOpenConns int
  92. DB *sql.DB
  93. DbBaser dbBaser
  94. TZ *time.Location
  95. Engine string
  96. }
  97. func detectTZ(al *alias) {
  98. // orm timezone system match database
  99. // default use Local
  100. al.TZ = time.Local
  101. if al.DriverName == "sphinx" {
  102. return
  103. }
  104. switch al.Driver {
  105. case DR_MySQL:
  106. row := al.DB.QueryRow("SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)")
  107. var tz string
  108. row.Scan(&tz)
  109. if len(tz) >= 8 {
  110. if tz[0] != '-' {
  111. tz = "+" + tz
  112. }
  113. t, err := time.Parse("-07:00:00", tz)
  114. if err == nil {
  115. al.TZ = t.Location()
  116. } else {
  117. DebugLog.Printf("Detect DB timezone: %s %s\n", tz, err.Error())
  118. }
  119. }
  120. // get default engine from current database
  121. row = al.DB.QueryRow("SELECT ENGINE, TRANSACTIONS FROM information_schema.engines WHERE SUPPORT = 'DEFAULT'")
  122. var engine string
  123. var tx bool
  124. row.Scan(&engine, &tx)
  125. if engine != "" {
  126. al.Engine = engine
  127. } else {
  128. al.Engine = "INNODB"
  129. }
  130. case DR_Sqlite:
  131. al.TZ = time.UTC
  132. case DR_Postgres:
  133. row := al.DB.QueryRow("SELECT current_setting('TIMEZONE')")
  134. var tz string
  135. row.Scan(&tz)
  136. loc, err := time.LoadLocation(tz)
  137. if err == nil {
  138. al.TZ = loc
  139. } else {
  140. DebugLog.Printf("Detect DB timezone: %s %s\n", tz, err.Error())
  141. }
  142. }
  143. }
  144. func addAliasWthDB(aliasName, driverName string, db *sql.DB) (*alias, error) {
  145. al := new(alias)
  146. al.Name = aliasName
  147. al.DriverName = driverName
  148. al.DB = db
  149. if dr, ok := drivers[driverName]; ok {
  150. al.DbBaser = dbBasers[dr]
  151. al.Driver = dr
  152. } else {
  153. return nil, fmt.Errorf("driver name `%s` have not registered", driverName)
  154. }
  155. err := db.Ping()
  156. if err != nil {
  157. return nil, fmt.Errorf("register db Ping `%s`, %s", aliasName, err.Error())
  158. }
  159. if dataBaseCache.add(aliasName, al) == false {
  160. return nil, fmt.Errorf("DataBase alias name `%s` already registered, cannot reuse", aliasName)
  161. }
  162. return al, nil
  163. }
  164. func AddAliasWthDB(aliasName, driverName string, db *sql.DB) error {
  165. _, err := addAliasWthDB(aliasName, driverName, db)
  166. return err
  167. }
  168. // Setting the database connect params. Use the database driver self dataSource args.
  169. func RegisterDataBase(aliasName, driverName, dataSource string, params ...int) error {
  170. var (
  171. err error
  172. db *sql.DB
  173. al *alias
  174. )
  175. db, err = sql.Open(driverName, dataSource)
  176. if err != nil {
  177. err = fmt.Errorf("register db `%s`, %s", aliasName, err.Error())
  178. goto end
  179. }
  180. al, err = addAliasWthDB(aliasName, driverName, db)
  181. if err != nil {
  182. goto end
  183. }
  184. al.DataSource = dataSource
  185. detectTZ(al)
  186. for i, v := range params {
  187. switch i {
  188. case 0:
  189. SetMaxIdleConns(al.Name, v)
  190. case 1:
  191. SetMaxOpenConns(al.Name, v)
  192. }
  193. }
  194. end:
  195. if err != nil {
  196. if db != nil {
  197. db.Close()
  198. }
  199. DebugLog.Println(err.Error())
  200. }
  201. return err
  202. }
  203. // Register a database driver use specify driver name, this can be definition the driver is which database type.
  204. func RegisterDriver(driverName string, typ DriverType) error {
  205. if t, ok := drivers[driverName]; ok == false {
  206. drivers[driverName] = typ
  207. } else {
  208. if t != typ {
  209. return fmt.Errorf("driverName `%s` db driver already registered and is other type\n", driverName)
  210. }
  211. }
  212. return nil
  213. }
  214. // Change the database default used timezone
  215. func SetDataBaseTZ(aliasName string, tz *time.Location) error {
  216. if al, ok := dataBaseCache.get(aliasName); ok {
  217. al.TZ = tz
  218. } else {
  219. return fmt.Errorf("DataBase alias name `%s` not registered\n", aliasName)
  220. }
  221. return nil
  222. }
  223. // Change the max idle conns for *sql.DB, use specify database alias name
  224. func SetMaxIdleConns(aliasName string, maxIdleConns int) {
  225. al := getDbAlias(aliasName)
  226. al.MaxIdleConns = maxIdleConns
  227. al.DB.SetMaxIdleConns(maxIdleConns)
  228. }
  229. // Change the max open conns for *sql.DB, use specify database alias name
  230. func SetMaxOpenConns(aliasName string, maxOpenConns int) {
  231. al := getDbAlias(aliasName)
  232. al.MaxOpenConns = maxOpenConns
  233. // for tip go 1.2
  234. if fun := reflect.ValueOf(al.DB).MethodByName("SetMaxOpenConns"); fun.IsValid() {
  235. fun.Call([]reflect.Value{reflect.ValueOf(maxOpenConns)})
  236. }
  237. }
  238. // Get *sql.DB from registered database by db alias name.
  239. // Use "default" as alias name if you not set.
  240. func GetDB(aliasNames ...string) (*sql.DB, error) {
  241. var name string
  242. if len(aliasNames) > 0 {
  243. name = aliasNames[0]
  244. } else {
  245. name = "default"
  246. }
  247. if al, ok := dataBaseCache.get(name); ok {
  248. return al.DB, nil
  249. } else {
  250. return nil, fmt.Errorf("DataBase of alias name `%s` not found\n", name)
  251. }
  252. }