Browse Source

1.add query interface
2.fix tests of query interface

xormplus 8 năm trước cách đây
mục cha
commit
0a4c79c508
9 tập tin đã thay đổi với 410 bổ sung296 xóa
  1. 7 0
      engine.go
  2. 0 8
      session.go
  3. 3 13
      session_exist.go
  4. 15 24
      session_find.go
  5. 15 21
      session_get.go
  6. 182 0
      session_query.go
  7. 112 0
      session_query_test.go
  8. 76 198
      session_raw.go
  9. 0 32
      session_raw_test.go

+ 7 - 0
engine.go

@@ -1393,6 +1393,13 @@ func (engine *Engine) QueryString(sqlStr string, args ...interface{}) ([]map[str
 	return session.QueryString(sqlStr, args...)
 	return session.QueryString(sqlStr, args...)
 }
 }
 
 
+// QueryInterface runs a raw sql and return records as []map[string]interface{}
+func (engine *Engine) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) {
+	session := engine.NewSession()
+	defer session.Close()
+	return session.QueryInterface(sqlStr, args...)
+}
+
 // Insert one or more records
 // Insert one or more records
 func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
 func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
 	session := engine.NewSession()
 	session := engine.NewSession()

+ 0 - 8
session.go

@@ -783,14 +783,6 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, f
 	return pk, nil
 	return pk, nil
 }
 }
 
 
-func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
-	for _, filter := range session.engine.dialect.Filters() {
-		*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable)
-	}
-
-	session.saveLastSQL(*sqlStr, paramStr...)
-}
-
 // saveLastSQL stores executed query information
 // saveLastSQL stores executed query information
 func (session *Session) saveLastSQL(sql string, args ...interface{}) {
 func (session *Session) saveLastSQL(sql string, args ...interface{}) {
 	session.lastSQL = sql
 	session.lastSQL = sql

+ 3 - 13
session_exist.go

@@ -10,12 +10,10 @@ import (
 	"reflect"
 	"reflect"
 
 
 	"github.com/go-xorm/builder"
 	"github.com/go-xorm/builder"
-	"github.com/xormplus/core"
 )
 )
 
 
 // Exist returns true if the record exist otherwise return false
 // Exist returns true if the record exist otherwise return false
 func (session *Session) Exist(bean ...interface{}) (bool, error) {
 func (session *Session) Exist(bean ...interface{}) (bool, error) {
-	defer session.resetStatement()
 	if session.isAutoClose {
 	if session.isAutoClose {
 		defer session.Close()
 		defer session.Close()
 	}
 	}
@@ -69,19 +67,11 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) {
 		args = session.statement.RawParams
 		args = session.statement.RawParams
 	}
 	}
 
 
-	session.queryPreprocess(&sqlStr, args...)
-
-	var rawRows *core.Rows
-	if session.isAutoCommit {
-		_, rawRows, err = session.innerQuery(sqlStr, args...)
-	} else {
-		rawRows, err = session.tx.Query(sqlStr, args...)
-	}
+	rows, err := session.queryRows(sqlStr, args...)
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
+	defer rows.Close()
 
 
-	defer rawRows.Close()
-
-	return rawRows.Next(), nil
+	return rows.Next(), nil
 }
 }

+ 15 - 24
session_find.go

@@ -23,11 +23,13 @@ const (
 // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
 // are conditions. beans could be []Struct, []*Struct, map[int64]Struct
 // map[int64]*Struct
 // map[int64]*Struct
 func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
 func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
-	defer session.resetStatement()
 	if session.isAutoClose {
 	if session.isAutoClose {
 		defer session.Close()
 		defer session.Close()
 	}
 	}
+	return session.find(rowsSlicePtr, condiBean...)
+}
 
 
+func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
 	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
 	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
 	if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
 	if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
 		return errors.New("needs a pointer to a slice or a map")
 		return errors.New("needs a pointer to a slice or a map")
@@ -181,21 +183,13 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
 }
 }
 
 
 func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
 func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
