优化func (session *Session) slice2Bean方法中的strings.ToLower(对应issue:https://gitea.com/xorm/xorm/issues/2243)

This commit is contained in:
洪坤安 2023-04-03 02:28:35 +08:00
parent 84ff9cba03
commit b9ee143cc2
4 changed files with 53 additions and 18 deletions

View File

@ -129,7 +129,9 @@ func (rows *Rows) Scan(beans ...interface{}) error {
return err return err
} }
if err := rows.session.scan(rows.rows, rows.session.statement.RefTable, beanKind, beans, types, fields); err != nil { allColumn := ParseQueryRows(fields, types)
if err := rows.session.scan(rows.rows, rows.session.statement.RefTable, beanKind, beans, allColumn, types, fields); err != nil {
return err return err
} }

View File

@ -16,8 +16,6 @@ import (
"io" "io"
"reflect" "reflect"
"strconv" "strconv"
"strings"
"xorm.io/xorm/contexts" "xorm.io/xorm/contexts"
"xorm.io/xorm/convert" "xorm.io/xorm/convert"
"xorm.io/xorm/core" "xorm.io/xorm/core"
@ -418,7 +416,7 @@ func getField(dataStruct *reflect.Value, table *schemas.Table, colName string, i
// Cell cell is a result of one column field // Cell cell is a result of one column field
type Cell *interface{} type Cell *interface{}
func (session *Session) rows2Beans(rows *core.Rows, fields []string, types []*sql.ColumnType, func (session *Session) rows2Beans(rows *core.Rows, allColumn *AllColumn, fields []string, types []*sql.ColumnType,
table *schemas.Table, newElemFunc func([]string) reflect.Value, table *schemas.Table, newElemFunc func([]string) reflect.Value,
sliceValueSetFunc func(*reflect.Value, schemas.PK) error, sliceValueSetFunc func(*reflect.Value, schemas.PK) error,
) error { ) error {
@ -428,11 +426,11 @@ func (session *Session) rows2Beans(rows *core.Rows, fields []string, types []*sq
dataStruct := newValue.Elem() dataStruct := newValue.Elem()
// handle beforeClosures // handle beforeClosures
scanResults, err := session.row2Slice(rows, fields, types, bean) scanResults, err := session.row2Slice(rows, allColumn, fields, types, bean)
if err != nil { if err != nil {
return err return err
} }
pk, err := session.slice2Bean(scanResults, fields, bean, &dataStruct, table) pk, err := session.slice2Bean(scanResults, allColumn, fields, bean, &dataStruct, table)
if err != nil { if err != nil {
return err return err
} }
@ -447,7 +445,7 @@ func (session *Session) rows2Beans(rows *core.Rows, fields []string, types []*sq
return rows.Err() return rows.Err()
} }
func (session *Session) row2Slice(rows *core.Rows, fields []string, types []*sql.ColumnType, bean interface{}) ([]interface{}, error) { func (session *Session) row2Slice(rows *core.Rows, allColumn *AllColumn, fields []string, types []*sql.ColumnType, bean interface{}) ([]interface{}, error) {
for _, closure := range session.beforeClosures { for _, closure := range session.beforeClosures {
closure(bean) closure(bean)
} }
@ -705,7 +703,7 @@ func (session *Session) convertBeanField(col *schemas.Column, fieldValue *reflec
return convert.AssignValue(fieldValue.Addr(), scanResult) return convert.AssignValue(fieldValue.Addr(), scanResult)
} }
func (session *Session) slice2Bean(scanResults []interface{}, fields []string, bean interface{}, dataStruct *reflect.Value, table *schemas.Table) (schemas.PK, error) { func (session *Session) slice2Bean(scanResults []interface{}, allColum *AllColumn, fields []string, bean interface{}, dataStruct *reflect.Value, table *schemas.Table) (schemas.PK, error) {
defer func() { defer func() {
executeAfterSet(bean, fields, scanResults) executeAfterSet(bean, fields, scanResults)
}() }()
@ -714,19 +712,18 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, b
tempMap := make(map[string]int) tempMap := make(map[string]int)
var pk schemas.PK var pk schemas.PK
for i, colName := range fields { for i, field := range allColum.Fields {
var idx int var idx int
lKey := strings.ToLower(colName)
var ok bool var ok bool
if idx, ok = tempMap[lKey]; !ok { if idx, ok = tempMap[field.LowerFieldName]; !ok {
idx = 0 idx = 0
} else { } else {
idx++ idx++
} }
tempMap[lKey] = idx tempMap[field.LowerFieldName] = idx
col, fieldValue, err := getField(dataStruct, table, colName, idx) col, fieldValue, err := getField(dataStruct, table, field.FieldName, idx)
if _, ok := err.(ErrFieldIsNotExist); ok { if _, ok := err.(ErrFieldIsNotExist); ok {
continue continue
} else if err != nil { } else if err != nil {

View File

@ -5,8 +5,10 @@
package xorm package xorm
import ( import (
"database/sql"
"errors" "errors"
"reflect" "reflect"
"strings"
"xorm.io/builder" "xorm.io/builder"
"xorm.io/xorm/caches" "xorm.io/xorm/caches"
@ -161,6 +163,36 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
return session.noCacheFind(table, sliceValue, sqlStr, args...) return session.noCacheFind(table, sliceValue, sqlStr, args...)
} }
type QueryedField struct {
FieldName string
LowerFieldName string
ColumnType *sql.ColumnType
}
type AllColumn struct {
Fields []*QueryedField
FieldNames []string
Types []*sql.ColumnType
}
func ParseQueryRows(fieldNames []string, types []*sql.ColumnType) *AllColumn {
var allColumn AllColumn
fields := make([]*QueryedField, 0, len(fieldNames))
for i, fieldName := range fieldNames {
field := &QueryedField{
FieldName: fieldName,
LowerFieldName: strings.ToLower(fieldName),
ColumnType: types[i],
}
fields = append(fields, field)
}
allColumn.Fields = fields
return &allColumn
}
func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error { func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
elemType := containerValue.Type().Elem() elemType := containerValue.Type().Elem()
var isPointer bool var isPointer bool
@ -188,6 +220,8 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect
return err return err
} }
allColumn := ParseQueryRows(fields, types)
newElemFunc := func(fields []string) reflect.Value { newElemFunc := func(fields []string) reflect.Value {
return utils.New(elemType, len(fields), len(fields)) return utils.New(elemType, len(fields), len(fields))
} }
@ -238,7 +272,7 @@ func (session *Session) noCacheFind(table *schemas.Table, containerValue reflect
if err != nil { if err != nil {
return err return err
} }
err = session.rows2Beans(rows, fields, types, tb, newElemFunc, containerValueSetFunc) err = session.rows2Beans(rows, allColumn, fields, types, tb, newElemFunc, containerValueSetFunc)
rows.Close() rows.Close()
if err != nil { if err != nil {
return err return err

View File

@ -164,7 +164,9 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *schemas.Table,
return true, err return true, err
} }
if err := session.scan(rows, table, beanKind, beans, types, fields); err != nil { allColumn := ParseQueryRows(fields, types)
if err := session.scan(rows, table, beanKind, beans, allColumn, types, fields); err != nil {
return true, err return true, err
} }
rows.Close() rows.Close()
@ -172,7 +174,7 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *schemas.Table,
return true, session.executeProcessors() return true, session.executeProcessors()
} }
func (session *Session) scan(rows *core.Rows, table *schemas.Table, firstBeanKind reflect.Kind, beans []interface{}, types []*sql.ColumnType, fields []string) error { func (session *Session) scan(rows *core.Rows, table *schemas.Table, firstBeanKind reflect.Kind, beans []interface{}, allColumn *AllColumn, types []*sql.ColumnType, fields []string) error {
if len(beans) == 1 { if len(beans) == 1 {
bean := beans[0] bean := beans[0]
switch firstBeanKind { switch firstBeanKind {
@ -180,13 +182,13 @@ func (session *Session) scan(rows *core.Rows, table *schemas.Table, firstBeanKin
if !isScannableStruct(bean, len(types)) { if !isScannableStruct(bean, len(types)) {
break break
} }
scanResults, err := session.row2Slice(rows, fields, types, bean) scanResults, err := session.row2Slice(rows, allColumn, fields, types, bean)
if err != nil { if err != nil {
return err return err
} }
dataStruct := utils.ReflectValue(bean) dataStruct := utils.ReflectValue(bean)
_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table) _, err = session.slice2Bean(scanResults, allColumn, fields, bean, &dataStruct, table)
return err return err
case reflect.Slice: case reflect.Slice:
return session.getSlice(rows, types, fields, bean) return session.getSlice(rows, types, fields, bean)