Simple and Powerful ORM for Go, support mysql,postgres,tidb,sqlite3,mssql,oracle https://xorm.io
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

459 行
12 KiB

  1. // Copyright 2016 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package xorm
  5. import (
  6. "errors"
  7. "fmt"
  8. "reflect"
  9. "strings"
  10. "github.com/go-xorm/builder"
  11. "github.com/go-xorm/core"
  12. )
  13. const (
  14. tpStruct = iota
  15. tpNonStruct
  16. )
  17. // Find retrieve records from table, condiBeans's non-empty fields
  18. // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
  19. // map[int64]*Struct
  20. func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
  21. if session.isAutoClose {
  22. defer session.Close()
  23. }
  24. return session.find(rowsSlicePtr, condiBean...)
  25. }
  26. func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
  27. sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
  28. if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
  29. return errors.New("needs a pointer to a slice or a map")
  30. }
  31. sliceElementType := sliceValue.Type().Elem()
  32. var tp = tpStruct
  33. if session.statement.RefTable == nil {
  34. if sliceElementType.Kind() == reflect.Ptr {
  35. if sliceElementType.Elem().Kind() == reflect.Struct {
  36. pv := reflect.New(sliceElementType.Elem())
  37. if err := session.statement.setRefValue(pv.Elem()); err != nil {
  38. return err
  39. }
  40. } else {
  41. tp = tpNonStruct
  42. }
  43. } else if sliceElementType.Kind() == reflect.Struct {
  44. pv := reflect.New(sliceElementType)
  45. if err := session.statement.setRefValue(pv.Elem()); err != nil {
  46. return err
  47. }
  48. } else {
  49. tp = tpNonStruct
  50. }
  51. }
  52. var table = session.statement.RefTable
  53. var addedTableName = (len(session.statement.JoinStr) > 0)
  54. var autoCond builder.Cond
  55. if tp == tpStruct {
  56. if !session.statement.noAutoCondition && len(condiBean) > 0 {
  57. var err error
  58. autoCond, err = session.statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName)
  59. if err != nil {
  60. return err
  61. }
  62. } else {
  63. // !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
  64. // See https://github.com/go-xorm/xorm/issues/179
  65. if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled
  66. var colName = session.engine.Quote(col.Name)
  67. if addedTableName {
  68. var nm = session.statement.TableName()
  69. if len(session.statement.TableAlias) > 0 {
  70. nm = session.statement.TableAlias
  71. }
  72. colName = session.engine.Quote(nm) + "." + colName
  73. }
  74. autoCond = session.engine.CondDeleted(colName)
  75. }
  76. }
  77. }
  78. var sqlStr string
  79. var args []interface{}
  80. var err error
  81. if session.statement.RawSQL == "" {
  82. if len(session.statement.TableName()) <= 0 {
  83. return ErrTableNotFound
  84. }
  85. var columnStr = session.statement.ColumnStr
  86. if len(session.statement.selectStr) > 0 {
  87. columnStr = session.statement.selectStr
  88. } else {
  89. if session.statement.JoinStr == "" {
  90. if columnStr == "" {
  91. if session.statement.GroupByStr != "" {
  92. columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
  93. } else {
  94. columnStr = session.statement.genColumnStr()
  95. }
  96. }
  97. } else {
  98. if columnStr == "" {
  99. if session.statement.GroupByStr != "" {
  100. columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
  101. } else {
  102. columnStr = "*"
  103. }
  104. }
  105. }
  106. if columnStr == "" {
  107. columnStr = "*"
  108. }
  109. }
  110. session.statement.cond = session.statement.cond.And(autoCond)
  111. condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
  112. if err != nil {
  113. return err
  114. }
  115. args = append(session.statement.joinArgs, condArgs...)
  116. sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL)
  117. if err != nil {
  118. return err
  119. }
  120. // for mssql and use limit
  121. qs := strings.Count(sqlStr, "?")
  122. if len(args)*2 == qs {
  123. args = append(args, args...)
  124. }
  125. } else {
  126. sqlStr = session.statement.RawSQL
  127. args = session.statement.RawParams
  128. }
  129. if session.canCache() {
  130. if cacher := session.engine.getCacher2(table); cacher != nil &&
  131. !session.statement.IsDistinct &&
  132. !session.statement.unscoped {
  133. err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
  134. if err != ErrCacheFailed {
  135. return err
  136. }
  137. err = nil // !nashtsai! reset err to nil for ErrCacheFailed
  138. session.engine.logger.Warn("Cache Find Failed")
  139. }
  140. }
  141. return session.noCacheFind(table, sliceValue, sqlStr, args...)
  142. }
  143. func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
  144. rows, err := session.queryRows(sqlStr, args...)
  145. if err != nil {
  146. return err
  147. }
  148. defer rows.Close()
  149. fields, err := rows.Columns()
  150. if err != nil {
  151. return err
  152. }
  153. var newElemFunc func(fields []string) reflect.Value
  154. elemType := containerValue.Type().Elem()
  155. var isPointer bool
  156. if elemType.Kind() == reflect.Ptr {
  157. isPointer = true
  158. elemType = elemType.Elem()
  159. }
  160. if elemType.Kind() == reflect.Ptr {
  161. return errors.New("pointer to pointer is not supported")
  162. }
  163. newElemFunc = func(fields []string) reflect.Value {
  164. switch elemType.Kind() {
  165. case reflect.Slice:
  166. slice := reflect.MakeSlice(elemType, len(fields), len(fields))
  167. x := reflect.New(slice.Type())
  168. x.Elem().Set(slice)
  169. return x
  170. case reflect.Map:
  171. mp := reflect.MakeMap(elemType)
  172. x := reflect.New(mp.Type())
  173. x.Elem().Set(mp)
  174. return x
  175. }
  176. return reflect.New(elemType)
  177. }
  178. var containerValueSetFunc func(*reflect.Value, core.PK) error
  179. if containerValue.Kind() == reflect.Slice {
  180. containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
  181. if isPointer {
  182. containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
  183. } else {
  184. containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
  185. }
  186. return nil
  187. }
  188. } else {
  189. keyType := containerValue.Type().Key()
  190. if len(table.PrimaryKeys) == 0 {
  191. return errors.New("don't support multiple primary key's map has non-slice key type")
  192. }
  193. if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice {
  194. return errors.New("don't support multiple primary key's map has non-slice key type")
  195. }
  196. containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
  197. keyValue := reflect.New(keyType)
  198. err := convertPKToValue(table, keyValue.Interface(), pk)
  199. if err != nil {
  200. return err
  201. }
  202. if isPointer {
  203. containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
  204. } else {
  205. containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
  206. }
  207. return nil
  208. }
  209. }
  210. if elemType.Kind() == reflect.Struct {
  211. var newValue = newElemFunc(fields)
  212. dataStruct := rValue(newValue.Interface())
  213. tb, err := session.engine.autoMapType(dataStruct)
  214. if err != nil {
  215. return err
  216. }
  217. return session.rows2Beans(rows, fields, len(fields), tb, newElemFunc, containerValueSetFunc)
  218. }
  219. for rows.Next() {
  220. var newValue = newElemFunc(fields)
  221. bean := newValue.Interface()
  222. switch elemType.Kind() {
  223. case reflect.Slice:
  224. err = rows.ScanSlice(bean)
  225. case reflect.Map:
  226. err = rows.ScanMap(bean)
  227. default:
  228. err = rows.Scan(bean)
  229. }
  230. if err != nil {
  231. return err
  232. }
  233. if err := containerValueSetFunc(&newValue, nil); err != nil {
  234. return err
  235. }
  236. }
  237. return nil
  238. }
  239. func convertPKToValue(table *core.Table, dst interface{}, pk core.PK) error {
  240. cols := table.PKColumns()
  241. if len(cols) == 1 {
  242. return convertAssign(dst, pk[0])
  243. }
  244. dst = pk
  245. return nil
  246. }
  247. func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
  248. if !session.canCache() ||
  249. indexNoCase(sqlStr, "having") != -1 ||
  250. indexNoCase(sqlStr, "group by") != -1 {
  251. return ErrCacheFailed
  252. }
  253. for _, filter := range session.engine.dialect.Filters() {
  254. sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
  255. }
  256. newsql := session.statement.convertIDSQL(sqlStr)
  257. if newsql == "" {
  258. return ErrCacheFailed
  259. }
  260. tableName := session.statement.TableName()
  261. table := session.statement.RefTable
  262. cacher := session.engine.getCacher2(table)
  263. ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
  264. if err != nil {
  265. rows, err := session.NoCache().queryRows(newsql, args...)
  266. if err != nil {
  267. return err
  268. }
  269. defer rows.Close()
  270. var i int
  271. ids = make([]core.PK, 0)
  272. for rows.Next() {
  273. i++
  274. if i > 500 {
  275. session.engine.logger.Debug("[cacheFind] ids length > 500, no cache")
  276. return ErrCacheFailed
  277. }
  278. var res = make([]string, len(table.PrimaryKeys))
  279. err = rows.ScanSlice(&res)
  280. if err != nil {
  281. return err
  282. }
  283. var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
  284. for i, col := range table.PKColumns() {
  285. pk[i], err = session.engine.idTypeAssertion(col, res[i])
  286. if err != nil {
  287. return err
  288. }
  289. }
  290. ids = append(ids, pk)
  291. }
  292. session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, newsql, args)
  293. err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
  294. if err != nil {
  295. return err
  296. }
  297. } else {
  298. session.engine.logger.Debug("[cacheFind] cache hit sql:", newsql, args)
  299. }
  300. sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
  301. ididxes := make(map[string]int)
  302. var ides []core.PK
  303. var temps = make([]interface{}, len(ids))
  304. for idx, id := range ids {
  305. sid, err := id.ToString()
  306. if err != nil {
  307. return err
  308. }
  309. bean := cacher.GetBean(tableName, sid)
  310. if bean == nil {
  311. ides = append(ides, id)
  312. ididxes[sid] = idx
  313. } else {
  314. session.engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean)
  315. pk := session.engine.IdOf(bean)
  316. xid, err := pk.ToString()
  317. if err != nil {
  318. return err
  319. }
  320. if sid != xid {
  321. session.engine.logger.Error("[cacheFind] error cache", xid, sid, bean)
  322. return ErrCacheFailed
  323. }
  324. temps[idx] = bean
  325. }
  326. }
  327. if len(ides) > 0 {
  328. slices := reflect.New(reflect.SliceOf(t))
  329. beans := slices.Interface()
  330. if len(table.PrimaryKeys) == 1 {
  331. ff := make([]interface{}, 0, len(ides))
  332. for _, ie := range ides {
  333. ff = append(ff, ie[0])
  334. }
  335. session.In("`"+table.PrimaryKeys[0]+"`", ff...)
  336. } else {
  337. for _, ie := range ides {
  338. cond := builder.NewCond()
  339. for i, name := range table.PrimaryKeys {
  340. cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
  341. }
  342. session.Or(cond)
  343. }
  344. }
  345. err = session.NoCache().find(beans)
  346. if err != nil {
  347. return err
  348. }
  349. vs := reflect.Indirect(reflect.ValueOf(beans))
  350. for i := 0; i < vs.Len(); i++ {
  351. rv := vs.Index(i)
  352. if rv.Kind() != reflect.Ptr {
  353. rv = rv.Addr()
  354. }
  355. id, err := session.engine.idOfV(rv)
  356. if err != nil {
  357. return err
  358. }
  359. sid, err := id.ToString()
  360. if err != nil {
  361. return err
  362. }
  363. bean := rv.Interface()
  364. temps[ididxes[sid]] = bean
  365. session.engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps)
  366. cacher.PutBean(tableName, sid, bean)
  367. }
  368. }
  369. for j := 0; j < len(temps); j++ {
  370. bean := temps[j]
  371. if bean == nil {
  372. session.engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps)
  373. // return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
  374. continue
  375. }
  376. if sliceValue.Kind() == reflect.Slice {
  377. if t.Kind() == reflect.Ptr {
  378. sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean)))
  379. } else {
  380. sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean))))
  381. }
  382. } else if sliceValue.Kind() == reflect.Map {
  383. var key = ids[j]
  384. keyType := sliceValue.Type().Key()
  385. var ikey interface{}
  386. if len(key) == 1 {
  387. ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType)
  388. if err != nil {
  389. return err
  390. }
  391. } else {
  392. if keyType.Kind() != reflect.Slice {
  393. return errors.New("table have multiple primary keys, key is not core.PK or slice")
  394. }
  395. ikey = key
  396. }
  397. if t.Kind() == reflect.Ptr {
  398. sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean))
  399. } else {
  400. sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean)))
  401. }
  402. }
  403. }
  404. return nil
  405. }