qrz/vendor/xorm.io/xorm/session_delete.go

202 lines
5.4 KiB
Go
Raw Normal View History

2020-07-19 19:32:22 +02:00
// Copyright 2016 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
"errors"
"strconv"
2022-07-16 11:43:41 +02:00
"xorm.io/builder"
2020-07-19 19:32:22 +02:00
"xorm.io/xorm/caches"
"xorm.io/xorm/schemas"
)
2023-10-01 12:09:07 +02:00
// ErrNeedDeletedCond delete needs less one condition error
var ErrNeedDeletedCond = errors.New("Delete action needs at least one condition")
2020-07-19 19:32:22 +02:00
func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error {
if table == nil ||
session.tx != nil {
return ErrCacheFailed
}
for _, filter := range session.engine.dialect.Filters() {
2023-10-01 12:09:07 +02:00
sqlStr = filter.Do(session.ctx, sqlStr)
2020-07-19 19:32:22 +02:00
}
newsql := session.statement.ConvertIDSQL(sqlStr)
if newsql == "" {
return ErrCacheFailed
}
cacher := session.engine.cacherMgr.GetCacher(tableName)
pkColumns := table.PKColumns()
ids, err := caches.GetCacheSql(cacher, tableName, newsql, args)
if err != nil {
2022-07-16 11:43:41 +02:00
rows, err := session.queryRows(newsql, args...)
if err != nil {
return err
}
defer rows.Close()
resultsSlice, err := session.engine.ScanStringMaps(rows)
2020-07-19 19:32:22 +02:00
if err != nil {
return err
}
ids = make([]schemas.PK, 0)
if len(resultsSlice) > 0 {
for _, data := range resultsSlice {
var id int64
var pk schemas.PK = make([]interface{}, 0)
for _, col := range pkColumns {
if v, ok := data[col.Name]; !ok {
return errors.New("no id")
} else if col.SQLType.IsText() {
2022-07-16 11:43:41 +02:00
pk = append(pk, v)
2020-07-19 19:32:22 +02:00
} else if col.SQLType.IsNumeric() {
2022-07-16 11:43:41 +02:00
id, err = strconv.ParseInt(v, 10, 64)
2020-07-19 19:32:22 +02:00
if err != nil {
return err
}
pk = append(pk, id)
} else {
return errors.New("not supported primary key type")
}
}
ids = append(ids, pk)
}
}
}
for _, id := range ids {
session.engine.logger.Debugf("[cache] delete cache obj: %v, %v", tableName, id)
sid, err := id.ToString()
if err != nil {
return err
}
cacher.DelBean(tableName, sid)
}
session.engine.logger.Debugf("[cache] clear cache table: %v", tableName)
cacher.ClearIds(tableName)
return nil
}
// Delete records, bean's non-empty fields are conditions
2023-10-01 12:09:07 +02:00
// At least one condition must be set.
2021-08-30 19:45:06 +02:00
func (session *Session) Delete(beans ...interface{}) (int64, error) {
2023-10-01 12:09:07 +02:00
return session.delete(beans, true)
}
// Truncate records, bean's non-empty fields are conditions
// In contrast to Delete this method allows deletes without conditions.
func (session *Session) Truncate(beans ...interface{}) (int64, error) {
return session.delete(beans, false)
}
func (session *Session) delete(beans []interface{}, mustHaveConditions bool) (int64, error) {
2020-07-19 19:32:22 +02:00
if session.isAutoClose {
defer session.Close()
}
if session.statement.LastError != nil {
return 0, session.statement.LastError
}
2021-08-30 19:45:06 +02:00
var (
2023-10-01 12:09:07 +02:00
err error
bean interface{}
2021-08-30 19:45:06 +02:00
)
if len(beans) > 0 {
bean = beans[0]
if err = session.statement.SetRefBean(bean); err != nil {
return 0, err
}
2020-07-19 19:32:22 +02:00
2021-08-30 19:45:06 +02:00
executeBeforeClosures(session, bean)
2020-07-19 19:32:22 +02:00
2021-08-30 19:45:06 +02:00
if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
processor.BeforeDelete()
}
2020-07-19 19:32:22 +02:00
2022-07-16 11:43:41 +02:00
if err = session.statement.MergeConds(bean); err != nil {
return 0, err
}
2021-08-30 19:45:06 +02:00
}
2022-07-16 11:43:41 +02:00
2020-07-19 19:32:22 +02:00
pLimitN := session.statement.LimitN
2023-10-01 12:09:07 +02:00
if mustHaveConditions && !session.statement.Conds().IsValid() && (pLimitN == nil || *pLimitN == 0) {
2020-07-19 19:32:22 +02:00
return 0, ErrNeedDeletedCond
}
2022-07-16 11:43:41 +02:00
tableNameNoQuote := session.statement.TableName()
table := session.statement.RefTable
2020-07-19 19:32:22 +02:00
2023-10-01 12:09:07 +02:00
realSQLWriter := builder.NewWriter()
deleteSQLWriter := builder.NewWriter()
if err := session.statement.WriteDelete(realSQLWriter, deleteSQLWriter, session.engine.nowTime); err != nil {
2022-07-16 11:43:41 +02:00
return 0, err
2020-07-19 19:32:22 +02:00
}
2022-07-16 11:43:41 +02:00
2021-08-30 19:45:06 +02:00
if session.statement.GetUnscoped() || table == nil || table.DeletedColumn() == nil { // tag "deleted" is disabled
2020-07-19 19:32:22 +02:00
} else {
deletedColumn := table.DeletedColumn()
2023-10-01 12:09:07 +02:00
_, t, err := session.engine.nowTime(deletedColumn)
2021-08-30 19:45:06 +02:00
if err != nil {
return 0, err
}
2020-07-19 19:32:22 +02:00
2022-07-16 11:43:41 +02:00
colName := deletedColumn.Name
2020-07-19 19:32:22 +02:00
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
}
2023-10-01 12:09:07 +02:00
argsForCache := make([]interface{}, 0, len(deleteSQLWriter.Args())*2)
copy(argsForCache, deleteSQLWriter.Args())
argsForCache = append(deleteSQLWriter.Args(), argsForCache...)
2020-07-19 19:32:22 +02:00
if cacher := session.engine.GetCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache {
2022-07-16 11:43:41 +02:00
_ = session.cacheDelete(table, tableNameNoQuote, deleteSQLWriter.String(), argsForCache...)
2020-07-19 19:32:22 +02:00
}
session.statement.RefTable = table
2022-07-16 11:43:41 +02:00
res, err := session.exec(realSQLWriter.String(), realSQLWriter.Args()...)
2020-07-19 19:32:22 +02:00
if err != nil {
return 0, err
}
2021-08-30 19:45:06 +02:00
if bean != nil {
// handle after delete processors
if session.isAutoCommit {
for _, closure := range session.afterClosures {
closure(bean)
}
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
processor.AfterDelete()
2020-07-19 19:32:22 +02:00
}
} else {
2021-08-30 19:45:06 +02:00
lenAfterClosures := len(session.afterClosures)
if lenAfterClosures > 0 && len(beans) > 0 {
if value, has := session.afterDeleteBeans[beans[0]]; has && value != nil {
*value = append(*value, session.afterClosures...)
} else {
afterClosures := make([]func(interface{}), lenAfterClosures)
copy(afterClosures, session.afterClosures)
session.afterDeleteBeans[bean] = &afterClosures
}
} else {
if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
session.afterDeleteBeans[bean] = nil
}
2020-07-19 19:32:22 +02:00
}
}
}
cleanupProcessorsClosures(&session.afterClosures)
// --
return res.RowsAffected()
}