1
0

db_mysql.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. "fmt"
  17. "reflect"
  18. "strings"
  19. )
  20. // mysql operators.
  21. var mysqlOperators = map[string]string{
  22. "exact": "= ?",
  23. "iexact": "LIKE ?",
  24. "contains": "LIKE BINARY ?",
  25. "icontains": "LIKE ?",
  26. // "regex": "REGEXP BINARY ?",
  27. // "iregex": "REGEXP ?",
  28. "gt": "> ?",
  29. "gte": ">= ?",
  30. "lt": "< ?",
  31. "lte": "<= ?",
  32. "eq": "= ?",
  33. "ne": "!= ?",
  34. "startswith": "LIKE BINARY ?",
  35. "endswith": "LIKE BINARY ?",
  36. "istartswith": "LIKE ?",
  37. "iendswith": "LIKE ?",
  38. }
  39. // mysql column field types.
  40. var mysqlTypes = map[string]string{
  41. "auto": "AUTO_INCREMENT NOT NULL PRIMARY KEY",
  42. "pk": "NOT NULL PRIMARY KEY",
  43. "bool": "bool",
  44. "string": "varchar(%d)",
  45. "string-text": "longtext",
  46. "time.Time-date": "date",
  47. "time.Time": "datetime",
  48. "int8": "tinyint",
  49. "int16": "smallint",
  50. "int32": "integer",
  51. "int64": "bigint",
  52. "uint8": "tinyint unsigned",
  53. "uint16": "smallint unsigned",
  54. "uint32": "integer unsigned",
  55. "uint64": "bigint unsigned",
  56. "float64": "double precision",
  57. "float64-decimal": "numeric(%d, %d)",
  58. }
  59. // mysql dbBaser implementation.
  60. type dbBaseMysql struct {
  61. dbBase
  62. }
  63. var _ dbBaser = new(dbBaseMysql)
  64. // get mysql operator.
  65. func (d *dbBaseMysql) OperatorSQL(operator string) string {
  66. return mysqlOperators[operator]
  67. }
  68. // get mysql table field types.
  69. func (d *dbBaseMysql) DbTypes() map[string]string {
  70. return mysqlTypes
  71. }
  72. // show table sql for mysql.
  73. func (d *dbBaseMysql) ShowTablesQuery() string {
  74. return "SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = DATABASE()"
  75. }
  76. // show columns sql of table for mysql.
  77. func (d *dbBaseMysql) ShowColumnsQuery(table string) string {
  78. return fmt.Sprintf("SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE FROM information_schema.columns "+
  79. "WHERE table_schema = DATABASE() AND table_name = '%s'", table)
  80. }
  81. // execute sql to check index exist.
  82. func (d *dbBaseMysql) IndexExists(db dbQuerier, table string, name string) bool {
  83. row := db.QueryRow("SELECT count(*) FROM information_schema.statistics "+
  84. "WHERE table_schema = DATABASE() AND table_name = ? AND index_name = ?", table, name)
  85. var cnt int
  86. row.Scan(&cnt)
  87. return cnt > 0
  88. }
  89. // InsertOrUpdate a row
  90. // If your primary key or unique column conflict will update
  91. // If no will insert
  92. // Add "`" for mysql sql building
  93. func (d *dbBaseMysql) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a *alias, args ...string) (int64, error) {
  94. iouStr := ""
  95. argsMap := map[string]string{}
  96. iouStr = "ON DUPLICATE KEY UPDATE"
  97. //Get on the key-value pairs
  98. for _, v := range args {
  99. kv := strings.Split(v, "=")
  100. if len(kv) == 2 {
  101. argsMap[strings.ToLower(kv[0])] = kv[1]
  102. }
  103. }
  104. isMulti := false
  105. names := make([]string, 0, len(mi.fields.dbcols)-1)
  106. Q := d.ins.TableQuote()
  107. values, _, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, &names, a.TZ)
  108. if err != nil {
  109. return 0, err
  110. }
  111. marks := make([]string, len(names))
  112. updateValues := make([]interface{}, 0)
  113. updates := make([]string, len(names))
  114. for i, v := range names {
  115. marks[i] = "?"
  116. valueStr := argsMap[strings.ToLower(v)]
  117. if valueStr != "" {
  118. updates[i] = "`" + v + "`" + "=" + valueStr
  119. } else {
  120. updates[i] = "`" + v + "`" + "=?"
  121. updateValues = append(updateValues, values[i])
  122. }
  123. }
  124. values = append(values, updateValues...)
  125. sep := fmt.Sprintf("%s, %s", Q, Q)
  126. qmarks := strings.Join(marks, ", ")
  127. qupdates := strings.Join(updates, ", ")
  128. columns := strings.Join(names, sep)
  129. multi := len(values) / len(names)
  130. if isMulti {
  131. qmarks = strings.Repeat(qmarks+"), (", multi-1) + qmarks
  132. }
  133. //conflitValue maybe is a int,can`t use fmt.Sprintf
  134. query := fmt.Sprintf("INSERT INTO %s%s%s (%s%s%s) VALUES (%s) %s "+qupdates, Q, mi.table, Q, Q, columns, Q, qmarks, iouStr)
  135. d.ins.ReplaceMarks(&query)
  136. if isMulti || !d.ins.HasReturningID(mi, &query) {
  137. res, err := q.Exec(query, values...)
  138. if err == nil {
  139. if isMulti {
  140. return res.RowsAffected()
  141. }
  142. return res.LastInsertId()
  143. }
  144. return 0, err
  145. }
  146. row := q.QueryRow(query, values...)
  147. var id int64
  148. err = row.Scan(&id)
  149. return id, err
  150. }
  151. // create new mysql dbBaser.
  152. func newdbBaseMysql() dbBaser {
  153. b := new(dbBaseMysql)
  154. b.ins = b
  155. return b
  156. }