-	var rawRows *core.Rows
-	var err error
-
-	session.queryPreprocess(&sqlStr, args...)
-	if session.isAutoCommit {
-		_, rawRows, err = session.innerQuery(sqlStr, args...)
-	} else {
-		rawRows, err = session.tx.Query(sqlStr, args...)
-	}
+	rows, err := session.queryRows(sqlStr, args...)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	defer rawRows.Close()
+	defer rows.Close()
 
 
-	fields, err := rawRows.Columns()
+	fields, err := rows.Columns()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -269,20 +263,20 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		return session.rows2Beans(rawRows, fields, len(fields), tb, newElemFunc, containerValueSetFunc)
+		return session.rows2Beans(rows, fields, len(fields), tb, newElemFunc, containerValueSetFunc)
 	}
 	}
 
 
-	for rawRows.Next() {
+	for rows.Next() {
 		var newValue = newElemFunc(fields)
 		var newValue = newElemFunc(fields)
 		bean := newValue.Interface()
 		bean := newValue.Interface()
 
 
 		switch elemType.Kind() {
 		switch elemType.Kind() {
 		case reflect.Slice:
 		case reflect.Slice:
-			err = rawRows.ScanSlice(bean)
+			err = rows.ScanSlice(bean)
 		case reflect.Map:
 		case reflect.Map:
-			err = rawRows.ScanMap(bean)
+			err = rows.ScanMap(bean)
 		default:
 		default:
-			err = rawRows.Scan(bean)
+			err = rows.Scan(bean)
 		}
 		}
 
 
 		if err != nil {
 		if err != nil {
@@ -328,7 +322,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 	cacher := session.engine.getCacher2(table)
 	cacher := session.engine.getCacher2(table)
 	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
 	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
 	if err != nil {
 	if err != nil {
-		rows, err := session.DB().Query(newsql, args...)
+		rows, err := session.NoCache().queryRows(newsql, args...)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -400,9 +394,6 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 	}
 	}
 
 
 	if len(ides) > 0 {
 	if len(ides) > 0 {
-		newSession := session.engine.NewSession()
-		defer newSession.Close()
-
 		slices := reflect.New(reflect.SliceOf(t))
 		slices := reflect.New(reflect.SliceOf(t))
 		beans := slices.Interface()
 		beans := slices.Interface()
 
 
@@ -412,18 +403,18 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in
 				ff = append(ff, ie[0])
 				ff = append(ff, ie[0])
 			}
 			}
 
 
-			newSession.In("`"+table.PrimaryKeys[0]+"`", ff...)
+			session.In("`"+table.PrimaryKeys[0]+"`", ff...)
 		} else {
 		} else {
 			for _, ie := range ides {
 			for _, ie := range ides {
 				cond := builder.NewCond()
 				cond := builder.NewCond()
 				for i, name := range table.PrimaryKeys {
 				for i, name := range table.PrimaryKeys {
 					cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
 					cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
 				}
 				}
-				newSession.Or(cond)
+				session.Or(cond)
 			}
 			}
 		}
 		}
 
 
-		err = newSession.NoCache().Find(beans)
+		err = session.NoCache().find(beans)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 15 - 21
session_get.go

@@ -15,11 +15,13 @@ import (
 // Get retrieve one record from database, bean's non-empty fields
 // Get retrieve one record from database, bean's non-empty fields
 // will be as conditions
 // will be as conditions
 func (session *Session) Get(bean interface{}) (bool, error) {
 func (session *Session) Get(bean interface{}) (bool, error) {
-	defer session.resetStatement()
 	if session.isAutoClose {
 	if session.isAutoClose {
 		defer session.Close()
 		defer session.Close()
 	}
 	}
+	return session.get(bean)
+}
 
 
+func (session *Session) get(bean interface{}) (bool, error) {
 	beanValue := reflect.ValueOf(bean)
 	beanValue := reflect.ValueOf(bean)
 	if beanValue.Kind() != reflect.Ptr {
 	if beanValue.Kind() != reflect.Ptr {
 		return false, errors.New("needs a pointer to a value")
 		return false, errors.New("needs a pointer to a value")
@@ -65,30 +67,21 @@ func (session *Session) Get(bean interface{}) (bool, error) {
 }
 }
 
 
 func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
 func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
-	session.queryPreprocess(&sqlStr, args...)
-
-	var rawRows *core.Rows
-	var err error
-	if session.isAutoCommit {
-		_, rawRows, err = session.innerQuery(sqlStr, args...)
-	} else {
-		rawRows, err = session.tx.Query(sqlStr, args...)
-	}
+	rows, err := session.queryRows(sqlStr, args...)
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
+	defer rows.Close()
 
 
-	defer rawRows.Close()
-
-	if !rawRows.Next() {
+	if !rows.Next() {
 		return false, nil
 		return false, nil
 	}
 	}
 
 
 	switch beanKind {
 	switch beanKind {
 	case reflect.Struct:
 	case reflect.Struct:
-		fields, err := rawRows.Columns()
+		fields, err := rows.Columns()
 		if err != nil {
 		if err != nil {
-			// WARN: Alougth rawRows return true, but get fields failed
+			// WARN: Alougth rows return true, but get fields failed
 			return true, err
 			return true, err
 		}
 		}
 		dataStruct := rValue(bean)
 		dataStruct := rValue(bean)
@@ -96,19 +89,20 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlS
 			return false, err
 			return false, err
 		}
 		}
 
 
-		scanResults, err := session.row2Slice(rawRows, fields, len(fields), bean)
+		scanResults, err := session.row2Slice(rows, fields, len(fields), bean)
 		if err != nil {
 		if err != nil {
 			return false, err
 			return false, err
 		}
 		}
-		rawRows.Close()
+		// close it before covert data
+		rows.Close()
 
 
 		_, err = session.slice2Bean(scanResults, fields, len(fields), bean, &dataStruct, session.statement.RefTable)
 		_, err = session.slice2Bean(scanResults, fields, len(fields), bean, &dataStruct, session.statement.RefTable)
 	case reflect.Slice:
 	case reflect.Slice:
-		err = rawRows.ScanSlice(bean)
+		err = rows.ScanSlice(bean)
 	case reflect.Map:
 	case reflect.Map:
-		err = rawRows.ScanMap(bean)
+		err = rows.ScanMap(bean)
 	default:
 	default:
-		err = rawRows.Scan(bean)
+		err = rows.Scan(bean)
 	}
 	}
 
 
 	return true, err
 	return true, err
@@ -135,7 +129,7 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf
 	table := session.statement.RefTable
 	table := session.statement.RefTable
 	if err != nil {
 	if err != nil {
 		var res = make([]string, len(table.PrimaryKeys))
 		var res = make([]string, len(table.PrimaryKeys))
-		rows, err := session.DB().Query(newsql, args...)
+		rows, err := session.NoCache().queryRows(newsql, args...)
 		if err != nil {
 		if err != nil {
 			return false, err
 			return false, err
 		}
 		}

+ 182 - 0
session_query.go

@@ -0,0 +1,182 @@
+// Copyright 2017 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 (
+	"fmt"
+	"reflect"
+	"strconv"
+	"time"
+
+	"github.com/xormplus/core"
+)
+
+// Query runs a raw sql and return records as []map[string][]byte
+func (session *Session) query(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	return session.queryBytes(sqlStr, args...)
+}
+
+func reflect2value(rawValue *reflect.Value) (str string, err error) {
+	aa := reflect.TypeOf((*rawValue).Interface())
+	vv := reflect.ValueOf((*rawValue).Interface())
+	switch aa.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		str = strconv.FormatInt(vv.Int(), 10)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		str = strconv.FormatUint(vv.Uint(), 10)
+	case reflect.Float32, reflect.Float64:
+		str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
+	case reflect.String:
+		str = vv.String()
+	case reflect.Array, reflect.Slice:
+		switch aa.Elem().Kind() {
+		case reflect.Uint8:
+			data := rawValue.Interface().([]byte)
+			str = string(data)
+		default:
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	// time type
+	case reflect.Struct:
+		if aa.ConvertibleTo(core.TimeType) {
+			str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
+		} else {
+			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+		}
+	case reflect.Bool:
+		str = strconv.FormatBool(vv.Bool())
+	case reflect.Complex128, reflect.Complex64:
+		str = fmt.Sprintf("%v", vv.Complex())
+	/* TODO: unsupported types below
+	   case reflect.Map:
+	   case reflect.Ptr:
+	   case reflect.Uintptr:
+	   case reflect.UnsafePointer:
+	   case reflect.Chan, reflect.Func, reflect.Interface:
+	*/
+	default:
+		err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
+	}
+	return
+}
+
+func value2String(rawValue *reflect.Value) (data string, err error) {
+	data, err = reflect2value(rawValue)
+	if err != nil {
+		return
+	}
+	return
+}
+
+func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
+	result := make(map[string]string)
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
+		// if row is null then as empty string
+		if rawValue.Interface() == nil {
+			result[key] = ""
+			continue
+		}
+
+		if data, err := value2String(&rawValue); err == nil {
+			result[key] = data
+		} else {
+			return nil, err
+		}
+	}
+	return result, nil
+}
+
+func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2mapStr(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+// QueryString runs a raw sql and return records as []map[string]string
+func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2Strings(rows)
+}
+
+func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
+	resultsMap = make(map[string]interface{}, len(fields))
+	scanResultContainers := make([]interface{}, len(fields))
+	for i := 0; i < len(fields); i++ {
+		var scanResultContainer interface{}
+		scanResultContainers[i] = &scanResultContainer
+	}
+	if err := rows.Scan(scanResultContainers...); err != nil {
+		return nil, err
+	}
+
+	for ii, key := range fields {
+		resultsMap[key] = reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])).Interface()
+	}
+	return
+}
+
+func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
+	fields, err := rows.Columns()
+	if err != nil {
+		return nil, err
+	}
+	for rows.Next() {
+		result, err := row2mapInterface(rows, fields)
+		if err != nil {
+			return nil, err
+		}
+		resultsSlice = append(resultsSlice, result)
+	}
+
+	return resultsSlice, nil
+}
+
+// QueryInterface runs a raw sql and return records as []map[string]interface{}
+func (session *Session) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) {
+	if session.isAutoClose {
+		defer session.Close()
+	}
+
+	rows, err := session.queryRows(sqlStr, args...)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	return rows2Interfaces(rows)
+}

