gdb.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. // Package gdb provides ORM features for popular relationship databases.
  7. package gdb
  8. import (
  9. "context"
  10. "database/sql"
  11. "fmt"
  12. "time"
  13. "github.com/gogf/gf/v2/container/garray"
  14. "github.com/gogf/gf/v2/container/gmap"
  15. "github.com/gogf/gf/v2/container/gtype"
  16. "github.com/gogf/gf/v2/container/gvar"
  17. "github.com/gogf/gf/v2/errors/gcode"
  18. "github.com/gogf/gf/v2/errors/gerror"
  19. "github.com/gogf/gf/v2/os/gcache"
  20. "github.com/gogf/gf/v2/os/gcmd"
  21. "github.com/gogf/gf/v2/os/gctx"
  22. "github.com/gogf/gf/v2/os/glog"
  23. "github.com/gogf/gf/v2/util/grand"
  24. "github.com/gogf/gf/v2/util/gutil"
  25. )
  26. // DB defines the interfaces for ORM operations.
  27. type DB interface {
  28. // ===========================================================================
  29. // Model creation.
  30. // ===========================================================================
  31. // Model creates and returns a new ORM model from given schema.
  32. // The parameter `table` can be more than one table names, and also alias name, like:
  33. // 1. Model names:
  34. // Model("user")
  35. // Model("user u")
  36. // Model("user, user_detail")
  37. // Model("user u, user_detail ud")
  38. // 2. Model name with alias: Model("user", "u")
  39. // Also see Core.Model.
  40. Model(tableNameOrStruct ...interface{}) *Model
  41. // Raw creates and returns a model based on a raw sql not a table.
  42. Raw(rawSql string, args ...interface{}) *Model
  43. // Schema creates and returns a schema.
  44. // Also see Core.Schema.
  45. Schema(schema string) *Schema
  46. // With creates and returns an ORM model based on metadata of given object.
  47. // Also see Core.With.
  48. With(objects ...interface{}) *Model
  49. // Open creates a raw connection object for database with given node configuration.
  50. // Note that it is not recommended using the function manually.
  51. // Also see DriverMysql.Open.
  52. Open(config *ConfigNode) (*sql.DB, error)
  53. // Ctx is a chaining function, which creates and returns a new DB that is a shallow copy
  54. // of current DB object and with given context in it.
  55. // Also see Core.Ctx.
  56. Ctx(ctx context.Context) DB
  57. // Close closes the database and prevents new queries from starting.
  58. // Close then waits for all queries that have started processing on the server
  59. // to finish.
  60. //
  61. // It is rare to Close a DB, as the DB handle is meant to be
  62. // long-lived and shared between many goroutines.
  63. Close(ctx context.Context) error
  64. // ===========================================================================
  65. // Query APIs.
  66. // ===========================================================================
  67. Query(ctx context.Context, sql string, args ...interface{}) (Result, error) // See Core.Query.
  68. Exec(ctx context.Context, sql string, args ...interface{}) (sql.Result, error) // See Core.Exec.
  69. Prepare(ctx context.Context, sql string, execOnMaster ...bool) (*Stmt, error) // See Core.Prepare.
  70. // ===========================================================================
  71. // Common APIs for CURD.
  72. // ===========================================================================
  73. Insert(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Insert.
  74. InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.InsertIgnore.
  75. InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) // See Core.InsertAndGetId.
  76. Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Replace.
  77. Save(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) // See Core.Save.
  78. Update(ctx context.Context, table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Update.
  79. Delete(ctx context.Context, table string, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Delete.
  80. // ===========================================================================
  81. // Internal APIs for CURD, which can be overwritten by custom CURD implements.
  82. // ===========================================================================
  83. DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoSelect.
  84. DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error) // See Core.DoInsert.
  85. DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoUpdate.
  86. DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoDelete.
  87. DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoQuery.
  88. DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) // See Core.DoExec.
  89. DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) // See Core.DoFilter.
  90. DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) // See Core.DoCommit.
  91. DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) // See Core.DoPrepare.
  92. // ===========================================================================
  93. // Query APIs for convenience purpose.
  94. // ===========================================================================
  95. GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) // See Core.GetAll.
  96. GetOne(ctx context.Context, sql string, args ...interface{}) (Record, error) // See Core.GetOne.
  97. GetValue(ctx context.Context, sql string, args ...interface{}) (Value, error) // See Core.GetValue.
  98. GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) // See Core.GetArray.
  99. GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) // See Core.GetCount.
  100. GetScan(ctx context.Context, objPointer interface{}, sql string, args ...interface{}) error // See Core.GetScan.
  101. Union(unions ...*Model) *Model // See Core.Union.
  102. UnionAll(unions ...*Model) *Model // See Core.UnionAll.
  103. // ===========================================================================
  104. // Master/Slave specification support.
  105. // ===========================================================================
  106. Master(schema ...string) (*sql.DB, error) // See Core.Master.
  107. Slave(schema ...string) (*sql.DB, error) // See Core.Slave.
  108. // ===========================================================================
  109. // Ping-Pong.
  110. // ===========================================================================
  111. PingMaster() error // See Core.PingMaster.
  112. PingSlave() error // See Core.PingSlave.
  113. // ===========================================================================
  114. // Transaction.
  115. // ===========================================================================
  116. Begin(ctx context.Context) (TX, error) // See Core.Begin.
  117. Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) error // See Core.Transaction.
  118. // ===========================================================================
  119. // Configuration methods.
  120. // ===========================================================================
  121. GetCache() *gcache.Cache // See Core.GetCache.
  122. SetDebug(debug bool) // See Core.SetDebug.
  123. GetDebug() bool // See Core.GetDebug.
  124. GetSchema() string // See Core.GetSchema.
  125. GetPrefix() string // See Core.GetPrefix.
  126. GetGroup() string // See Core.GetGroup.
  127. SetDryRun(enabled bool) // See Core.SetDryRun.
  128. GetDryRun() bool // See Core.GetDryRun.
  129. SetLogger(logger glog.ILogger) // See Core.SetLogger.
  130. GetLogger() glog.ILogger // See Core.GetLogger.
  131. GetConfig() *ConfigNode // See Core.GetConfig.
  132. SetMaxIdleConnCount(n int) // See Core.SetMaxIdleConnCount.
  133. SetMaxOpenConnCount(n int) // See Core.SetMaxOpenConnCount.
  134. SetMaxConnLifeTime(d time.Duration) // See Core.SetMaxConnLifeTime.
  135. // ===========================================================================
  136. // Utility methods.
  137. // ===========================================================================
  138. GetCtx() context.Context // See Core.GetCtx.
  139. GetCore() *Core // See Core.GetCore
  140. GetChars() (charLeft string, charRight string) // See Core.GetChars.
  141. Tables(ctx context.Context, schema ...string) (tables []string, err error) // See Core.Tables. The driver must implement this function.
  142. TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) // See Core.TableFields. The driver must implement this function.
  143. ConvertValueForField(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) // See Core.ConvertValueForField
  144. ConvertValueForLocal(ctx context.Context, fieldType string, fieldValue interface{}) (interface{}, error) // See Core.ConvertValueForLocal
  145. CheckLocalTypeForField(ctx context.Context, fieldType string, fieldValue interface{}) (LocalType, error) // See Core.CheckLocalTypeForField
  146. }
  147. // TX defines the interfaces for ORM transaction operations.
  148. type TX interface {
  149. Link
  150. Ctx(ctx context.Context) TX
  151. Raw(rawSql string, args ...interface{}) *Model
  152. Model(tableNameQueryOrStruct ...interface{}) *Model
  153. With(object interface{}) *Model
  154. // ===========================================================================
  155. // Nested transaction if necessary.
  156. // ===========================================================================
  157. Begin() error
  158. Commit() error
  159. Rollback() error
  160. Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error)
  161. // ===========================================================================
  162. // Core method.
  163. // ===========================================================================
  164. Query(sql string, args ...interface{}) (result Result, err error)
  165. Exec(sql string, args ...interface{}) (sql.Result, error)
  166. Prepare(sql string) (*Stmt, error)
  167. // ===========================================================================
  168. // Query.
  169. // ===========================================================================
  170. GetAll(sql string, args ...interface{}) (Result, error)
  171. GetOne(sql string, args ...interface{}) (Record, error)
  172. GetStruct(obj interface{}, sql string, args ...interface{}) error
  173. GetStructs(objPointerSlice interface{}, sql string, args ...interface{}) error
  174. GetScan(pointer interface{}, sql string, args ...interface{}) error
  175. GetValue(sql string, args ...interface{}) (Value, error)
  176. GetCount(sql string, args ...interface{}) (int64, error)
  177. // ===========================================================================
  178. // CURD.
  179. // ===========================================================================
  180. Insert(table string, data interface{}, batch ...int) (sql.Result, error)
  181. InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error)
  182. InsertAndGetId(table string, data interface{}, batch ...int) (int64, error)
  183. Replace(table string, data interface{}, batch ...int) (sql.Result, error)
  184. Save(table string, data interface{}, batch ...int) (sql.Result, error)
  185. Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error)
  186. Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)
  187. // ===========================================================================
  188. // Utility methods.
  189. // ===========================================================================
  190. GetCtx() context.Context
  191. GetDB() DB
  192. GetSqlTX() *sql.Tx
  193. IsClosed() bool
  194. // ===========================================================================
  195. // Save point feature.
  196. // ===========================================================================
  197. SavePoint(point string) error
  198. RollbackTo(point string) error
  199. }
  200. // Core is the base struct for database management.
  201. type Core struct {
  202. db DB // DB interface object.
  203. ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization.
  204. group string // Configuration group name.
  205. schema string // Custom schema for this object.
  206. debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime.
  207. cache *gcache.Cache // Cache manager, SQL result cache only.
  208. links *gmap.StrAnyMap // links caches all created links by node.
  209. logger glog.ILogger // Logger for logging functionality.
  210. config *ConfigNode // Current config node.
  211. dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime.
  212. }
  213. type dynamicConfig struct {
  214. MaxIdleConnCount int
  215. MaxOpenConnCount int
  216. MaxConnLifeTime time.Duration
  217. }
  218. // DoCommitInput is the input parameters for function DoCommit.
  219. type DoCommitInput struct {
  220. Db *sql.DB
  221. Tx *sql.Tx
  222. Stmt *sql.Stmt
  223. Link Link
  224. Sql string
  225. Args []interface{}
  226. Type string
  227. IsTransaction bool
  228. }
  229. // DoCommitOutput is the output parameters for function DoCommit.
  230. type DoCommitOutput struct {
  231. Result sql.Result // Result is the result of exec statement.
  232. Records []Record // Records is the result of query statement.
  233. Stmt *Stmt // Stmt is the Statement object result for Prepare.
  234. Tx TX // Tx is the transaction object result for Begin.
  235. RawResult interface{} // RawResult is the underlying result, which might be sql.Result/*sql.Rows/*sql.Row.
  236. }
  237. // Driver is the interface for integrating sql drivers into package gdb.
  238. type Driver interface {
  239. // New creates and returns a database object for specified database server.
  240. New(core *Core, node *ConfigNode) (DB, error)
  241. }
  242. // Link is a common database function wrapper interface.
  243. // Note that, any operation using `Link` will have no SQL logging.
  244. type Link interface {
  245. QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error)
  246. ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error)
  247. PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error)
  248. IsOnMaster() bool
  249. IsTransaction() bool
  250. }
  251. // Sql is the sql recording struct.
  252. type Sql struct {
  253. Sql string // SQL string(may contain reserved char '?').
  254. Type string // SQL operation type.
  255. Args []interface{} // Arguments for this sql.
  256. Format string // Formatted sql which contains arguments in the sql.
  257. Error error // Execution result.
  258. Start int64 // Start execution timestamp in milliseconds.
  259. End int64 // End execution timestamp in milliseconds.
  260. Group string // Group is the group name of the configuration that the sql is executed from.
  261. Schema string // Schema is the schema name of the configuration that the sql is executed from.
  262. IsTransaction bool // IsTransaction marks whether this sql is executed in transaction.
  263. RowsAffected int64 // RowsAffected marks retrieved or affected number with current sql statement.
  264. }
  265. // DoInsertOption is the input struct for function DoInsert.
  266. type DoInsertOption struct {
  267. OnDuplicateStr string // Custom string for `on duplicated` statement.
  268. OnDuplicateMap map[string]interface{} // Custom key-value map from `OnDuplicateEx` function for `on duplicated` statement.
  269. InsertOption InsertOption // Insert operation in constant value.
  270. BatchCount int // Batch count for batch inserting.
  271. }
  272. // TableField is the struct for table field.
  273. type TableField struct {
  274. Index int // For ordering purpose as map is unordered.
  275. Name string // Field name.
  276. Type string // Field type. Eg: 'int(10) unsigned', 'varchar(64)'.
  277. Null bool // Field can be null or not.
  278. Key string // The index information(empty if it's not an index). Eg: PRI, MUL.
  279. Default interface{} // Default value for the field.
  280. Extra string // Extra information. Eg: auto_increment.
  281. Comment string // Field comment.
  282. }
  283. // Counter is the type for update count.
  284. type Counter struct {
  285. Field string
  286. Value float64
  287. }
  288. type (
  289. Raw string // Raw is a raw sql that will not be treated as argument but as a direct sql part.
  290. Value = *gvar.Var // Value is the field value type.
  291. Record map[string]Value // Record is the row record of the table.
  292. Result []Record // Result is the row record array.
  293. Map = map[string]interface{} // Map is alias of map[string]interface{}, which is the most common usage map type.
  294. List = []Map // List is type of map array.
  295. )
  296. type CatchSQLManager struct {
  297. SQLArray *garray.StrArray
  298. DoCommit bool // DoCommit marks it will be committed to underlying driver or not.
  299. }
  300. const (
  301. defaultModelSafe = false
  302. defaultCharset = `utf8`
  303. defaultProtocol = `tcp`
  304. unionTypeNormal = 0
  305. unionTypeAll = 1
  306. defaultMaxIdleConnCount = 10 // Max idle connection count in pool.
  307. defaultMaxOpenConnCount = 0 // Max open connection count in pool. Default is no limit.
  308. defaultMaxConnLifeTime = 30 * time.Second // Max lifetime for per connection in pool in seconds.
  309. ctxTimeoutTypeExec = 0
  310. ctxTimeoutTypeQuery = 1
  311. ctxTimeoutTypePrepare = 2
  312. cachePrefixTableFields = `TableFields:`
  313. cachePrefixSelectCache = `SelectCache:`
  314. commandEnvKeyForDryRun = "gf.gdb.dryrun"
  315. modelForDaoSuffix = `ForDao`
  316. dbRoleSlave = `slave`
  317. ctxKeyForDB gctx.StrKey = `CtxKeyForDB`
  318. ctxKeyCatchSQL gctx.StrKey = `CtxKeyCatchSQL`
  319. ctxKeyInternalProducedSQL gctx.StrKey = `CtxKeyInternalProducedSQL`
  320. // type:[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]
  321. linkPattern = `(\w+):([\w\-\$]*):(.*?)@(\w+?)\((.+?)\)/{0,1}([^\?]*)\?{0,1}(.*)`
  322. )
  323. type queryType int
  324. const (
  325. queryTypeNormal queryType = 0
  326. queryTypeCount queryType = 1
  327. queryTypeValue queryType = 2
  328. )
  329. type joinOperator string
  330. const (
  331. joinOperatorLeft joinOperator = "LEFT"
  332. joinOperatorRight joinOperator = "RIGHT"
  333. joinOperatorInner joinOperator = "INNER"
  334. )
  335. type InsertOption int
  336. const (
  337. InsertOptionDefault InsertOption = 0
  338. InsertOptionReplace InsertOption = 1
  339. InsertOptionSave InsertOption = 2
  340. InsertOptionIgnore InsertOption = 3
  341. InsertOperationInsert = "INSERT"
  342. InsertOperationReplace = "REPLACE"
  343. InsertOperationIgnore = "INSERT IGNORE"
  344. InsertOnDuplicateKeyUpdate = "ON DUPLICATE KEY UPDATE"
  345. )
  346. const (
  347. SqlTypeBegin = "DB.Begin"
  348. SqlTypeTXCommit = "TX.Commit"
  349. SqlTypeTXRollback = "TX.Rollback"
  350. SqlTypeExecContext = "DB.ExecContext"
  351. SqlTypeQueryContext = "DB.QueryContext"
  352. SqlTypePrepareContext = "DB.PrepareContext"
  353. SqlTypeStmtExecContext = "DB.Statement.ExecContext"
  354. SqlTypeStmtQueryContext = "DB.Statement.QueryContext"
  355. SqlTypeStmtQueryRowContext = "DB.Statement.QueryRowContext"
  356. )
  357. type LocalType string
  358. const (
  359. LocalTypeString LocalType = "string"
  360. LocalTypeDate LocalType = "date"
  361. LocalTypeDatetime LocalType = "datetime"
  362. LocalTypeInt LocalType = "int"
  363. LocalTypeUint LocalType = "uint"
  364. LocalTypeInt64 LocalType = "int64"
  365. LocalTypeUint64 LocalType = "uint64"
  366. LocalTypeIntSlice LocalType = "[]int"
  367. LocalTypeInt64Slice LocalType = "[]int64"
  368. LocalTypeUint64Slice LocalType = "[]uint64"
  369. LocalTypeInt64Bytes LocalType = "int64-bytes"
  370. LocalTypeUint64Bytes LocalType = "uint64-bytes"
  371. LocalTypeFloat32 LocalType = "float32"
  372. LocalTypeFloat64 LocalType = "float64"
  373. LocalTypeBytes LocalType = "[]byte"
  374. LocalTypeBool LocalType = "bool"
  375. LocalTypeJson LocalType = "json"
  376. LocalTypeJsonb LocalType = "jsonb"
  377. )
  378. const (
  379. fieldTypeBinary = "binary"
  380. fieldTypeVarbinary = "varbinary"
  381. fieldTypeBlob = "blob"
  382. fieldTypeTinyblob = "tinyblob"
  383. fieldTypeMediumblob = "mediumblob"
  384. fieldTypeLongblob = "longblob"
  385. fieldTypeInt = "int"
  386. fieldTypeTinyint = "tinyint"
  387. fieldTypeSmallInt = "small_int"
  388. fieldTypeSmallint = "smallint"
  389. fieldTypeMediumInt = "medium_int"
  390. fieldTypeMediumint = "mediumint"
  391. fieldTypeSerial = "serial"
  392. fieldTypeBigInt = "big_int"
  393. fieldTypeBigint = "bigint"
  394. fieldTypeBigserial = "bigserial"
  395. fieldTypeReal = "real"
  396. fieldTypeFloat = "float"
  397. fieldTypeDouble = "double"
  398. fieldTypeDecimal = "decimal"
  399. fieldTypeMoney = "money"
  400. fieldTypeNumeric = "numeric"
  401. fieldTypeSmallmoney = "smallmoney"
  402. fieldTypeBool = "bool"
  403. fieldTypeBit = "bit"
  404. fieldTypeDate = "date"
  405. fieldTypeDatetime = "datetime"
  406. fieldTypeTimestamp = "timestamp"
  407. fieldTypeTimestampz = "timestamptz"
  408. fieldTypeJson = "json"
  409. fieldTypeJsonb = "jsonb"
  410. )
  411. var (
  412. // instances is the management map for instances.
  413. instances = gmap.NewStrAnyMap(true)
  414. // driverMap manages all custom registered driver.
  415. driverMap = map[string]Driver{}
  416. // lastOperatorRegPattern is the regular expression pattern for a string
  417. // which has operator at its tail.
  418. lastOperatorRegPattern = `[<>=]+\s*$`
  419. // regularFieldNameRegPattern is the regular expression pattern for a string
  420. // which is a regular field name of table.
  421. regularFieldNameRegPattern = `^[\w\.\-]+$`
  422. // regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'.
  423. // Note that, although some databases allow char '.' in the field name, but it here does not allow '.'
  424. // in the field name as it conflicts with "db.table.field" pattern in SOME situations.
  425. regularFieldNameWithoutDotRegPattern = `^[\w\-]+$`
  426. // allDryRun sets dry-run feature for all database connections.
  427. // It is commonly used for command options for convenience.
  428. allDryRun = false
  429. // tableFieldsMap caches the table information retrieved from database.
  430. tableFieldsMap = gmap.NewStrAnyMap(true)
  431. )
  432. func init() {
  433. // allDryRun is initialized from environment or command options.
  434. allDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool()
  435. }
  436. // Register registers custom database driver to gdb.
  437. func Register(name string, driver Driver) error {
  438. driverMap[name] = newDriverWrapper(driver)
  439. return nil
  440. }
  441. // New creates and returns an ORM object with given configuration node.
  442. func New(node ConfigNode) (db DB, err error) {
  443. return newDBByConfigNode(&node, "")
  444. }
  445. // NewByGroup creates and returns an ORM object with global configurations.
  446. // The parameter `name` specifies the configuration group name,
  447. // which is DefaultGroupName in default.
  448. func NewByGroup(group ...string) (db DB, err error) {
  449. groupName := configs.group
  450. if len(group) > 0 && group[0] != "" {
  451. groupName = group[0]
  452. }
  453. configs.RLock()
  454. defer configs.RUnlock()
  455. if len(configs.config) < 1 {
  456. return nil, gerror.NewCode(
  457. gcode.CodeInvalidConfiguration,
  458. "database configuration is empty, please set the database configuration before using",
  459. )
  460. }
  461. if _, ok := configs.config[groupName]; ok {
  462. var node *ConfigNode
  463. if node, err = getConfigNodeByGroup(groupName, true); err == nil {
  464. return newDBByConfigNode(node, groupName)
  465. }
  466. return nil, err
  467. }
  468. return nil, gerror.NewCodef(
  469. gcode.CodeInvalidConfiguration,
  470. `database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`,
  471. groupName, groupName,
  472. )
  473. }
  474. // newDBByConfigNode creates and returns an ORM object with given configuration node and group name.
  475. //
  476. // Very Note:
  477. // The parameter `node` is used for DB creation, not for underlying connection creation.
  478. // So all db type configurations in the same group should be the same.
  479. func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) {
  480. if node.Link != "" {
  481. node = parseConfigNodeLink(node)
  482. }
  483. c := &Core{
  484. group: group,
  485. debug: gtype.NewBool(),
  486. cache: gcache.New(),
  487. links: gmap.NewStrAnyMap(true),
  488. logger: glog.New(),
  489. config: node,
  490. dynamicConfig: dynamicConfig{
  491. MaxIdleConnCount: node.MaxIdleConnCount,
  492. MaxOpenConnCount: node.MaxOpenConnCount,
  493. MaxConnLifeTime: node.MaxConnLifeTime,
  494. },
  495. }
  496. if v, ok := driverMap[node.Type]; ok {
  497. if c.db, err = v.New(c, node); err != nil {
  498. return nil, err
  499. }
  500. return c.db, nil
  501. }
  502. errorMsg := `cannot find database driver for specified database type "%s"`
  503. errorMsg += `, did you misspell type name "%s" or forget importing the database driver? `
  504. errorMsg += `possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers`
  505. return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type)
  506. }
  507. // Instance returns an instance for DB operations.
  508. // The parameter `name` specifies the configuration group name,
  509. // which is DefaultGroupName in default.
  510. func Instance(name ...string) (db DB, err error) {
  511. group := configs.group
  512. if len(name) > 0 && name[0] != "" {
  513. group = name[0]
  514. }
  515. v := instances.GetOrSetFuncLock(group, func() interface{} {
  516. db, err = NewByGroup(group)
  517. return db
  518. })
  519. if v != nil {
  520. return v.(DB), nil
  521. }
  522. return
  523. }
  524. // getConfigNodeByGroup calculates and returns a configuration node of given group. It
  525. // calculates the value internally using weight algorithm for load balance.
  526. //
  527. // The parameter `master` specifies whether retrieving a master node, or else a slave node
  528. // if master-slave configured.
  529. func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) {
  530. if list, ok := configs.config[group]; ok {
  531. // Separates master and slave configuration nodes array.
  532. var (
  533. masterList = make(ConfigGroup, 0)
  534. slaveList = make(ConfigGroup, 0)
  535. )
  536. for i := 0; i < len(list); i++ {
  537. if list[i].Role == dbRoleSlave {
  538. slaveList = append(slaveList, list[i])
  539. } else {
  540. masterList = append(masterList, list[i])
  541. }
  542. }
  543. if len(masterList) < 1 {
  544. return nil, gerror.NewCode(
  545. gcode.CodeInvalidConfiguration,
  546. "at least one master node configuration's need to make sense",
  547. )
  548. }
  549. if len(slaveList) < 1 {
  550. slaveList = masterList
  551. }
  552. if master {
  553. return getConfigNodeByWeight(masterList), nil
  554. } else {
  555. return getConfigNodeByWeight(slaveList), nil
  556. }
  557. }
  558. return nil, gerror.NewCodef(
  559. gcode.CodeInvalidConfiguration,
  560. "empty database configuration for item name '%s'",
  561. group,
  562. )
  563. }
  564. // getConfigNodeByWeight calculates the configuration weights and randomly returns a node.
  565. //
  566. // Calculation algorithm brief:
  567. // 1. If we have 2 nodes, and their weights are both 1, then the weight range is [0, 199];
  568. // 2. Node1 weight range is [0, 99], and node2 weight range is [100, 199], ratio is 1:1;
  569. // 3. If the random number is 99, it then chooses and returns node1;.
  570. func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
  571. if len(cg) < 2 {
  572. return &cg[0]
  573. }
  574. var total int
  575. for i := 0; i < len(cg); i++ {
  576. total += cg[i].Weight * 100
  577. }
  578. // If total is 0 means all the nodes have no weight attribute configured.
  579. // It then defaults each node's weight attribute to 1.
  580. if total == 0 {
  581. for i := 0; i < len(cg); i++ {
  582. cg[i].Weight = 1
  583. total += cg[i].Weight * 100
  584. }
  585. }
  586. // Exclude the right border value.
  587. var (
  588. min = 0
  589. max = 0
  590. random = grand.N(0, total-1)
  591. )
  592. for i := 0; i < len(cg); i++ {
  593. max = min + cg[i].Weight*100
  594. if random >= min && random < max {
  595. // ====================================================
  596. // Return a COPY of the ConfigNode.
  597. // ====================================================
  598. node := ConfigNode{}
  599. node = cg[i]
  600. return &node
  601. }
  602. min = max
  603. }
  604. return nil
  605. }
  606. // getSqlDb retrieves and returns an underlying database connection object.
  607. // The parameter `master` specifies whether retrieves master node connection if
  608. // master-slave nodes are configured.
  609. func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
  610. var (
  611. node *ConfigNode
  612. ctx = c.db.GetCtx()
  613. )
  614. if c.group != "" {
  615. // Load balance.
  616. configs.RLock()
  617. defer configs.RUnlock()
  618. // Value COPY for node.
  619. node, err = getConfigNodeByGroup(c.group, master)
  620. if err != nil {
  621. return nil, err
  622. }
  623. } else {
  624. // Value COPY for node.
  625. n := *c.db.GetConfig()
  626. node = &n
  627. }
  628. if node.Charset == "" {
  629. node.Charset = defaultCharset
  630. }
  631. // Changes the schema.
  632. nodeSchema := gutil.GetOrDefaultStr(c.schema, schema...)
  633. if nodeSchema != "" {
  634. node.Name = nodeSchema
  635. }
  636. // Update the configuration object in internal data.
  637. internalData := c.GetInternalCtxDataFromCtx(ctx)
  638. if internalData != nil {
  639. internalData.ConfigNode = node
  640. }
  641. // Cache the underlying connection pool object by node.
  642. instanceNameByNode := fmt.Sprintf(`%+v`, node)
  643. instanceValue := c.links.GetOrSetFuncLock(instanceNameByNode, func() interface{} {
  644. if sqlDb, err = c.db.Open(node); err != nil {
  645. return nil
  646. }
  647. if sqlDb == nil {
  648. return nil
  649. }
  650. if c.dynamicConfig.MaxIdleConnCount > 0 {
  651. sqlDb.SetMaxIdleConns(c.dynamicConfig.MaxIdleConnCount)
  652. } else {
  653. sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount)
  654. }
  655. if c.dynamicConfig.MaxOpenConnCount > 0 {
  656. sqlDb.SetMaxOpenConns(c.dynamicConfig.MaxOpenConnCount)
  657. } else {
  658. sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount)
  659. }
  660. if c.dynamicConfig.MaxConnLifeTime > 0 {
  661. sqlDb.SetConnMaxLifetime(c.dynamicConfig.MaxConnLifeTime)
  662. } else {
  663. sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime)
  664. }
  665. return sqlDb
  666. })
  667. if instanceValue != nil && sqlDb == nil {
  668. // It reads from instance map.
  669. sqlDb = instanceValue.(*sql.DB)
  670. }
  671. if node.Debug {
  672. c.db.SetDebug(node.Debug)
  673. }
  674. if node.DryRun {
  675. c.db.SetDryRun(node.DryRun)
  676. }
  677. return
  678. }