From dd633142579c475e0297add705f71a46e97822de Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 6 Mar 2020 14:03:28 +0800 Subject: [PATCH] revert change for delete --- internal/statements/delete.go | 133 ---------------------------------- session_delete.go | 131 ++++++++++++++++++++++++++++----- 2 files changed, 114 insertions(+), 150 deletions(-) delete mode 100644 internal/statements/delete.go diff --git a/internal/statements/delete.go b/internal/statements/delete.go deleted file mode 100644 index 2cb91f2a..00000000 --- a/internal/statements/delete.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2020 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 statements - -import ( - "errors" - "fmt" - "time" - - "xorm.io/xorm/dialects" - "xorm.io/xorm/schemas" -) - -var ( - // ErrNeedDeletedCond delete needs less one condition error - ErrNeedDeletedCond = errors.New("Delete action needs at least one condition") - - // ErrNotImplemented not implemented - ErrNotImplemented = errors.New("Not implemented") -) - -// GenDeleteSQL generated delete SQL according conditions -func (statement *Statement) GenDeleteSQL(bean interface{}) (string, string, []interface{}, *time.Time, error) { - condSQL, condArgs, err := statement.GenConds(bean) - if err != nil { - return "", "", nil, nil, err - } - pLimitN := statement.LimitN - if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) { - return "", "", nil, nil, ErrNeedDeletedCond - } - - var tableNameNoQuote = statement.TableName() - var tableName = statement.quote(tableNameNoQuote) - var table = 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(statement.OrderStr) > 0 { - orderSQL += fmt.Sprintf(" ORDER BY %s", statement.OrderStr) - } - if pLimitN != nil && *pLimitN > 0 { - limitNValue := *pLimitN - orderSQL += fmt.Sprintf(" LIMIT %d", limitNValue) - } - - if len(orderSQL) > 0 { - switch statement.dialect.DBType() { - case schemas.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 schemas.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 schemas.MSSQL: - return "", "", nil, nil, ErrNotImplemented - default: - deleteSQL += orderSQL - } - } - - var realSQL string - if statement.GetUnscoped() || table.DeletedColumn() == nil { // tag "deleted" is disabled - return deleteSQL, deleteSQL, condArgs, nil, nil - } - - deletedColumn := table.DeletedColumn() - realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v", - statement.quote(statement.TableName()), - statement.quote(deletedColumn.Name), - condSQL) - - if len(orderSQL) > 0 { - switch statement.dialect.DBType() { - case schemas.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 schemas.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 schemas.MSSQL: - return "", "", nil, nil, ErrNotImplemented - default: - realSQL += orderSQL - } - } - - // !oinume! Insert nowTime to the head of statement.Params - condArgs = append(condArgs, "") - paramsLen := len(condArgs) - copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1]) - - now := ColumnNow(deletedColumn, statement.defaultTimeZone) - val := dialects.FormatTime(statement.dialect, deletedColumn.SQLType.Name, now) - condArgs[0] = val - - return realSQL, deleteSQL, condArgs, &now, nil -} - -// ColumnNow returns the current time for a column -func ColumnNow(col *schemas.Column, defaultTimeZone *time.Location) time.Time { - t := time.Now() - tz := defaultTimeZone - if !col.DisableTimeZone && col.TimeZone != nil { - tz = col.TimeZone - } - return t.In(tz) -} diff --git a/session_delete.go b/session_delete.go index 16434bac..eb5e2aea 100644 --- a/session_delete.go +++ b/session_delete.go @@ -6,13 +6,21 @@ package xorm import ( "errors" + "fmt" "strconv" - "time" "xorm.io/xorm/caches" "xorm.io/xorm/schemas" ) +var ( + // ErrNeedDeletedCond delete needs less one condition error + ErrNeedDeletedCond = errors.New("Delete action needs at least one condition") + + // ErrNotImplemented not implemented + ErrNotImplemented = errors.New("Not implemented") +) + func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error { if table == nil || session.tx != nil { @@ -98,30 +106,119 @@ func (session *Session) Delete(bean interface{}) (int64, error) { processor.BeforeDelete() } - realSQL, deleteSQL, condArgs, now, err := session.statement.GenDeleteSQL(bean) + condSQL, condArgs, err := session.statement.GenConds(bean) if err != nil { return 0, err } - - argsForCache := make([]interface{}, 0, len(condArgs)*2) - copy(argsForCache, condArgs) - argsForCache = append(condArgs, argsForCache...) - - if !session.statement.GetUnscoped() && session.statement.RefTable.DeletedColumn() != nil { - deletedColumn := session.statement.RefTable.DeletedColumn() - - session.afterClosures = append(session.afterClosures, func(col *schemas.Column, t time.Time) func(interface{}) { - return func(bean interface{}) { - setColumnTime(bean, col, t) - } - }(deletedColumn, now.In(session.engine.TZLocation))) + pLimitN := session.statement.LimitN + if len(condSQL) == 0 && (pLimitN == nil || *pLimitN == 0) { + return 0, ErrNeedDeletedCond } var tableNameNoQuote = session.statement.TableName() - if cacher := session.engine.GetCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache { - session.cacheDelete(session.statement.RefTable, tableNameNoQuote, deleteSQL, argsForCache...) + 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 schemas.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 schemas.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 schemas.MSSQL: + return 0, ErrNotImplemented + default: + deleteSQL += orderSQL + } + } + + var realSQL string + argsForCache := make([]interface{}, 0, len(condArgs)*2) + if session.statement.GetUnscoped() || 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 caches. + 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 schemas.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 schemas.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 schemas.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