+ 112 - 0
session_query_test.go

@@ -0,0 +1,112 @@
+// Copyright 2017 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 (
+	"fmt"
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestQueryString(t *testing.T) {
+	assert.NoError(t, prepareEngine())
+
+	type GetVar struct {
+		Id      int64  `xorm:"autoincr pk"`
+		Msg     string `xorm:"varchar(255)"`
+		Age     int
+		Money   float32
+		Created time.Time `xorm:"created"`
+	}
+
+	assert.NoError(t, testEngine.Sync2(new(GetVar)))
+
+	var data = GetVar{
+		Msg:   "hi",
+		Age:   28,
+		Money: 1.5,
+	}
+	_, err := testEngine.InsertOne(data)
+	assert.NoError(t, err)
+
+	records, err := testEngine.QueryString("select * from get_var")
+	assert.NoError(t, err)
+	assert.Equal(t, 1, len(records))
+	assert.Equal(t, 5, len(records[0]))
+	assert.Equal(t, "1", records[0]["id"])
+	assert.Equal(t, "hi", records[0]["msg"])
+	assert.Equal(t, "28", records[0]["age"])
+	assert.Equal(t, "1.5", records[0]["money"])
+}
+
+func toString(i interface{}) string {
+	switch i.(type) {
+	case []byte:
+		return string(i.([]byte))
+	case string:
+		return i.(string)
+	}
+	return fmt.Sprintf("%v", i)
+}
+
+func toInt64(i interface{}) int64 {
+	switch i.(type) {
+	case []byte:
+		n, _ := strconv.ParseInt(string(i.([]byte)), 10, 64)
+		return n
+	case int:
+		return int64(i.(int))
+	case int64:
+		return i.(int64)
+	}
+	return 0
+}
+
+func toFloat64(i interface{}) float64 {
+	switch i.(type) {
+	case []byte:
+		n, _ := strconv.ParseFloat(string(i.([]byte)), 64)
+		return n
+	case float64:
+		return i.(float64)
+	case float32:
+		return float64(i.(float32))
+	}
+	return 0
+}
+
+func TestQueryInterface(t *testing.T) {
+	assert.NoError(t, prepareEngine())
+
+	type GetVarInterface struct {
+		Id      int64  `xorm:"autoincr pk"`
+		Msg     string `xorm:"varchar(255)"`
+		Age     int
+		Money   float32
+		Created time.Time `xorm:"created"`
+	}
+
+	assert.NoError(t, testEngine.Sync2(new(GetVarInterface)))
+
+	var data = GetVarInterface{
+		Msg:   "hi",
+		Age:   28,
+		Money: 1.5,
+	}
+	_, err := testEngine.InsertOne(data)
+	assert.NoError(t, err)
+
+	records, err := testEngine.QueryInterface("select * from get_var_interface")
+	assert.NoError(t, err)
+	assert.Equal(t, 1, len(records))
+	assert.Equal(t, 5, len(records[0]))
+	assert.EqualValues(t, 1, toInt64(records[0]["id"]))
+	assert.Equal(t, "hi", toString(records[0]["msg"]))
+	assert.EqualValues(t, 28, toInt64(records[0]["age"]))
+	assert.EqualValues(t, 1.5, toFloat64(records[0]["money"]))
+}

