gdb_driver_pgsql.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Copyright GoFrame Author(https://github.com/gogf/gf). 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. //
  7. // Note:
  8. // 1. It needs manually import: _ "github.com/lib/pq"
  9. // 2. It does not support Save/Replace features.
  10. // 3. It does not support LastInsertId.
  11. package gdb
  12. import (
  13. "database/sql"
  14. "fmt"
  15. "github.com/gogf/gf/errors/gerror"
  16. "github.com/gogf/gf/internal/intlog"
  17. "github.com/gogf/gf/text/gstr"
  18. "strings"
  19. "github.com/gogf/gf/text/gregex"
  20. )
  21. // DriverPgsql is the driver for postgresql database.
  22. type DriverPgsql struct {
  23. *Core
  24. }
  25. // New creates and returns a database object for postgresql.
  26. // It implements the interface of gdb.Driver for extra database driver installation.
  27. func (d *DriverPgsql) New(core *Core, node *ConfigNode) (DB, error) {
  28. return &DriverPgsql{
  29. Core: core,
  30. }, nil
  31. }
  32. // Open creates and returns a underlying sql.DB object for pgsql.
  33. func (d *DriverPgsql) Open(config *ConfigNode) (*sql.DB, error) {
  34. var source string
  35. if config.LinkInfo != "" {
  36. source = config.LinkInfo
  37. } else {
  38. source = fmt.Sprintf(
  39. "user=%s password=%s host=%s port=%s dbname=%s sslmode=disable",
  40. config.User, config.Pass, config.Host, config.Port, config.Name,
  41. )
  42. }
  43. intlog.Printf("Open: %s", source)
  44. if db, err := sql.Open("postgres", source); err == nil {
  45. return db, nil
  46. } else {
  47. return nil, err
  48. }
  49. }
  50. // GetChars returns the security char for this type of database.
  51. func (d *DriverPgsql) GetChars() (charLeft string, charRight string) {
  52. return "\"", "\""
  53. }
  54. // HandleSqlBeforeCommit deals with the sql string before commits it to underlying sql driver.
  55. func (d *DriverPgsql) HandleSqlBeforeCommit(link Link, sql string, args []interface{}) (string, []interface{}) {
  56. var index int
  57. // Convert place holder char '?' to string "$x".
  58. sql, _ = gregex.ReplaceStringFunc("\\?", sql, func(s string) string {
  59. index++
  60. return fmt.Sprintf("$%d", index)
  61. })
  62. sql, _ = gregex.ReplaceString(` LIMIT (\d+),\s*(\d+)`, ` LIMIT $2 OFFSET $1`, sql)
  63. return sql, args
  64. }
  65. // Tables retrieves and returns the tables of current schema.
  66. // It's mainly used in cli tool chain for automatically generating the models.
  67. func (d *DriverPgsql) Tables(schema ...string) (tables []string, err error) {
  68. var result Result
  69. link, err := d.DB.GetSlave(schema...)
  70. if err != nil {
  71. return nil, err
  72. }
  73. query := "SELECT TABLENAME FROM PG_TABLES WHERE SCHEMANAME = 'public' ORDER BY TABLENAME"
  74. if len(schema) > 0 && schema[0] != "" {
  75. query = fmt.Sprintf("SELECT TABLENAME FROM PG_TABLES WHERE SCHEMANAME = '%s' ORDER BY TABLENAME", schema[0])
  76. }
  77. result, err = d.DB.DoGetAll(link, query)
  78. if err != nil {
  79. return
  80. }
  81. for _, m := range result {
  82. for _, v := range m {
  83. tables = append(tables, v.String())
  84. }
  85. }
  86. return
  87. }
  88. // TableFields retrieves and returns the fields information of specified table of current schema.
  89. func (d *DriverPgsql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
  90. charL, charR := d.GetChars()
  91. table = gstr.Trim(table, charL+charR)
  92. if gstr.Contains(table, " ") {
  93. return nil, gerror.New("function TableFields supports only single table operations")
  94. }
  95. table, _ = gregex.ReplaceString("\"", "", table)
  96. checkSchema := d.DB.GetSchema()
  97. if len(schema) > 0 && schema[0] != "" {
  98. checkSchema = schema[0]
  99. }
  100. v, _ := internalCache.GetOrSetFunc(
  101. fmt.Sprintf(`pgsql_table_fields_%s_%s@group:%s`, table, checkSchema, d.GetGroup()),
  102. func() (interface{}, error) {
  103. var (
  104. result Result
  105. link *sql.DB
  106. )
  107. link, err = d.DB.GetSlave(checkSchema)
  108. if err != nil {
  109. return nil, err
  110. }
  111. structureSql := fmt.Sprintf(`
  112. SELECT a.attname AS field, t.typname AS type FROM pg_class c, pg_attribute a
  113. LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,pg_type t
  114. WHERE c.relname = '%s' and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid
  115. ORDER BY a.attnum`,
  116. strings.ToLower(table),
  117. )
  118. structureSql, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(structureSql))
  119. result, err = d.DB.DoGetAll(link, structureSql)
  120. if err != nil {
  121. return nil, err
  122. }
  123. fields = make(map[string]*TableField)
  124. for i, m := range result {
  125. fields[m["field"].String()] = &TableField{
  126. Index: i,
  127. Name: m["field"].String(),
  128. Type: m["type"].String(),
  129. }
  130. }
  131. return fields, nil
  132. }, 0)
  133. if err == nil {
  134. fields = v.(map[string]*TableField)
  135. }
  136. return
  137. }