session_delete.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. "strconv"
  9. "github.com/2637309949/dolphin/packages/xormplus/xorm/caches"
  10. "github.com/2637309949/dolphin/packages/xormplus/xorm/schemas"
  11. )
  12. func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error {
  13. if table == nil ||
  14. session.tx != nil {
  15. return ErrCacheFailed
  16. }
  17. for _, filter := range session.engine.dialect.Filters() {
  18. sqlStr = filter.Do(sqlStr)
  19. }
  20. newsql := session.statement.ConvertIDSQL(sqlStr)
  21. if newsql == "" {
  22. return ErrCacheFailed
  23. }
  24. cacher := session.engine.cacherMgr.GetCacher(tableName)
  25. pkColumns := table.PKColumns()
  26. ids, err := caches.GetCacheSql(cacher, tableName, newsql, args)
  27. if err != nil {
  28. resultsSlice, err := session.queryBytes(newsql, args...)
  29. if err != nil {
  30. return err
  31. }
  32. ids = make([]schemas.PK, 0)
  33. if len(resultsSlice) > 0 {
  34. for _, data := range resultsSlice {
  35. var id int64
  36. var pk schemas.PK = make([]interface{}, 0)
  37. for _, col := range pkColumns {
  38. if v, ok := data[col.Name]; !ok {
  39. return errors.New("no id")
  40. } else if col.SQLType.IsText() {
  41. pk = append(pk, string(v))
  42. } else if col.SQLType.IsNumeric() {
  43. id, err = strconv.ParseInt(string(v), 10, 64)
  44. if err != nil {
  45. return err
  46. }
  47. pk = append(pk, id)
  48. } else {
  49. return errors.New("not supported primary key type")
  50. }
  51. }
  52. ids = append(ids, pk)
  53. }
  54. }
  55. }
  56. for _, id := range ids {
  57. session.engine.logger.Debugf("[cache] delete cache obj: %v, %v", tableName, id)
  58. sid, err := id.ToString()
  59. if err != nil {
  60. return err
  61. }
  62. cacher.DelBean(tableName, sid)
  63. }
  64. session.engine.logger.Debugf("[cache] clear cache table: %v", tableName)
  65. cacher.ClearIds(tableName)
  66. return nil
  67. }
  68. // Delete records, bean's non-empty fields are conditions
  69. func (session *Session) Delete(bean interface{}) (int64, error) {
  70. if session.isAutoClose {
  71. defer session.Close()
  72. }
  73. if session.statement.LastError != nil {
  74. return 0, session.statement.LastError
  75. }
  76. if err := session.statement.SetRefBean(bean); err != nil {
  77. return 0, err
  78. }
  79. executeBeforeClosures(session, bean)
  80. if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
  81. processor.BeforeDelete()
  82. }
  83. condSQL, condArgs, err := session.statement.GenConds(bean)
  84. if err != nil {
  85. return 0, err
  86. }
  87. pLimitN := session.statement.LimitN
  88. if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) {
  89. return 0, ErrNeedDeletedCond
  90. }
  91. var tableNameNoQuote = session.statement.TableName()
  92. var tableName = session.engine.Quote(tableNameNoQuote)
  93. var table = session.statement.RefTable
  94. var deleteSQL string
  95. if len(condSQL) > 0 {
  96. deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
  97. } else {
  98. deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
  99. }
  100. var orderSQL string
  101. if len(session.statement.OrderStr) > 0 {
  102. orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr)
  103. }
  104. if pLimitN != nil && *pLimitN > 0 {
  105. limitNValue := *pLimitN
  106. orderSQL += fmt.Sprintf(" LIMIT %d", limitNValue)
  107. }
  108. if len(orderSQL) > 0 {
  109. switch session.engine.dialect.URI().DBType {
  110. case schemas.POSTGRES:
  111. inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
  112. if len(condSQL) > 0 {
  113. deleteSQL += " AND " + inSQL
  114. } else {
  115. deleteSQL += " WHERE " + inSQL
  116. }
  117. case schemas.SQLITE:
  118. inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
  119. if len(condSQL) > 0 {
  120. deleteSQL += " AND " + inSQL
  121. } else {
  122. deleteSQL += " WHERE " + inSQL
  123. }
  124. // TODO: how to handle delete limit on mssql?
  125. case schemas.MSSQL:
  126. return 0, ErrNotImplemented
  127. default:
  128. deleteSQL += orderSQL
  129. }
  130. }
  131. var realSQL string
  132. argsForCache := make([]interface{}, 0, len(condArgs)*2)
  133. if session.statement.GetUnscoped() || table.DeletedColumn() == nil { // tag "deleted" is disabled
  134. realSQL = deleteSQL
  135. copy(argsForCache, condArgs)
  136. argsForCache = append(condArgs, argsForCache...)
  137. } else {
  138. // !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for caches.
  139. copy(argsForCache, condArgs)
  140. argsForCache = append(condArgs, argsForCache...)
  141. deletedColumn := table.DeletedColumn()
  142. realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
  143. session.engine.Quote(session.statement.TableName()),
  144. session.engine.Quote(deletedColumn.Name),
  145. condSQL)
  146. if len(orderSQL) > 0 {
  147. switch session.engine.dialect.URI().DBType {
  148. case schemas.POSTGRES:
  149. inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
  150. if len(condSQL) > 0 {
  151. realSQL += " AND " + inSQL
  152. } else {
  153. realSQL += " WHERE " + inSQL
  154. }
  155. case schemas.SQLITE:
  156. inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
  157. if len(condSQL) > 0 {
  158. realSQL += " AND " + inSQL
  159. } else {
  160. realSQL += " WHERE " + inSQL
  161. }
  162. // TODO: how to handle delete limit on mssql?
  163. case schemas.MSSQL:
  164. return 0, ErrNotImplemented
  165. default:
  166. realSQL += orderSQL
  167. }
  168. }
  169. // !oinume! Insert nowTime to the head of session.statement.Params
  170. condArgs = append(condArgs, "")
  171. paramsLen := len(condArgs)
  172. copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
  173. val, t := session.engine.nowTime(deletedColumn)
  174. condArgs[0] = val
  175. var colName = deletedColumn.Name
  176. session.afterClosures = append(session.afterClosures, func(bean interface{}) {
  177. col := table.GetColumn(colName)
  178. setColumnTime(bean, col, t)
  179. })
  180. }
  181. if cacher := session.engine.GetCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache {
  182. session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
  183. }
  184. session.statement.RefTable = table
  185. res, err := session.exec(realSQL, condArgs...)
  186. if err != nil {
  187. return 0, err
  188. }
  189. // handle after delete processors
  190. if session.isAutoCommit {
  191. for _, closure := range session.afterClosures {
  192. closure(bean)
  193. }
  194. if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
  195. processor.AfterDelete()
  196. }
  197. } else {
  198. lenAfterClosures := len(session.afterClosures)
  199. if lenAfterClosures > 0 {
  200. if value, has := session.afterDeleteBeans[bean]; has && value != nil {
  201. *value = append(*value, session.afterClosures...)
  202. } else {
  203. afterClosures := make([]func(interface{}), lenAfterClosures)
  204. copy(afterClosures, session.afterClosures)
  205. session.afterDeleteBeans[bean] = &afterClosures
  206. }
  207. } else {
  208. if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
  209. session.afterDeleteBeans[bean] = nil
  210. }
  211. }
  212. }
  213. cleanupProcessorsClosures(&session.afterClosures)
  214. // --
  215. return res.RowsAffected()
  216. }