+ 76 - 198
session_raw.go

@@ -6,77 +6,77 @@ package xorm
 
 
 import (
 import (
 	"database/sql"
 	"database/sql"
-	"fmt"
 	"reflect"
 	"reflect"
-	"strconv"
 	"time"
 	"time"
 
 
 	"github.com/xormplus/core"
 	"github.com/xormplus/core"
 )
 )
 
 
-func (session *Session) query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) {
-	session.queryPreprocess(&sqlStr, paramStr...)
-
-	if session.isAutoCommit {
-		return session.innerQuery2(sqlStr, paramStr...)
+func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
+	for _, filter := range session.engine.dialect.Filters() {
+		*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable)
 	}
 	}
-	return session.txQuery(session.tx, sqlStr, paramStr...)
+
+	session.lastSQL = *sqlStr
+	session.lastSQLArgs = paramStr
 }
 }
 
 
-func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string][]byte, error) {
-	rows, err := tx.Query(sqlStr, params...)
-	if err != nil {
-		return nil, err
-	}
-	defer rows.Close()
+func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) {
+	defer session.resetStatement()
 
 
-	return rows2maps(rows)
-}
+	session.queryPreprocess(&sqlStr, args...)
 
 
-func (session *Session) innerQuery(sqlStr string, params ...interface{}) (*core.Stmt, *core.Rows, error) {
-	var callback func() (*core.Stmt, *core.Rows, error)
-	if session.prepareStmt {
-		callback = func() (*core.Stmt, *core.Rows, error) {
+	if session.engine.showSQL {
+		if session.engine.showExecTime {
+			b4ExecTime := time.Now()
+			defer func() {
+				execDuration := time.Since(b4ExecTime)
+				if len(args) > 0 {
+					session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
+				} else {
+					session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
+				}
+			}()
+		} else {
+			if len(args) > 0 {
+				session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
+			} else {
+				session.engine.logger.Infof("[SQL] %v", sqlStr)
+			}
+		}
+	}
+
+	if session.isAutoCommit {
+		if session.prepareStmt {
+			// don't clear stmt since session will cache them
 			stmt, err := session.doPrepare(sqlStr)
 			stmt, err := session.doPrepare(sqlStr)
 			if err != nil {
 			if err != nil {
-				return nil, nil, err
+				return nil, err
 			}
 			}
-			rows, err := stmt.Query(params...)
+
+			rows, err := stmt.Query(args...)
 			if err != nil {
 			if err != nil {
-				return nil, nil, err
+				return nil, err
 			}
 			}
-			return stmt, rows, nil
+			return rows, nil
 		}
 		}
-	} else {
-		callback = func() (*core.Stmt, *core.Rows, error) {
-			rows, err := session.DB().Query(sqlStr, params...)
-			if err != nil {
-				return nil, nil, err
-			}
-			return nil, rows, err
+
+		rows, err := session.DB().Query(sqlStr, args...)
+		if err != nil {
+			return nil, err
 		}
 		}
+		return rows, nil
 	}
 	}
-	stmt, rows, err := session.engine.logSQLQueryTime(sqlStr, params, callback)
-	if err != nil {
-		return nil, nil, err
-	}
-	return stmt, rows, nil
-}
 
 
-func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
-	fields, err := rows.Columns()
+	rows, err := session.tx.Query(sqlStr, args...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	for rows.Next() {
-		result, err := row2map(rows, fields)
-		if err != nil {
-			return nil, err
-		}
-		resultsSlice = append(resultsSlice, result)
-	}
+	return rows, nil
+}
 
 
-	return resultsSlice, nil
+func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
+	return core.NewRow(session.queryRows(sqlStr, args...))
 }
 }
 
 
 func value2Bytes(rawValue *reflect.Value) (data []byte, err error) {
 func value2Bytes(rawValue *reflect.Value) (data []byte, err error) {
@@ -104,7 +104,7 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er
 		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
 		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
 		//if row is null then ignore
 		//if row is null then ignore
 		if rawValue.Interface() == nil {
 		if rawValue.Interface() == nil {
-			//fmt.Println("ignore ...", key, rawValue)
+			result[key] = []byte{}
 			continue
 			continue
 		}
 		}
 
 
@@ -117,34 +117,13 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er
 	return result, nil
 	return result, nil
 }
 }
 
 
