Lunny Xiao
6dfe337869
fix test fix nil pointer fix statement.Limit(0) will update or delete all data fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: xorm/xorm#1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: xorm/xorm#1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: xorm/xorm#1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi <guillep2k@noreply.gitea.io> Reviewed-on: xorm/xorm#941 fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: xorm/xorm#1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: xorm/xorm#1448 Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: xorm/xorm#1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: xorm/xorm#1505 SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: xorm/xorm#1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Improve ci tests (#1477) Rewrite Engine.QuoteTo() to accept multi-part identifiers (#1476) Support local sql log (#1338) Fix go mod and update version (#1460) Move github.com/go-xorm/xorm to xorm.io/xorm (#1459) add support custom type Nullfloat64 (#1450) fix bug when query map condtion with no quote (#1449) Don't warn when bool column default is 1 but not true (#1447) * don't warn when bool column default is 1 but not true * fix default case sensitive Fix sync2 with custom table name (#1445) * fix sync2 with custom table name * fix bug on postgres * fix bug on postgres fix bug when update with setexpr (#1446) add tidb tests on drone ci (#1444) improve sync2 (#1443) Fix wrong dbmetas (#1442) * add tests for db metas * add more tests * fix bug on mssql Fix default value parse bugs (#1437) * fix default value * fix default value tags * fix postgres default * fix default on postgres * fix default on postgres * fix mssql default fix arg conversion (#1441) * fix arg conversion * fix bugs * fix bug on postgres * use traditional positional parameters on insert into select * remove unnecessary tests upgrade core (#1440) add tests (#1439) add go1.13 tests on drone (#1416) Fix bug on insert where (#1436) * fix bug on insert where * fix bug * fix lint fix bug when insert multiple slices with customize table name (#1433) * fix bug when insert multiple slices with customize table name * fix tests on mssql * fix tests fix insert where with bool bug on mssql (#1432) fix setexpr missing big quotes (#1431) * fix setexpr missing big quotes * fix tests * fix tests Add support subquery on SetExpr (#1428) * add support subquery on SetExpr * fix tests fix go mod (#1427) fix tests (#1429) Use strings.Builder instead of builder.StringBuilder (#1417) * use strings.Builder instead of builder.StringBuilder * fix dependency * fix dependency Remove unuse get cols code (#1413) Add mssql ci test (#1410) * add mssql ci test * fix drone test Add insert select where support (#1401) Use drone new format (#1388) * use drone new format fix get customize type bug (#1382) fix bugs (#1375) update drone (#1374) Add tests for get var (#1305) * add test for SQL get * fix tests fix error when get null var (#890) * fix error when get null var * add support get for null var * fix bug Remove quotestr totally (#1366) * remove QuoteStr() totally * update xorm.core -> v0.7.0 * update dialect Quote remove QuoteStr() usage in dialects (#1364) document of FindAndCount() (#1365) remove QuoteStr() usage (#1360) Co-authored-by: yifhao <yifhao@tencent.com> Co-authored-by: yifhao <1124210681@qq.com> Co-authored-by: Guillermo Prandi <guillep2k@noreply.gitea.io> Co-authored-by: Guillermo Prandi <guillep2k@noreply@gitea.io> Co-authored-by: yudppp <yu.d.ppp@gmail.com> Co-authored-by: BetaCat <outman99@hotmail.com> Reviewed-on: xorm/xorm#1119
247 lines
6.7 KiB
Go
247 lines
6.7 KiB
Go
// 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"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"xorm.io/core"
|
|
)
|
|
|
|
func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
|
|
if table == nil ||
|
|
session.tx != nil {
|
|
return ErrCacheFailed
|
|
}
|
|
|
|
for _, filter := range session.engine.dialect.Filters() {
|
|
sqlStr = filter.Do(sqlStr, session.engine.dialect, table)
|
|
}
|
|
|
|
newsql := session.statement.convertIDSQL(sqlStr)
|
|
if newsql == "" {
|
|
return ErrCacheFailed
|
|
}
|
|
|
|
cacher := session.engine.getCacher(tableName)
|
|
pkColumns := table.PKColumns()
|
|
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
|
|
if err != nil {
|
|
resultsSlice, err := session.queryBytes(newsql, args...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ids = make([]core.PK, 0)
|
|
if len(resultsSlice) > 0 {
|
|
for _, data := range resultsSlice {
|
|
var id int64
|
|
var pk core.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() {
|
|
pk = append(pk, string(v))
|
|
} else if col.SQLType.IsNumeric() {
|
|
id, err = strconv.ParseInt(string(v), 10, 64)
|
|
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.Debug("[cacheDelete] delete cache obj:", tableName, id)
|
|
sid, err := id.ToString()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cacher.DelBean(tableName, sid)
|
|
}
|
|
session.engine.logger.Debug("[cacheDelete] clear cache table:", tableName)
|
|
cacher.ClearIds(tableName)
|
|
return nil
|
|
}
|
|
|
|
// Delete records, bean's non-empty fields are conditions
|
|
func (session *Session) Delete(bean interface{}) (int64, error) {
|
|
if session.isAutoClose {
|
|
defer session.Close()
|
|
}
|
|
|
|
if session.statement.lastError != nil {
|
|
return 0, session.statement.lastError
|
|
}
|
|
|
|
if err := session.statement.setRefBean(bean); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// handle before delete processors
|
|
for _, closure := range session.beforeClosures {
|
|
closure(bean)
|
|
}
|
|
cleanupProcessorsClosures(&session.beforeClosures)
|
|
|
|
if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
|
|
processor.BeforeDelete()
|
|
}
|
|
|
|
condSQL, condArgs, err := session.statement.genConds(bean)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
pLimitN := session.statement.LimitN
|
|
if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) {
|
|
return 0, ErrNeedDeletedCond
|
|
}
|
|
|
|
var tableNameNoQuote = session.statement.TableName()
|
|
var tableName = session.engine.Quote(tableNameNoQuote)
|
|
var table = session.statement.RefTable
|
|
var deleteSQL string
|
|
if len(condSQL) > 0 {
|
|
deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
|
|
} else {
|
|
deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
|
|
}
|
|
|
|
var orderSQL string
|
|
if len(session.statement.OrderStr) > 0 {
|
|
orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr)
|
|
}
|
|
if pLimitN != nil && *pLimitN > 0 {
|
|
limitNValue := *pLimitN
|
|
orderSQL += fmt.Sprintf(" LIMIT %d", limitNValue)
|
|
}
|
|
|
|
if len(orderSQL) > 0 {
|
|
switch session.engine.dialect.DBType() {
|
|
case core.POSTGRES:
|
|
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
|
|
if len(condSQL) > 0 {
|
|
deleteSQL += " AND " + inSQL
|
|
} else {
|
|
deleteSQL += " WHERE " + inSQL
|
|
}
|
|
case core.SQLITE:
|
|
inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
|
|
if len(condSQL) > 0 {
|
|
deleteSQL += " AND " + inSQL
|
|
} else {
|
|
deleteSQL += " WHERE " + inSQL
|
|
}
|
|
// TODO: how to handle delete limit on mssql?
|
|
case core.MSSQL:
|
|
return 0, ErrNotImplemented
|
|
default:
|
|
deleteSQL += orderSQL
|
|
}
|
|
}
|
|
|
|
var realSQL string
|
|
argsForCache := make([]interface{}, 0, len(condArgs)*2)
|
|
if session.statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
|
|
realSQL = deleteSQL
|
|
copy(argsForCache, condArgs)
|
|
argsForCache = append(condArgs, argsForCache...)
|
|
} else {
|
|
// !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache.
|
|
copy(argsForCache, condArgs)
|
|
argsForCache = append(condArgs, argsForCache...)
|
|
|
|
deletedColumn := table.DeletedColumn()
|
|
realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
|
|
session.engine.Quote(session.statement.TableName()),
|
|
session.engine.Quote(deletedColumn.Name),
|
|
condSQL)
|
|
|
|
if len(orderSQL) > 0 {
|
|
switch session.engine.dialect.DBType() {
|
|
case core.POSTGRES:
|
|
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
|
|
if len(condSQL) > 0 {
|
|
realSQL += " AND " + inSQL
|
|
} else {
|
|
realSQL += " WHERE " + inSQL
|
|
}
|
|
case core.SQLITE:
|
|
inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
|
|
if len(condSQL) > 0 {
|
|
realSQL += " AND " + inSQL
|
|
} else {
|
|
realSQL += " WHERE " + inSQL
|
|
}
|
|
// TODO: how to handle delete limit on mssql?
|
|
case core.MSSQL:
|
|
return 0, ErrNotImplemented
|
|
default:
|
|
realSQL += orderSQL
|
|
}
|
|
}
|
|
|
|
// !oinume! Insert nowTime to the head of session.statement.Params
|
|
condArgs = append(condArgs, "")
|
|
paramsLen := len(condArgs)
|
|
copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
|
|
|
|
val, t := session.engine.nowTime(deletedColumn)
|
|
condArgs[0] = val
|
|
|
|
var colName = deletedColumn.Name
|
|
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
|
|
col := table.GetColumn(colName)
|
|
setColumnTime(bean, col, t)
|
|
})
|
|
}
|
|
|
|
if cacher := session.engine.getCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache {
|
|
session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
|
|
}
|
|
|
|
session.statement.RefTable = table
|
|
res, err := session.exec(realSQL, condArgs...)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// handle after delete processors
|
|
if session.isAutoCommit {
|
|
for _, closure := range session.afterClosures {
|
|
closure(bean)
|
|
}
|
|
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
|
|
processor.AfterDelete()
|
|
}
|
|
} else {
|
|
lenAfterClosures := len(session.afterClosures)
|
|
if lenAfterClosures > 0 {
|
|
if value, has := session.afterDeleteBeans[bean]; 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
|
|
}
|
|
}
|
|
}
|
|
cleanupProcessorsClosures(&session.afterClosures)
|
|
// --
|
|
|
|
return res.RowsAffected()
|
|
}
|