package restful

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"../../pkg/setting"
	"github.com/patrickmn/go-cache"
	"github.com/tealeg/xlsx"
	"github.com/xormplus/xorm"
	"math"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

var (
	Engine       *xorm.Engine
	Apisql_cache *cache.Cache
)

func SQLT() *xorm.Session {
	tx := Engine.NewSession()
	return tx
}

// SQLInit 初始化数据库操作句柄,这里要提供:
// driverName string: 数据库类型,例如mysql、sqlite等,参考github.com/go-sql-driver/mysql官方介绍
// dataSourceName string: 数据库地址,参考github.com/go-sql-driver/mysql官方介绍
// MaxOpenConns int: 最大缓存连接数,这个数值包含了MaxIdleConns
// MaxIdleConns int:预备的最大空闲连接数
func SQLInit(driverName, dataSourceName string, maxOpenConns, maxIdleConns int, showlog bool) error {
	if Engine == nil {
		var err error
		if Engine, err = xorm.NewEngine(driverName, dataSourceName); err != nil {
			return err
		}
		if showlog {
			Engine.ShowSQL(true)
		}
		Engine.SetMaxIdleConns(maxIdleConns)
		Engine.SetMaxOpenConns(maxOpenConns)

	}
	if Apisql_cache == nil {
		Apisql_cache = cache.New(600*time.Second, 10*time.Second)
		SetCacheSql()
	}
	return nil
}

func SetCacheSql() {
	valuesMap, err := Engine.SQL("SELECT sqlname, CONCAT(sqlstr,'|',IFNULL(params,'')) AS sqlstr FROM apisql WHERE ENABLE>0 ").QueryString()
	if err == nil && len(valuesMap) > 0 {
		for _, v := range valuesMap {
			Apisql_cache.Set(v["sqlname"], v["sqlstr"], cache.DefaultExpiration)
		}
	}
}
func sqlCheckParam(param string) error {
	/*if strings.Contains(param, "where") {
		return errors.New("can not have where")
	}

	if strings.Contains(param, "and") {
		return errors.New("can not have and")
	}

	if strings.Contains(param, "or") {
		return errors.New("can not have or")
	}

	if strings.Contains(param, "=") {
		return errors.New("can not have =")
	}*/

	if strings.Contains(param, ";") {
		return errors.New("can not have ;")
	}

	return nil
}

func GetSqlByName(name string, tx *xorm.Session) (string, string) {
	sqls := ""
	param := ""
	if sql, ok := Apisql_cache.Get(name); ok {
		tempstrb := strings.IndexAny(sql.(string), "|")
		sqls = sql.(string)[0:tempstrb]
		param = sql.(string)[tempstrb+1:]
	} else {
		valuesMap, err := tx.SQL("SELECT sqlstr, params FROM apisql WHERE sqlname = ? AND ENABLE>0 ", name).QueryString()

		if err == nil && len(valuesMap) > 0 {
			sqls = valuesMap[0]["sqlstr"]
			param = valuesMap[0]["params"]
			Apisql_cache.Set(name, (sqls + "|" + param), cache.DefaultExpiration)
		}
	}
	if setting.DatabaseSetting.ShowGetSqllog {

		fmt.Println("==============")
		fmt.Println("apisql:" + sqls)
		fmt.Println("--------------")
		fmt.Println("param:" + param)
		fmt.Println("==============")
	}
	return sqls, param
}

func GetSqlByNameDB(name string) (string, string) {

	sqls := ""
	param := ""
	if sql, ok := Apisql_cache.Get(name); ok && setting.DatabaseSetting.CacheApiSql {
		tempstrb := strings.IndexAny(sql.(string), "|")
		sqls = sql.(string)[0:tempstrb]
		param = sql.(string)[tempstrb+1:]
	} else {
		valuesMap, err := Engine.SQL("SELECT sqlstr,params FROM apisql WHERE sqlname = ? AND ENABLE>0 ", name).QueryString()

		if err == nil && len(valuesMap) > 0 {
			sqls = valuesMap[0]["sqlstr"]
			param = valuesMap[0]["params"]
			Apisql_cache.Set(name, (sqls + "|" + param), cache.DefaultExpiration)
		}
	}
	if setting.DatabaseSetting.ShowGetSqllog {

		fmt.Println("==============")
		fmt.Println("apisql:" + sqls)
		fmt.Println("--------------")
		fmt.Println("param:" + param)
		fmt.Println("==============")
	}
	return sqls, param
}

