You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

session_find.go 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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. "xorm.io/builder"
  10. "xorm.io/xorm/caches"
  11. "xorm.io/xorm/internal/statements"
  12. "xorm.io/xorm/internal/utils"
  13. "xorm.io/xorm/schemas"
  14. )
  15. const (
  16. tpStruct = iota
  17. tpNonStruct
  18. )
  19. // Find retrieve records from table, condiBeans's non-empty fields
  20. // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
  21. // map[int64]*Struct
  22. func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
  23. if session.isAutoClose {
  24. defer session.Close()
  25. }
  26. return session.find(rowsSlicePtr, condiBean...)
  27. }
  28. // FindAndCount find the results and also return the counts
  29. func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
  30. if session.isAutoClose {
  31. defer session.Close()
  32. }
  33. session.autoResetStatement = false
  34. err := session.find(rowsSlicePtr, condiBean...)
  35. if err != nil {
  36. return 0, err
  37. }
  38. sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
  39. if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
  40. return 0, errors.New("needs a pointer to a slice or a map")
  41. }
  42. sliceElementType := sliceValue.Type().Elem()
  43. if sliceElementType.Kind() == reflect.Ptr {
  44. sliceElementType = sliceElementType.Elem()
  45. }
  46. session.autoResetStatement = true
  47. if session.statement.SelectStr != "" {
  48. session.statement.SelectStr = ""
  49. }
  50. if session.statement.OrderStr != "" {
  51. session.statement.OrderStr = ""
  52. }
  53. if session.statement.LimitN != nil {
  54. session.statement.LimitN = nil
  55. }
  56. if session.statement.Start > 0 {
  57. session.statement.Start = 0
  58. }
  59. // session has stored the conditions so we use `unscoped` to avoid duplicated condition.
  60. return session.Unscoped().Count(reflect.New(sliceElementType).Interface())
  61. }
  62. func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
  63. defer session.resetStatement()
  64. if session.statement.LastError != nil {
  65. return session.statement.LastError
  66. }
  67. sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
  68. var isSlice = sliceValue.Kind() == reflect.Slice
  69. var isMap = sliceValue.Kind() == reflect.Map
  70. if !isSlice && !isMap {
  71. return errors.New("needs a pointer to a slice or a map")
  72. }
  73. sliceElementType := sliceValue.Type().Elem()
  74. var tp = tpStruct
  75. if session.statement.RefTable == nil {
  76. if sliceElementType.Kind() == reflect.Ptr {
  77. if sliceElementType.Elem().Kind() == reflect.Struct {
  78. pv := reflect.New(sliceElementType.Elem())
  79. if err := session.statement.SetRefValue(pv); err != nil {
  80. return err
  81. }
  82. } else {
  83. tp = tpNonStruct
  84. }
  85. } else if sliceElementType.Kind() == reflect.Struct {
  86. pv := reflect.New(sliceElementType)
  87. if err := session.statement.SetRefValue(pv); err != nil {
  88. return err
  89. }
  90. } else {
  91. tp = tpNonStruct
  92. }
  93. }
  94. var (
  95. table = session.statement.RefTable
  96. addedTableName = (len(session.statement.JoinStr) > 0)
  97. autoCond builder.Cond
  98. )
  99. if tp == tpStruct {
  100. if !session.statement.NoAutoCondition && len(condiBean) > 0 {
  101. condTable, err := session.engine.tagParser.Parse(reflect.ValueOf(condiBean[0]))
  102. if err != nil {
  103. return err
  104. }
  105. autoCond, err = session.statement.BuildConds(condTable, condiBean[0], true, true, false, true, addedTableName)
  106. if err != nil {
  107. return err
  108. }
  109. } else {
  110. if col := table.DeletedColumn(); col != nil && !session.statement.GetUnscoped() { // tag "deleted" is enabled
  111. autoCond = session.statement.CondDeleted(col)
  112. }
  113. }
  114. }
  115. // if it's a map with Cols but primary key not in column list, we still need the primary key
  116. if isMap && !session.statement.ColumnMap.IsEmpty() {
  117. for _, k := range session.statement.RefTable.PrimaryKeys {
  118. session.statement.ColumnMap.Add(k)
  119. }
  120. }
  121. sqlStr, args, err := session.statement.GenFindSQL(autoCond)
  122. if err != nil {
  123. return err
  124. }
  125. if session.statement.ColumnMap.IsEmpty() && session.canCache() {
  126. if cacher := session.engine.GetCacher(session.statement.TableName()); cacher != nil &&
  127. !session.statement.IsDistinct &&
  128. !session.statement.GetUnscoped() {
  129. err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
  130. if err != ErrCacheFailed {
  131. return err
  132. }
  133. err = nil // !nashtsai! reset err to nil for ErrCacheFailed
  134. session.engine.logger.Warnf("Cache Find Failed")
  135. }
  136. }
  137. return session.noCacheFind(table, sliceValue, sqlStr, args...)
  138. }
  139. func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
  140. rows, err := session.queryRows(sqlStr, args...)
  141. if err != nil {
  142. return err
  143. }
  144. defer rows.Close()
  145. fields, err := rows.Columns()
  146. if err != nil {
  147. return err
  148. }
  149. var newElemFunc func(fields []string) reflect.Value
  150. elemType := containerValue.Type().Elem()
  151. var isPointer bool
  152. if elemType.Kind() == reflect.Ptr {
  153. isPointer = true
  154. elemType = elemType.Elem()
  155. }
  156. if elemType.Kind() == reflect.Ptr {
  157. return errors.New("pointer to pointer is not supported")
  158. }
  159. newElemFunc = func(fields []string) reflect.Value {
  160. switch elemType.Kind() {
  161. case reflect.Slice:
  162. slice := reflect.MakeSlice(elemType, len(fields), len(fields))
  163. x := reflect.New(slice.Type())
  164. x.Elem().Set(slice)
  165. return x
  166. case reflect.Map:
  167. mp := reflect.MakeMap(elemType)
  168. x := reflect.New(mp.Type())
  169. x.Elem().Set(mp)
  170. return x
  171. }
  172. return reflect.New(elemType)
  173. }
  174. var containerValueSetFunc func(*reflect.Value, schemas.PK) error
  175. if containerValue.Kind() == reflect.Slice {
  176. containerValueSetFunc = func(newValue *reflect.Value, pk schemas.PK) error {
  177. if isPointer {
  178. containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
  179. } else {
  180. containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
  181. }
  182. return nil
  183. }
  184. } else {
  185. keyType := containerValue.Type().Key()
  186. if len(table.PrimaryKeys) == 0 {
  187. return errors.New("don't support multiple primary key's map has non-slice key type")
  188. }
  189. if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice {
  190. return errors.New("don't support multiple primary key's map has non-slice key type")
  191. }
  192. containerValueSetFunc = func(newValue *reflect.Value, pk schemas.PK) error {
  193. keyValue := reflect.New(keyType)
  194. err := convertPKToValue(table, keyValue.Interface(), pk)
  195. if err != nil {
  196. return err
  197. }
  198. if isPointer {
  199. containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
  200. } else {
  201. containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
  202. }
  203. return nil
  204. }
  205. }
  206. if elemType.Kind() == reflect.Struct {
  207. var newValue = newElemFunc(fields)
  208. dataStruct := utils.ReflectValue(newValue.Interface())
  209. tb, err := session.engine.tagParser.ParseWithCache(dataStruct)
  210. if err != nil {
  211. return err
  212. }
  213. err = session.rows2Beans(rows, fields, tb, newElemFunc, containerValueSetFunc)
  214. rows.Close()
  215. if err != nil {
  216. return err
  217. }
  218. return session.executeProcessors()
  219. }
  220. for rows.Next() {
  221. var newValue = newElemFunc(fields)
  222. bean := newValue.Interface()
  223. switch elemType.Kind() {
  224. case reflect.Slice:
  225. err = rows.ScanSlice(bean)
  226. case reflect.Map:
  227. err = rows.ScanMap(bean)
  228. default:
  229. err = rows.Scan(bean)
  230. }
  231. if err != nil {
  232. return err
  233. }
  234. if err := containerValueSetFunc(&newValue, nil); err != nil {
  235. return err
  236. }
  237. }
  238. return nil
  239. }
  240. func convertPKToValue(table *schemas.Table, dst interface{}, pk schemas.PK) error {
  241. cols := table.PKColumns()
  242. if len(cols) == 1 {
  243. return convertAssign(dst, pk[0])
  244. }
  245. dst = pk
  246. return nil
  247. }
  248. func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
  249. if !session.canCache() ||
  250. utils.IndexNoCase(sqlStr, "having") != -1 ||
  251. utils.IndexNoCase(sqlStr, "group by") != -1 {
  252. return ErrCacheFailed
  253. }
  254. tableName := session.statement.TableName()
  255. cacher := session.engine.cacherMgr.GetCacher(tableName)
  256. if cacher == nil {
  257. return nil
  258. }
  259. for _, filter := range session.engine.dialect.Filters() {
  260. sqlStr = filter.Do(sqlStr)
  261. }
  262. newsql := session.statement.ConvertIDSQL(sqlStr)
  263. if newsql == "" {
  264. return ErrCacheFailed
  265. }
  266. table := session.statement.RefTable
  267. ids, err := caches.GetCacheSql(cacher, tableName, newsql, args)
  268. if err != nil {
  269. rows, err := session.queryRows(newsql, args...)
  270. if err != nil {
  271. return err
  272. }
  273. defer rows.Close()
  274. var i int
  275. ids = make([]schemas.PK, 0)
  276. for rows.Next() {
  277. i++
  278. if i > 500 {
  279. session.engine.logger.Debugf("[cacheFind] ids length > 500, no cache")
  280. return ErrCacheFailed
  281. }
  282. var res = make([]string, len(table.PrimaryKeys))
  283. err = rows.ScanSlice(&res)
  284. if err != nil {
  285. return err
  286. }
  287. var pk schemas.PK = make([]interface{}, len(table.PrimaryKeys))
  288. for i, col := range table.PKColumns() {
  289. pk[i], err = col.ConvertID(res[i])
  290. if err != nil {
  291. return err
  292. }
  293. }
  294. ids = append(ids, pk)
  295. }
  296. session.engine.logger.Debugf("[cache] cache sql: %v, %v, %v, %v, %v", ids, tableName, sqlStr, newsql, args)
  297. err = caches.PutCacheSql(cacher, ids, tableName, newsql, args)
  298. if err != nil {
  299. return err
  300. }
  301. } else {
  302. session.engine.logger.Debugf("[cache] cache hit sql: %v, %v, %v, %v", tableName, sqlStr, newsql, args)
  303. }
  304. sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
  305. ididxes := make(map[string]int)
  306. var ides []schemas.PK
  307. var temps = make([]interface{}, len(ids))
  308. for idx, id := range ids {
  309. sid, err := id.ToString()
  310. if err != nil {
  311. return err
  312. }
  313. bean := cacher.GetBean(tableName, sid)
  314. // fix issue #894
  315. isHit := func() (ht bool) {
  316. if bean == nil {
  317. ht = false
  318. return
  319. }
  320. ckb := reflect.ValueOf(bean).Elem().Type()
  321. ht = ckb == t
  322. if !ht && t.Kind() == reflect.Ptr {
  323. ht = t.Elem() == ckb
  324. }
  325. return
  326. }
  327. if !isHit() {
  328. ides = append(ides, id)
  329. ididxes[sid] = idx
  330. } else {
  331. session.engine.logger.Debugf("[cache] cache hit bean: %v, %v, %v", tableName, id, bean)
  332. pk, err := table.IDOfV(reflect.ValueOf(bean))
  333. if err != nil {
  334. return err
  335. }
  336. xid, err := pk.ToString()
  337. if err != nil {
  338. return err
  339. }
  340. if sid != xid {
  341. session.engine.logger.Errorf("[cache] error cache: %v, %v, %v", xid, sid, bean)
  342. return ErrCacheFailed
  343. }
  344. temps[idx] = bean
  345. }
  346. }
  347. if len(ides) > 0 {
  348. slices := reflect.New(reflect.SliceOf(t))
  349. beans := slices.Interface()
  350. statement := session.statement
  351. session.statement = statements.NewStatement(
  352. session.engine.dialect,
  353. session.engine.tagParser,
  354. session.engine.DatabaseTZ,
  355. )
  356. if len(table.PrimaryKeys) == 1 {
  357. ff := make([]interface{}, 0, len(ides))
  358. for _, ie := range ides {
  359. ff = append(ff, ie[0])
  360. }
  361. session.In("`"+table.PrimaryKeys[0]+"`", ff...)
  362. } else {
  363. for _, ie := range ides {
  364. cond := builder.NewCond()
  365. for i, name := range table.PrimaryKeys {
  366. cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
  367. }
  368. session.Or(cond)
  369. }
  370. }
  371. err = session.NoCache().Table(tableName).find(beans)
  372. if err != nil {
  373. return err
  374. }
  375. session.statement = statement
  376. vs := reflect.Indirect(reflect.ValueOf(beans))
  377. for i := 0; i < vs.Len(); i++ {
  378. rv := vs.Index(i)
  379. if rv.Kind() != reflect.Ptr {
  380. rv = rv.Addr()
  381. }
  382. id, err := table.IDOfV(rv)
  383. if err != nil {
  384. return err
  385. }
  386. sid, err := id.ToString()
  387. if err != nil {
  388. return err
  389. }
  390. bean := rv.Interface()
  391. temps[ididxes[sid]] = bean
  392. session.engine.logger.Debugf("[cache] cache bean: %v, %v, %v, %v", tableName, id, bean, temps)
  393. cacher.PutBean(tableName, sid, bean)
  394. }
  395. }
  396. for j := 0; j < len(temps); j++ {
  397. bean := temps[j]
  398. if bean == nil {
  399. session.engine.logger.Warnf("[cache] cache no hit: %v, %v, %v", tableName, ids[j], temps)
  400. // return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
  401. continue
  402. }
  403. if sliceValue.Kind() == reflect.Slice {
  404. if t.Kind() == reflect.Ptr {
  405. sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean)))
  406. } else {
  407. sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean))))
  408. }
  409. } else if sliceValue.Kind() == reflect.Map {
  410. var key = ids[j]
  411. keyType := sliceValue.Type().Key()
  412. var ikey interface{}
  413. if len(key) == 1 {
  414. ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType)
  415. if err != nil {
  416. return err
  417. }
  418. } else {
  419. if keyType.Kind() != reflect.Slice {
  420. return errors.New("table have multiple primary keys, key is not schemas.PK or slice")
  421. }
  422. ikey = key
  423. }
  424. if t.Kind() == reflect.Ptr {
  425. sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean))
  426. } else {
  427. sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean)))
  428. }
  429. }
  430. }
  431. return nil
  432. }