-func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map[string][]byte, error) {
-	_, rows, err := session.innerQuery(sqlStr, params...)
-	if rows != nil {
-		defer rows.Close()
-	}
-	if err != nil {
-		return nil, err
-	}
-	return rows2maps(rows)
-}
-
-// Exec a raw sql and return records as []map[string][]byte
-func (session *Session) query1(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) {
-	defer session.resetStatement()
-	if session.isAutoClose {
-		defer session.Close()
-	}
-
-	return session.query(sqlStr, paramStr...)
-}
-
-func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
+func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
 	fields, err := rows.Columns()
 	fields, err := rows.Columns()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	for rows.Next() {
 	for rows.Next() {
-		result, err := row2mapStr(rows, fields)
+		result, err := row2map(rows, fields)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -154,122 +133,45 @@ func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error)
 	return resultsSlice, nil
 	return resultsSlice, nil
 }
 }
 
 
-func reflect2value(rawValue *reflect.Value) (str string, err error) {
-	aa := reflect.TypeOf((*rawValue).Interface())
-	vv := reflect.ValueOf((*rawValue).Interface())
-	switch aa.Kind() {
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		str = strconv.FormatInt(vv.Int(), 10)
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		str = strconv.FormatUint(vv.Uint(), 10)
-	case reflect.Float32, reflect.Float64:
-		str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
-	case reflect.String:
-		str = vv.String()
-	case reflect.Array, reflect.Slice:
-		switch aa.Elem().Kind() {
-		case reflect.Uint8:
-			data := rawValue.Interface().([]byte)
-			str = string(data)
-		default:
-			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
-		}
-	// time type
-	case reflect.Struct:
-		if aa.ConvertibleTo(core.TimeType) {
-			str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
-		} else {
-			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
-		}
-	case reflect.Bool:
-		str = strconv.FormatBool(vv.Bool())
-	case reflect.Complex128, reflect.Complex64:
-		str = fmt.Sprintf("%v", vv.Complex())
-	/* TODO: unsupported types below
-	   case reflect.Map:
-	   case reflect.Ptr:
-	   case reflect.Uintptr:
-	   case reflect.UnsafePointer:
-	   case reflect.Chan, reflect.Func, reflect.Interface:
-	*/
-	default:
-		err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
-	}
-	return
-}
-
-func value2String(rawValue *reflect.Value) (data string, err error) {
-	data, err = reflect2value(rawValue)
-	if err != nil {
-		return
-	}
-	return
-}
-
-func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
-	result := make(map[string]string)
-	scanResultContainers := make([]interface{}, len(fields))
-	for i := 0; i < len(fields); i++ {
-		var scanResultContainer interface{}
-		scanResultContainers[i] = &scanResultContainer
-	}
-	if err := rows.Scan(scanResultContainers...); err != nil {
-		return nil, err
-	}
-
-	for ii, key := range fields {
-		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
-		// if row is null then as empty string
-		if rawValue.Interface() == nil {
-			result[key] = ""
-			continue
-		}
-
-		if data, err := value2String(&rawValue); err == nil {
-			result[key] = data
-		} else {
-			return nil, err
-		}
-	}
-	return result, nil
-}
-
-func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string]string, error) {
-	rows, err := tx.Query(sqlStr, params...)
+func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
+	rows, err := session.queryRows(sqlStr, args...)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	defer rows.Close()
 	defer rows.Close()
 
 
-	return rows2Strings(rows)
-}
-
-func query2(db *core.DB, sqlStr string, params ...interface{}) ([]map[string]string, error) {
-	rows, err := db.Query(sqlStr, params...)
-	if err != nil {
-		return nil, err
-	}
-	defer rows.Close()
-	return rows2Strings(rows)
+	return rows2maps(rows)
 }
 }
 
 