func GetSqlByNameDBT(name string,tx *xorm.Session) (string, string) {

	sqls := ""
	param := ""
	if sql, ok := Apisql_cache.Get(name); ok && setting.DatabaseSetting.CacheApiSql {
		tempstrb := strings.IndexAny(sql.(string), "|")
		sqls = sql.(string)[0:tempstrb]
		param = sql.(string)[tempstrb+1:]
	} else {
		valuesMap, err := tx.SQL("SELECT sqlstr,params FROM apisql WHERE sqlname = ? AND ENABLE>0 ", name).QueryString()

		if err == nil && len(valuesMap) > 0 {
			sqls = valuesMap[0]["sqlstr"]
			param = valuesMap[0]["params"]
			Apisql_cache.Set(name, (sqls + "|" + param), cache.DefaultExpiration)
		}
	}
	if setting.DatabaseSetting.ShowGetSqllog {

		fmt.Println("==============")
		fmt.Println("apisql:" + sqls)
		fmt.Println("--------------")
		fmt.Println("param:" + param)
		fmt.Println("==============")
	}
	return sqls, param
}

// sqlGetValues 根据结构体中指向实际数据的指针获取出数据,并存储到另一张表中返回
func sqlGetValues(pvs []interface{}, columnsType []*sql.ColumnType, columnsLen int) map[string]interface{} {

	result := make(map[string]interface{}, columnsLen)

	for a := 0; a < columnsLen; a++ {
		switch s := pvs[a].(type) {
		case *int8:
			result[columnsType[a].Name()] = *s
		case *int16:
			result[columnsType[a].Name()] = *s
		case *int32:
			result[columnsType[a].Name()] = *s
		case *int64:
			result[columnsType[a].Name()] = *s
		case *float32:
			result[columnsType[a].Name()] = *s
		case *float64:
			result[columnsType[a].Name()] = *s
		case *string:
			result[columnsType[a].Name()] = *s
		case *sql.NullInt64:
			result[columnsType[a].Name()] = *s
		case *sql.NullString:
			result[columnsType[a].Name()] = *s
		}
	}
	return result
}

// 这里返回的是原始数组的基础上加上了字段名标识
func sqlQuery(columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) ([]map[string]interface{}, error) {

	jsondata := make([]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		jsondata[k1] = sqlGetValues(v1, columnsType, columnsLen)
	}

	return jsondata, nil
}

func sqlQueryByTinyIntMap(columnName string, columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) (map[int8]map[string]interface{}, error) {

	jsondata := make(map[int8]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		for a := 0; a < columnsLen; a++ {
			if columnsType[a].Name() == columnName {
				if value, ok := v1[a].(*int8); ok {
					jsondata[*value] = sqlGetValues(v1, columnsType, columnsLen)
				}
				break
			}
		}
	}

	return jsondata, nil
}

func sqlQueryBySmallIntMap(columnName string, columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) (map[int16]map[string]interface{}, error) {

	jsondata := make(map[int16]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		for a := 0; a < columnsLen; a++ {
			if columnsType[a].Name() == columnName {
				if value, ok := v1[a].(*int16); ok {
					jsondata[*value] = sqlGetValues(v1, columnsType, columnsLen)
				}
				break
			}
		}
	}

	return jsondata, nil
}

func sqlQueryByIntMap(columnName string, columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) (map[int32]map[string]interface{}, error) {

	jsondata := make(map[int32]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		for a := 0; a < columnsLen; a++ {
			if columnsType[a].Name() == columnName {
				if value, ok := v1[a].(*int32); ok {
					jsondata[*value] = sqlGetValues(v1, columnsType, columnsLen)
				}
				break
			}
		}
	}

	return jsondata, nil
}

