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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2015 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. "database/sql"
  7. "errors"
  8. "fmt"
  9. "reflect"
  10. "xorm.io/builder"
  11. "xorm.io/xorm/core"
  12. "xorm.io/xorm/internal/utils"
  13. )
  14. // Rows rows wrapper a rows to
  15. type Rows struct {
  16. session *Session
  17. rows *core.Rows
  18. beanType reflect.Type
  19. lastError error
  20. }
  21. func newRows(session *Session, bean interface{}) (*Rows, error) {
  22. rows := new(Rows)
  23. rows.session = session
  24. rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
  25. var sqlStr string
  26. var args []interface{}
  27. var err error
  28. beanValue := reflect.ValueOf(bean)
  29. if beanValue.Kind() != reflect.Ptr {
  30. return nil, errors.New("needs a pointer to a value")
  31. } else if beanValue.Elem().Kind() == reflect.Ptr {
  32. return nil, errors.New("a pointer to a pointer is not allowed")
  33. }
  34. if err = rows.session.statement.SetRefBean(bean); err != nil {
  35. return nil, err
  36. }
  37. if len(session.statement.TableName()) <= 0 {
  38. return nil, ErrTableNotFound
  39. }
  40. if rows.session.statement.RawSQL == "" {
  41. var autoCond builder.Cond
  42. var addedTableName = (len(session.statement.JoinStr) > 0)
  43. var table = rows.session.statement.RefTable
  44. if !session.statement.NoAutoCondition {
  45. var err error
  46. autoCond, err = session.statement.BuildConds(table, bean, true, true, false, true, addedTableName)
  47. if err != nil {
  48. return nil, err
  49. }
  50. } else {
  51. // !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
  52. // See https://gitea.com/xorm/xorm/issues/179
  53. if col := table.DeletedColumn(); col != nil && !session.statement.GetUnscoped() { // tag "deleted" is enabled
  54. var colName = session.engine.Quote(col.Name)
  55. if addedTableName {
  56. var nm = session.statement.TableName()
  57. if len(session.statement.TableAlias) > 0 {
  58. nm = session.statement.TableAlias
  59. }
  60. colName = session.engine.Quote(nm) + "." + colName
  61. }
  62. autoCond = session.statement.CondDeleted(col)
  63. }
  64. }
  65. sqlStr, args, err = rows.session.statement.GenFindSQL(autoCond)
  66. if err != nil {
  67. return nil, err
  68. }
  69. } else {
  70. sqlStr = rows.session.statement.GenRawSQL()
  71. args = rows.session.statement.RawParams
  72. }
  73. rows.rows, err = rows.session.queryRows(sqlStr, args...)
  74. if err != nil {
  75. rows.lastError = err
  76. rows.Close()
  77. return nil, err
  78. }
  79. return rows, nil
  80. }
  81. // Next move cursor to next record, return false if end has reached
  82. func (rows *Rows) Next() bool {
  83. if rows.lastError == nil && rows.rows != nil {
  84. hasNext := rows.rows.Next()
  85. if !hasNext {
  86. rows.lastError = sql.ErrNoRows
  87. }
  88. return hasNext
  89. }
  90. return false
  91. }
  92. // Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
  93. func (rows *Rows) Err() error {
  94. return rows.lastError
  95. }
  96. // Scan row record to bean properties
  97. func (rows *Rows) Scan(bean interface{}) error {
  98. if rows.lastError != nil {
  99. return rows.lastError
  100. }
  101. if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
  102. return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
  103. }
  104. if err := rows.session.statement.SetRefBean(bean); err != nil {
  105. return err
  106. }
  107. fields, err := rows.rows.Columns()
  108. if err != nil {
  109. return err
  110. }
  111. scanResults, err := rows.session.row2Slice(rows.rows, fields, bean)
  112. if err != nil {
  113. return err
  114. }
  115. dataStruct := utils.ReflectValue(bean)
  116. _, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable)
  117. if err != nil {
  118. return err
  119. }
  120. return rows.session.executeProcessors()
  121. }
  122. // Close session if session.IsAutoClose is true, and claimed any opened resources
  123. func (rows *Rows) Close() error {
  124. if rows.session.isAutoClose {
  125. defer rows.session.Close()
  126. }
  127. if rows.rows != nil {
  128. return rows.rows.Close()
  129. }
  130. return rows.lastError
  131. }