-// QueryString runs a raw sql and return records as []map[string]string
-func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) {
+func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
 	defer session.resetStatement()
 	defer session.resetStatement()
-	if session.isAutoClose {
-		defer session.Close()
-	}
 
 
 	session.queryPreprocess(&sqlStr, args...)
 	session.queryPreprocess(&sqlStr, args...)
 
 
-	if session.isAutoCommit {
-		return query2(session.DB(), sqlStr, args...)
+	if session.engine.showSQL {
+		if session.engine.showExecTime {
+			b4ExecTime := time.Now()
+			defer func() {
+				execDuration := time.Since(b4ExecTime)
+				if len(args) > 0 {
+					session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
+				} else {
+					session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
+				}
+			}()
+		} else {
+			if len(args) > 0 {
+				session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
+			} else {
+				session.engine.logger.Infof("[SQL] %v", sqlStr)
+			}
+		}
+	}
+
+	if !session.isAutoCommit {
+		return session.tx.Exec(sqlStr, args...)
 	}
 	}
-	return txQuery2(session.tx, sqlStr, args...)
-}
 
 
-// Execute sql
-func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Result, error) {
 	if session.prepareStmt {
 	if session.prepareStmt {
 		stmt, err := session.doPrepare(sqlStr)
 		stmt, err := session.doPrepare(sqlStr)
 		if err != nil {
 		if err != nil {
@@ -286,32 +188,8 @@ func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Resul
 	return session.DB().Exec(sqlStr, args...)
 	return session.DB().Exec(sqlStr, args...)
 }
 }
 
 
-func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
-	for _, filter := range session.engine.dialect.Filters() {
-		// TODO: for table name, it's no need to RefTable
-		sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
-	}
-
-	session.saveLastSQL(sqlStr, args...)
-
-	return session.engine.logSQLExecutionTime(sqlStr, args, func() (sql.Result, error) {
-		if session.isAutoCommit {
-			// FIXME: oci8 can not auto commit (github.com/mattn/go-oci8)
-			if session.engine.dialect.DBType() == core.ORACLE {
-				session.Begin()
-				r, err := session.tx.Exec(sqlStr, args...)
-				session.Commit()
-				return r, err
-			}
-			return session.innerExec(sqlStr, args...)
-		}
-		return session.tx.Exec(sqlStr, args...)
-	})
-}
-
 // Exec raw sql
 // Exec raw sql
 func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
 func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
-	defer session.resetStatement()
 	if session.isAutoClose {
 	if session.isAutoClose {
 		defer session.Close()
 		defer session.Close()
 	}
 	}

+ 0 - 32
session_raw_test.go

@@ -7,42 +7,10 @@ package xorm
 import (
 import (
 	"strconv"
 	"strconv"
 	"testing"
 	"testing"
-	"time"
 
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 )
 )
 
 
-func TestQueryString(t *testing.T) {
-	assert.NoError(t, prepareEngine())
-
-	type GetVar struct {
-		Id      int64  `xorm:"autoincr pk"`
-		Msg     string `xorm:"varchar(255)"`
-		Age     int
-		Money   float32
-		Created time.Time `xorm:"created"`
-	}
-
-	assert.NoError(t, testEngine.Sync2(new(GetVar)))
-
-	var data = GetVar{
-		Msg:   "hi",
-		Age:   28,
-		Money: 1.5,
-	}
-	_, err := testEngine.InsertOne(data)
-	assert.NoError(t, err)
-
-	records, err := testEngine.QueryString("select * from get_var")
-	assert.NoError(t, err)
-	assert.Equal(t, 1, len(records))
-	assert.Equal(t, 5, len(records[0]))
-	assert.Equal(t, "1", records[0]["id"])
-	assert.Equal(t, "hi", records[0]["msg"])
-	assert.Equal(t, "28", records[0]["age"])
-	assert.Equal(t, "1.5", records[0]["money"])
-}
-
 func TestQuery(t *testing.T) {
 func TestQuery(t *testing.T) {
 	assert.NoError(t, prepareEngine())
 	assert.NoError(t, prepareEngine())