func sqlQueryByBigIntMap(columnName string, columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) (map[int64]map[string]interface{}, error) {

	jsondata := make(map[int64]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		for a := 0; a < columnsLen; a++ {
			if columnsType[a].Name() == columnName {
				if value, ok := v1[a].(*int64); ok {
					jsondata[*value] = sqlGetValues(v1, columnsType, columnsLen)
				}
				break
			}
		}
	}

	return jsondata, nil
}

func sqlQueryByFloatIntMap(columnName string, columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) (map[float32]map[string]interface{}, error) {

	jsondata := make(map[float32]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		for a := 0; a < columnsLen; a++ {
			if columnsType[a].Name() == columnName {
				if value, ok := v1[a].(*float32); ok {
					jsondata[*value] = sqlGetValues(v1, columnsType, columnsLen)
				}
				break
			}
		}
	}

	return jsondata, nil
}

func sqlQueryByDoubleMap(columnName string, columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) (map[float64]map[string]interface{}, error) {

	jsondata := make(map[float64]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		for a := 0; a < columnsLen; a++ {
			if columnsType[a].Name() == columnName {
				if value, ok := v1[a].(*float64); ok {
					jsondata[*value] = sqlGetValues(v1, columnsType, columnsLen)
				}
				break
			}
		}
	}

	return jsondata, nil
}

func sqlQueryByStringMap(columnName string, columnsType []*sql.ColumnType, columnsLen int, queryData [][]interface{}, queryCount int) (map[string]map[string]interface{}, error) {

	jsondata := make(map[string]map[string]interface{}, queryCount)
	for k1, v1 := range queryData {
		if k1 >= queryCount {
			break
		}

		for a := 0; a < columnsLen; a++ {
			if columnsType[a].Name() == columnName {
				if value, ok := v1[a].(*string); ok {
					jsondata[*value] = sqlGetValues(v1, columnsType, columnsLen)
				}
				break
			}
		}
	}

	return jsondata, nil
}

func sqlGetColumnType(columnsType []*sql.ColumnType, columnsLen int, valueName string) string {

	for a := 0; a < columnsLen; a++ {
		if columnsType[a].Name() == valueName {
			return columnsType[a].DatabaseTypeName()
		}
	}

	return ""
}

func round(num float64) int {
	return int(num + math.Copysign(0.5, num))
}

func toFixed(num float64, precision int) float64 {
	output := math.Pow(10, float64(precision))
	return float64(round(num*output)) / output
}

// QueryByMap 将查询到的数据,按照指定字段的值做为索引构建map并返回
// columnName string: 作为索引的字段名称
// sql string: 查询需要获取哪些字段的值,就是select后面跟着的部分,一般用"*"
// where string: 过滤条件,就是where后面跟着的部分
// order string: 排序条件,就是order by后面跟着的部分。默认是ASC排序,除非"-"开头则DESC排序
// offset string: limit后面逗号相隔的两个数值,前者就是offset,后者就是count
// count string: limit后面逗号相隔的两个数值,前者就是offset,后者就是count
func QueryByMap(sqlstr string, offset, count int, params []interface{}) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}
	recordcount := int64(0)

	if count > 1 {
		tt, err := Engine.SQL("SELECT COUNT(*) as count FROM ("+sqlstr+") a", params...).Query().List()
		if err != nil {
			fmt.Println("s1", err)
			return nil, err
		}
		if tt == nil {
			recordcount = 0
		} else {
			recordcount = tt[0]["count"].(int64)
		}

	}
	queryData := make([]map[string]interface{},1)
	var err error
	if(count==0){
		queryData, err = Engine.SQL(sqlstr, params...).Query().List()
	} else {
		if count > 0 && offset > 0 {
			offset = offset * count
		}
		queryData, err = Engine.SQL(sqlstr, params...).Limit(count, offset).Query().List()
	}
	//fmt.Println("count, offset==================",count, offset)

	if err != nil {
		return nil, err
	}
	if recordcount == 0 {
		recordcount = int64(len(queryData))
	}

	data := make(map[string]interface{})
	data["list"] = queryData
	data["total"] = recordcount
	data["code"] = 0
	data["message"] = "ok"
	if count > 0 {
		data["pages"] = math.Ceil(float64(recordcount) / float64(count))
		data["pageNum"] = math.Ceil(float64(offset+1) / float64(count))
	}
	data["pageSize"] = count
	return data, nil
}

