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

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