func QueryByMapT(sqlstr string, offset, count int, params []interface{}, tx *xorm.Session) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}
	recordcount := int64(0)

	if count > 1 {
		tt, err := tx.SQL("SELECT COUNT(*) as count FROM ("+sqlstr+") a", params...).Query().List()
		if err != nil {
			fmt.Println("s1", err)
			return nil, err
		}
		if tt == nil {
			recordcount = 0
		} else {
			switch tt[0]["count"].(type) {
			case int64 :
				recordcount = tt[0]["count"].(int64)
			case string :
				temp,_ :=strconv.Atoi(tt[0]["count"].(string))
				recordcount =  int64(temp)

			}

		}

	}
	queryData := make([]map[string]interface{},1)
	var err error
	if(count==0){
		queryData, err = tx.SQL(sqlstr, params...).Query().List()
	} else {
		if count > 0 && offset > 0 {
			offset = offset * count
		}
		queryData, err = tx.SQL(sqlstr, params...).Limit(count, offset).Query().List()
	}
	//fmt.Println("count, offset==================",count, offset)

	if err != nil {
		return nil, err
	}
	if recordcount == 0 {
		recordcount = int64(len(queryData))
	}

	data := make(map[string]interface{})
	data["list"] = queryData
	data["total"] = recordcount
	data["code"] = 0
	data["message"] = "ok"
	if count > 0 {
		data["pages"] = math.Ceil(float64(recordcount) / float64(count))
		data["pageNum"] = math.Ceil(float64(offset+1) / float64(count))
	}
	data["pageSize"] = count
	return data, nil
}


// QueryByXlsx 将查询到的数据,按照指定字段的值做为索引构建map并返回
// sql string: 查询需要获取哪些字段的值,就是select后面跟着的部分,一般用"*"
// params string: 过滤条件,就是where后面跟着的部分

func QueryByXlsx(sqlstr string, params []interface{}) (*xlsx.File, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return nil, err
	}

	rows, err := Engine.SQL(sqlstr, params...).QueryRows()
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	columnsType, _ := rows.ColumnTypes()
	columnsLen := len(columnsType)
	columns, _ := rows.Columns()
	values := make([]interface{}, columnsLen)
	valuePtrs := make([]interface{}, columnsLen)

	var sheet *xlsx.Sheet
	var row *xlsx.Row
	var cell *xlsx.Cell

	file := xlsx.NewFile()
	sheet, err = file.AddSheet("Sheet1")

	if err != nil {
		fmt.Printf(err.Error())
	}
	row = sheet.AddRow()
	for _, columnname := range columns {
		cell = row.AddCell()
		cell.Value = columnname
	}
	for rows.Next() {
		for a := 0; a < columnsLen; a++ {
			valuePtrs[a] = &values[a]
		}
		rows.Scan(valuePtrs...)
		row = sheet.AddRow()
		for i, _ := range columns {
			var v interface{}
			val := values[i]
			b, ok := val.([]byte)
			cell = row.AddCell()
			if ok {
				v1 := string(b)
				switch columnsType[i].DatabaseTypeName() {
				case "TINYINT", "SMALLINT", "MEDIUMINT", "INT", "INTEGER", "BIGINT":
					{
						v, _ = strconv.ParseInt(v1, 10, 32)
						cell.Value = fmt.Sprintf("%v", v)
					}
				case "FLOAT", "DOUBLE", "DECIMAL":
					{
						cindex := len(val.([]byte)) - strings.Index(v1, ".") - 1
						v2, _ := strconv.ParseFloat(v1, 32)
						v = toFixed(v2, cindex)
						cell.Value = fmt.Sprintf("%v", v)
					}
				case "BOOL":
					{
						v, _ = strconv.ParseBool(v1)
						cell.Value = fmt.Sprintf("%v", v)
					}
				default:
					{
						v = v1
						cell.Value = fmt.Sprintf("%v", v)
					}
				}

			} else {
				v = val
				cell.Value = fmt.Sprintf("%v", v)
			}
			if cell.Value == "<nil>" {
				cell.Value = ""
			}
		}
	}

	return file, nil
}

// QueryByMap 将查询到的数据,按照指定字段的值做为索引构建map并返回
// columnName string: 作为索引的字段名称
// sql string: 查询需要获取哪些字段的值,就是select后面跟着的部分,一般用"*"
// where string: 过滤条件,就是where后面跟着的部分
// order string: 排序条件,就是order by后面跟着的部分。默认是ASC排序,除非"-"开头则DESC排序
// offset string: limit后面逗号相隔的两个数值,前者就是offset,后者就是count
// count string: limit后面逗号相隔的两个数值,前者就是offset,后者就是count

func QueryByMapMenu(sqlstr string, offset, count int, params []interface{}) ([]map[string]interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return nil, err
	}

	if offset < 0 {
		offset = 0
	}
	if count <= 0 {
		count = 0
	}
	if count > 0 {
		sqlstr += " limit " + strconv.Itoa(offset) + "," + strconv.Itoa(count)
	}

	rows, err := Engine.SQL(sqlstr, params...).QueryRows()
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	columnsType, _ := rows.ColumnTypes()
	columnsLen := len(columnsType)
	columns, _ := rows.Columns()
	queryData := make([]map[string]interface{}, 0)
	values := make([]interface{}, columnsLen)
	valuePtrs := make([]interface{}, columnsLen)

	for rows.Next() {
		for a := 0; a < columnsLen; a++ {
			valuePtrs[a] = &values[a]
		}
		rows.Scan(valuePtrs...)
		entry := make(map[string]interface{})
		for i, col := range columns {
			entry[col] = getValue(values[i], columnsType[i].DatabaseTypeName())
		}
		queryData = append(queryData, entry)
	}

	data := queryData
	return data, nil
	//return Engine.SQL(sqlstr, params...).Query().List()
}

func QueryByList(sqlstr string, offset, count int, params []interface{}) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}
	if(count==0){
		count = 1000
	}
	recordcount := int64(0)
	if count > 1 {
		tt, err := Engine.SQL("SELECT COUNT(*) as count FROM ("+sqlstr+") a", params...).Query().List()
		if err != nil {
			return nil, err
		}
		recordcount = tt[0]["count"].(int64)
	}
	queryData := make([]map[string]interface{},1)
	var err error
	if(count==0){
		queryData, err = Engine.SQL(sqlstr, params...).Query().List()
	} else {
		if count > 0 && offset > 0 {
			offset = offset * count
		}
		queryData, err = Engine.SQL(sqlstr, params...).Limit(count, offset).Query().List()
	}
	if err != nil {
		return nil, err
	}
	columnsname := make([]string, 0)
	listdata := make(map[string][]interface{})
	if len(queryData) > 0 {
		for i, _ := range queryData {
			if i == 0 {
				for i, _ := range queryData[0] {
					columnsname = append(columnsname, i)
				}
			}

			for _, v := range columnsname {
				listdata[v] = append(listdata[v], queryData[i][v])
			}

		}
		recordcount = int64(len(queryData))
	}

	data := make(map[string]interface{})
	data["lists"] = listdata
	//data["columnsname"] = columnsname
	data["total"] = recordcount
	data["code"] = 0
	data["message"] = "ok"
	if count > 0 {
		data["pages"] = math.Ceil(float64(recordcount) / float64(count))
		data["pageNum"] = math.Ceil(float64(offset+1) / float64(count))
	}
	data["pageSize"] = count
	return data, nil
}

func QueryByListList(sqlstr string, offset, count int, params []interface{}) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}
	if(count==0){
		count = 1000
	}
	recordcount := int64(0)
	if count > 1 {
		tt, err := Engine.SQL("SELECT COUNT(*) as count FROM ("+sqlstr+") a", params...).Query().List()
		if err != nil {
			return nil, err
		}
		recordcount = tt[0]["count"].(int64)
	}


	queryData := make([]map[string]interface{},1)
	var err error
	if(count==0){
		queryData, err = Engine.SQL(sqlstr, params...).Query().List()
	} else {
		if count > 0 && offset > 0 {
			offset = offset * count
		}
		queryData, err = Engine.SQL(sqlstr, params...).Limit(count, offset).Query().List()
	}

	if err != nil {
		return nil, err
	}
	columnsname := make([]string, 0)
	listdata := make([]interface{}, 0)
	if len(queryData) > 0 {
		for i, _ := range queryData {
			if i == 0 {
				for i, _ := range queryData[0] {
					columnsname = append(columnsname, i)
				}
			}
			listdatarow := make([]interface{}, 0)

			for _, v := range columnsname {
				listdatarow = append(listdatarow, queryData[i][v])
			}
			listdata = append(listdata, listdatarow)
		}
		recordcount = int64(len(queryData))
	}
	data := make(map[string]interface{})
	data["list"] = listdata
	data["columnsname"] = columnsname
	data["total"] = recordcount
	data["code"] = 0
	data["message"] = "ok"
	if count > 0 {
		data["pages"] = math.Ceil(float64(recordcount) / float64(count))
		data["pageNum"] = math.Ceil(float64(offset+1) / float64(count))
	}
	data["pageSize"] = count
	return data, nil
}

func QueryByListT(sqlstr string, offset, count int, params []interface{}, tx *xorm.Session) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}
	if(count==0){
		count = 1000
	}
	recordcount := int64(0)
	if count > 1 {
		tt, err := tx.SQL("SELECT COUNT(*) as count FROM ("+sqlstr+") a", params...).Query().List()
		if err != nil {
			return nil, err
		}
		switch tt[0]["count"].(type) {
		case int64 :
			recordcount = tt[0]["count"].(int64)
		case string :
			temp,_ :=strconv.Atoi(tt[0]["count"].(string))
			recordcount =  int64(temp)

		}
	}
	queryData := make([]map[string]interface{},1)
	var err error
	if(count==0){
		queryData, err = tx.SQL(sqlstr, params...).Query().List()
	} else {
		if count > 0 && offset > 0 {
			offset = offset * count
		}
		queryData, err = tx.SQL(sqlstr, params...).Limit(count, offset).Query().List()

	}
	if err != nil {
		return nil, err
	}
	columnsname := make([]string, 0)
	listdata := make(map[string][]interface{})
	if len(queryData) > 0 {
		for i, _ := range queryData {
			if i == 0 {
				for i, _ := range queryData[0] {
					columnsname = append(columnsname, i)
				}
			}

			for _, v := range columnsname {
				listdata[v] = append(listdata[v], queryData[i][v])
			}

		}
		recordcount = int64(len(queryData))
	}

	data := make(map[string]interface{})
	data["lists"] = listdata
	//data["columnsname"] = columnsname
	data["total"] = recordcount
	data["code"] = 0
	data["message"] = "ok"
	if count > 0 {
		data["pages"] = math.Ceil(float64(recordcount) / float64(count))
		data["pageNum"] = math.Ceil(float64(offset+1) / float64(count))
	}
	data["pageSize"] = count
	return data, nil
}

func QueryByListListT(sqlstr string, offset, count int, params []interface{}, tx *xorm.Session) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}
	if(count==0){
		count = 1000
	}
	recordcount := int64(0)
	if count > 1 {
		tt, err := tx.SQL("SELECT COUNT(*) as count FROM ("+sqlstr+") a", params...).Query().List()
		if err != nil {
			return nil, err
		}
		switch tt[0]["count"].(type) {
		case int64 :
			recordcount = tt[0]["count"].(int64)
		case string :
			temp,_ :=strconv.Atoi(tt[0]["count"].(string))
			recordcount =  int64(temp)

		}
	}


	queryData := make([]map[string]interface{},1)
	var err error
	if(count==0){
		queryData, err = tx.SQL(sqlstr, params...).Query().List()
	} else {
		if count > 0 && offset > 0 {
			offset = offset * count
		}
		queryData, err = tx.SQL(sqlstr, params...).Limit(count, offset).Query().List()
	}

	if err != nil {
		return nil, err
	}
	columnsname := make([]string, 0)
	listdata := make([]interface{}, 0)
	if len(queryData) > 0 {
		for i, _ := range queryData {
			if i == 0 {
				for i, _ := range queryData[0] {
					columnsname = append(columnsname, i)
				}
			}
			listdatarow := make([]interface{}, 0)

			for _, v := range columnsname {
				listdatarow = append(listdatarow, queryData[i][v])
			}
			listdata = append(listdata, listdatarow)
		}
		recordcount = int64(len(queryData))
	}
	data := make(map[string]interface{})
	data["list"] = listdata
	data["columnsname"] = columnsname
	data["total"] = recordcount
	data["code"] = 0
	data["message"] = "ok"
	if count > 0 {
		data["pages"] = math.Ceil(float64(recordcount) / float64(count))
		data["pageNum"] = math.Ceil(float64(offset+1) / float64(count))
	}
	data["pageSize"] = count
	return data, nil
}

func ExecQuery(sqlstr string, params []interface{}) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}

	rows, err := Engine.SQL(sqlstr, params...).Execute()
	if err != nil {
		return nil, err
	}
	data := make(map[string]interface{})
	LastInsertId, _ := rows.LastInsertId()
	idPointer := (*int)(unsafe.Pointer(&LastInsertId))
	idd16 := *idPointer
	RowsAffected, _ := rows.RowsAffected()
	_idPointer := (*int)(unsafe.Pointer(&RowsAffected))
	_idd16 := *_idPointer
	data["result"] = rows
	data["LastInsertId"] = idd16

	data["RowsAffected"] = _idd16
	return data, nil
}

func ExecQueryT(sqlstr string, params []interface{}, tx *xorm.Session) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}

	rows, err := tx.SQL(sqlstr, params...).Execute()
	if err != nil {

		fmt.Println("exe", err)
		return nil, err
	}

	LastInsertId, _ := rows.LastInsertId()
	idPointer := (*int)(unsafe.Pointer(&LastInsertId))
	idd16 := *idPointer
	data := make(map[string]interface{})

	RowsAffected, _ := rows.RowsAffected()
	_idPointer := (*int)(unsafe.Pointer(&RowsAffected))
	_idd16 := *_idPointer
	data["LastInsertId"] =strconv.Itoa(idd16)
	data["LastInsertIdStr"] =idd16
	data["RowsAffected"] = _idd16
	data["result"] = rows
	return data, nil
}

func ExecQuerys(sqlstr string, params []interface{}) (interface{}, error) {
	if err := sqlCheckParam(sqlstr); err != nil {
		return 0, err
	}
	/*for i, v := range params{
		_, err := dbs.Exec(sqlstr, v[i]...)

		if err != nil {
			return nil, err
		}
	}

	*/
	data := make(map[string]interface{})
	data["result"] = nil
	return data, nil
}

func getValue(value interface{}, CT string) interface{} {
	var v interface{}
	val := value
	b, ok := val.([]byte)
	if ok {
		v1 := string(b)
		switch CT {
		case "TINYINT", "SMALLINT", "MEDIUMINT", "INT", "INTEGER", "BIGINT":
			{
				v, _ = strconv.ParseInt(v1, 10, 32)
			}
		case "FLOAT", "DOUBLE", "DECIMAL":
			{
				cindex := len(val.([]byte)) - strings.Index(v1, ".") - 1
				v2, _ := strconv.ParseFloat(v1, 32)
				v = toFixed(v2, cindex)
			}
		case "BOOL":
			{
				v, _ = strconv.ParseBool(v1)
			}
		default:
			{
				v = v1
			}
		}
	} else {
		v = val
	}
	return v
}