add mssql support

This commit is contained in:
lunny 2013-12-20 14:53:40 +08:00
parent 59412a951c
commit 4459c88a28
8 changed files with 440 additions and 23 deletions

View File

@ -231,7 +231,7 @@ func insertMulti(engine *Engine, t *testing.T) {
} }
func insertTwoTable(engine *Engine, t *testing.T) { func insertTwoTable(engine *Engine, t *testing.T) {
userdetail := Userdetail{Id: 1, Intro: "I'm a very beautiful women.", Profile: "sfsaf"} userdetail := Userdetail{ /*Id: 1, */ Intro: "I'm a very beautiful women.", Profile: "sfsaf"}
userinfo := Userinfo{Username: "xlw3", Departname: "dev", Alias: "lunny4", Created: time.Now(), Detail: userdetail} userinfo := Userinfo{Username: "xlw3", Departname: "dev", Alias: "lunny4", Created: time.Now(), Detail: userdetail}
cnt, err := engine.Insert(&userinfo, &userdetail) cnt, err := engine.Insert(&userinfo, &userdetail)
@ -1173,7 +1173,8 @@ func testColTypes(engine *Engine, t *testing.T) {
true, true,
21, 0,
//21,
} }
cnt, err := engine.Insert(ac) cnt, err := engine.Insert(ac)
@ -1202,6 +1203,10 @@ func testColTypes(engine *Engine, t *testing.T) {
newAc.Real = 0 newAc.Real = 0
newAc.Float = 0 newAc.Float = 0
newAc.Double = 0 newAc.Double = 0
newAc.LongText = ""
newAc.TinyText = ""
newAc.MediumText = ""
newAc.Text = ""
cnt, err = engine.Delete(newAc) cnt, err = engine.Delete(newAc)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -1286,6 +1291,9 @@ func testCustomType(engine *Engine, t *testing.T) {
} }
fmt.Println(i) fmt.Println(i)
i.NameArray = []string{}
i.MSS = map[string]string{}
i.F = 0
has, err := engine.Get(&i) has, err := engine.Get(&i)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -1312,6 +1320,8 @@ func testCustomType(engine *Engine, t *testing.T) {
fmt.Println(sss) fmt.Println(sss)
if has { if has {
sss.NameArray = []string{}
sss.MSS = map[string]string{}
cnt, err := engine.Delete(&sss) cnt, err := engine.Delete(&sss)
if err != nil { if err != nil {
t.Error(err) t.Error(err)

View File

@ -19,11 +19,14 @@ const (
SQLITE = "sqlite3" SQLITE = "sqlite3"
MYSQL = "mysql" MYSQL = "mysql"
MYMYSQL = "mymysql" MYMYSQL = "mymysql"
MSSQL = "mssql"
) )
// a dialect is a driver's wrapper // a dialect is a driver's wrapper
type dialect interface { type dialect interface {
Init(DriverName, DataSourceName string) error Init(DriverName, DataSourceName string) error
DBType() string
SqlType(t *Column) string SqlType(t *Column) string
SupportInsertMany() bool SupportInsertMany() bool
QuoteStr() string QuoteStr() string
@ -248,7 +251,7 @@ func (engine *Engine) DBMetas() ([]*Table, error) {
if col, ok := table.Columns[name]; ok { if col, ok := table.Columns[name]; ok {
col.Indexes[index.Name] = true col.Indexes[index.Name] = true
} else { } else {
return nil, errors.New("Unkonwn col " + name + " in indexes") return nil, fmt.Errorf("Unknown col "+name+" in indexes %v", table.Columns)
} }
} }
} }
@ -746,6 +749,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Println("-----", isExist)
if !isExist { if !isExist {
session := engine.NewSession() session := engine.NewSession()
session.Statement.RefTable = table session.Statement.RefTable = table

273
mssql.go Normal file
View File

@ -0,0 +1,273 @@
package xorm
import (
//"crypto/tls"
"database/sql"
"errors"
"fmt"
//"regexp"
"strconv"
"strings"
//"time"
)
type mssql struct {
base
quoteFilter Filter
}
type mssqlParser struct {
}
func (p *mssqlParser) parse(driverName, dataSourceName string) (*uri, error) {
return &uri{dbName: "xorm_test", dbType: MSSQL}, nil
}
func (db *mssql) Init(drivername, uri string) error {
db.quoteFilter = &QuoteFilter{}
return db.base.init(&mssqlParser{}, drivername, uri)
}
func (db *mssql) SqlType(c *Column) string {
var res string
switch t := c.SQLType.Name; t {
case Bool:
res = TinyInt
case Serial:
c.IsAutoIncrement = true
c.IsPrimaryKey = true
c.Nullable = false
res = Int
case BigSerial:
c.IsAutoIncrement = true
c.IsPrimaryKey = true
c.Nullable = false
res = BigInt
case Bytea, Blob, Binary, TinyBlob, MediumBlob, LongBlob:
res = VarBinary
if c.Length == 0 {
c.Length = 50
}
case TimeStamp:
res = DateTime
case TimeStampz:
res = "DATETIMEOFFSET"
c.Length = 7
case MediumInt:
res = Int
case MediumText, TinyText, LongText:
res = Text
case Double:
res = Real
default:
res = t
}
if res == Int {
return Int
}
var hasLen1 bool = (c.Length > 0)
var hasLen2 bool = (c.Length2 > 0)
if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
} else if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
}
return res
}
func (db *mssql) SupportInsertMany() bool {
return true
}
func (db *mssql) QuoteStr() string {
return "\""
}
func (db *mssql) SupportEngine() bool {
return false
}
func (db *mssql) AutoIncrStr() string {
return "IDENTITY"
}
func (db *mssql) SupportCharset() bool {
return false
}
func (db *mssql) IndexOnTable() bool {
return true
}
func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{idxName}
sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?"
return sql, args
}
func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{tableName, colName}
sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
return sql, args
}
func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{}
sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1"
return sql, args
}
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*Column, error) {
args := []interface{}{}
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale
from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id
where a.object_id=object_id('` + tableName + `')`
cnn, err := sql.Open(db.driverName, db.dataSourceName)
if err != nil {
return nil, nil, err
}
defer cnn.Close()
res, err := query(cnn, s, args...)
if err != nil {
return nil, nil, err
}
cols := make(map[string]*Column)
colSeq := make([]string, 0)
for _, record := range res {
col := new(Column)
col.Indexes = make(map[string]bool)
for name, content := range record {
switch name {
case "name":
col.Name = strings.Trim(string(content), "` ")
case "ctype":
ct := strings.ToUpper(string(content))
switch ct {
case "DATETIMEOFFSET":
col.SQLType = SQLType{TimeStampz, 0, 0}
default:
if _, ok := sqlTypes[ct]; ok {
col.SQLType = SQLType{ct, 0, 0}
} else {
return nil, nil, errors.New(fmt.Sprintf("unknow colType %v", ct))
}
}
case "max_length":
len1, err := strconv.Atoi(strings.TrimSpace(string(content)))
if err != nil {
return nil, nil, err
}
col.Length = len1
}
}
if col.SQLType.IsText() {
if col.Default != "" {
col.Default = "'" + col.Default + "'"
}
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}
return colSeq, cols, nil
}
func (db *mssql) GetTables() ([]*Table, error) {
args := []interface{}{}
s := `select name from sysobjects where xtype ='U'`
cnn, err := sql.Open(db.driverName, db.dataSourceName)
if err != nil {
return nil, err
}
defer cnn.Close()
res, err := query(cnn, s, args...)
if err != nil {
return nil, err
}
tables := make([]*Table, 0)
for _, record := range res {
table := new(Table)
for name, content := range record {
switch name {
case "name":
table.Name = strings.Trim(string(content), "` ")
}
}
tables = append(tables, table)
}
return tables, nil
}
func (db *mssql) GetIndexes(tableName string) (map[string]*Index, error) {
args := []interface{}{tableName}
s := `SELECT
IXS.NAME AS [INDEX_NAME],
C.NAME AS [COLUMN_NAME],
IXS.is_unique AS [IS_UNIQUE],
CASE IXCS.IS_INCLUDED_COLUMN
WHEN 0 THEN 'NONE'
ELSE 'INCLUDED' END AS [IS_INCLUDED_COLUMN]
FROM SYS.INDEXES IXS
INNER JOIN SYS.INDEX_COLUMNS IXCS
ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID
INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID
AND IXCS.COLUMN_ID=C.COLUMN_ID
WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
`
cnn, err := sql.Open(db.driverName, db.dataSourceName)
if err != nil {
return nil, err
}
defer cnn.Close()
res, err := query(cnn, s, args...)
if err != nil {
return nil, err
}
indexes := make(map[string]*Index, 0)
for _, record := range res {
fmt.Println("-----", record, "-----")
var indexType int
var indexName, colName string
for name, content := range record {
switch name {
case "IS_UNIQUE":
i, err := strconv.ParseBool(string(content))
if err != nil {
return nil, err
}
fmt.Println(name, string(content), i)
if i {
indexType = UniqueType
} else {
indexType = IndexType
}
case "INDEX_NAME":
indexName = string(content)
case "COLUMN_NAME":
colName = strings.Trim(string(content), "` ")
}
}
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
indexName = indexName[5+len(tableName) : len(indexName)]
}
var index *Index
var ok bool
if index, ok = indexes[indexName]; !ok {
index = new(Index)
index.Type = indexType
index.Name = indexName
indexes[indexName] = index
}
index.AddColumn(colName)
fmt.Print("------end------")
}
return indexes, nil
}

73
mssql_test.go Normal file
View File

@ -0,0 +1,73 @@
package xorm
import (
_ "code.google.com/p/odbc"
_ "github.com/mattn/go-adodb"
"testing"
)
/*
CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET
utf8 COLLATE utf8_general_ci;
*/
func newMssqlEngine() (*Engine, error) {
//return NewEngine("adodb", "Provider=SQLOLEDB; Server=127.0.0.1;Database=xorm_test; uid=sa; pwd=1234;")
return NewEngine("odbc", "driver={SQL Server};Server=127.0.0.1;Database=xorm_test; uid=sa; pwd=1234;")
}
func TestMssql(t *testing.T) {
engine, err := newMssqlEngine()
defer engine.Close()
if err != nil {
t.Error(err)
return
}
engine.ShowSQL = showTestSql
engine.ShowErr = showTestSql
engine.ShowWarn = showTestSql
engine.ShowDebug = showTestSql
testAll(engine, t)
testAll2(engine, t)
}
func TestMssqlWithCache(t *testing.T) {
engine, err := newMssqlEngine()
defer engine.Close()
if err != nil {
t.Error(err)
return
}
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
engine.ShowSQL = showTestSql
engine.ShowErr = showTestSql
engine.ShowWarn = showTestSql
engine.ShowDebug = showTestSql
testAll(engine, t)
testAll2(engine, t)
}
func BenchmarkMssqlNoCache(t *testing.B) {
engine, err := newMssqlEngine()
defer engine.Close()
if err != nil {
t.Error(err)
return
}
//engine.ShowSQL = true
doBenchFind(engine, t)
}
func BenchmarkMssqlCache(t *testing.B) {
engine, err := newMssqlEngine()
defer engine.Close()
if err != nil {
t.Error(err)
return
}
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
doBenchFind(engine, t)
}

View File

@ -68,6 +68,10 @@ func (b *base) init(parser parser, drivername, dataSourceName string) (err error
return return
} }
func (b *base) DBType() string {
return b.uri.dbType
}
type mysql struct { type mysql struct {
base base
net string net string

View File

@ -1003,7 +1003,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
if len(condiBean) > 0 { if len(condiBean) > 0 {
colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true, colNames, args := buildConditions(session.Engine, table, condiBean[0], true, true,
false, session.Statement.allUseBool, session.Statement.boolColumnMap) false, true, session.Statement.allUseBool, session.Statement.boolColumnMap)
session.Statement.ConditionStr = strings.Join(colNames, " AND ") session.Statement.ConditionStr = strings.Join(colNames, " AND ")
session.Statement.BeanArgs = args session.Statement.BeanArgs = args
} }
@ -1147,8 +1147,8 @@ func (session *Session) isIndexExist2(tableName string, cols []string, unique bo
return false, err return false, err
} }
for _, index := range indexes { for i, index := range indexes {
//fmt.Println(i, "new:", cols, "-old:", index.Cols) fmt.Println(i, "new:", cols, "-old:", index.Cols, sliceEq(index.Cols, cols), unique, index.Type)
if sliceEq(index.Cols, cols) { if sliceEq(index.Cols, cols) {
if unique { if unique {
return index.Type == UniqueType, nil return index.Type == UniqueType, nil
@ -1352,6 +1352,7 @@ func query(db *sql.DB, sql string, params ...interface{}) (resultsSlice []map[st
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
fmt.Println(rows)
return rows2maps(rows) return rows2maps(rows)
} }
@ -1635,7 +1636,7 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data
var err error var err error
// for mysql, when use bit, it returned \x01 // for mysql, when use bit, it returned \x01
if col.SQLType.Name == Bit && if col.SQLType.Name == Bit &&
strings.Contains(session.Engine.DriverName, "mysql") { session.Engine.dialect.DBType() == MYSQL {
if len(data) == 1 { if len(data) == 1 {
x = int64(data[0]) x = int64(data[0])
} else { } else {
@ -1646,6 +1647,10 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data
x, err = strconv.ParseInt(sdata, 16, 64) x, err = strconv.ParseInt(sdata, 16, 64)
} else if strings.HasPrefix(sdata, "0") { } else if strings.HasPrefix(sdata, "0") {
x, err = strconv.ParseInt(sdata, 8, 64) x, err = strconv.ParseInt(sdata, 8, 64)
} else if strings.ToLower(sdata) == "true" {
x = 1
} else if strings.ToLower(sdata) == "false" {
x = 0
} else { } else {
x, err = strconv.ParseInt(sdata, 10, 64) x, err = strconv.ParseInt(sdata, 10, 64)
} }
@ -1685,14 +1690,21 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data
if err != nil { if err != nil {
x, err = time.Parse("2006-01-02 15:04:05.999999999", sdata) x, err = time.Parse("2006-01-02 15:04:05.999999999", sdata)
} }
if err != nil {
x, err = time.Parse("2006-01-02 15:04:05.9999999 Z07:00", sdata)
}
} else if len(sdata) == 19 { } else if len(sdata) == 19 {
x, err = time.Parse("2006-01-02 15:04:05", sdata) x, err = time.Parse("2006-01-02 15:04:05", sdata)
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
x, err = time.Parse("2006-01-02", sdata) x, err = time.Parse("2006-01-02", sdata)
} else if col.SQLType.Name == Time { } else if col.SQLType.Name == Time {
if len(sdata) > 8 { if strings.Contains(sdata, " ") {
sdata = sdata[len(sdata)-8:] ssd := strings.Split(sdata, " ")
sdata = ssd[1]
} }
/*if len(sdata) > 8 {
sdata = sdata[len(sdata)-8:]
}*/
st := fmt.Sprintf("2006-01-02 %v", sdata) st := fmt.Sprintf("2006-01-02 %v", sdata)
x, err = time.Parse("2006-01-02 15:04:05", st) x, err = time.Parse("2006-01-02 15:04:05", st)
} else { } else {
@ -2052,6 +2064,13 @@ func (session *Session) value2Interface(col *Column, fieldValue reflect.Value) (
return fieldValue.String(), nil return fieldValue.String(), nil
case reflect.Struct: case reflect.Struct:
if fieldType.String() == "time.Time" { if fieldType.String() == "time.Time" {
t := fieldValue.Interface().(time.Time)
if session.Engine.dialect.DBType() == MSSQL {
if t.IsZero() {
return nil, nil
}
}
if col.SQLType.Name == Time { if col.SQLType.Name == Time {
//s := fieldValue.Interface().(time.Time).Format("2006-01-02 15:04:05 -0700") //s := fieldValue.Interface().(time.Time).Format("2006-01-02 15:04:05 -0700")
s := fieldValue.Interface().(time.Time).Format(time.RFC3339) s := fieldValue.Interface().(time.Time).Format(time.RFC3339)
@ -2059,6 +2078,11 @@ func (session *Session) value2Interface(col *Column, fieldValue reflect.Value) (
} else if col.SQLType.Name == Date { } else if col.SQLType.Name == Date {
return fieldValue.Interface().(time.Time).Format("2006-01-02"), nil return fieldValue.Interface().(time.Time).Format("2006-01-02"), nil
} else if col.SQLType.Name == TimeStampz { } else if col.SQLType.Name == TimeStampz {
if session.Engine.dialect.DBType() == MSSQL {
tf := t.Format("2006-01-02T15:04:05.9999999Z07:00")
fmt.Println("====", tf)
return tf, nil
}
return fieldValue.Interface().(time.Time).Format(time.RFC3339Nano), nil return fieldValue.Interface().(time.Time).Format(time.RFC3339Nano), nil
} }
return fieldValue.Interface(), nil return fieldValue.Interface(), nil
@ -2475,7 +2499,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
if session.Statement.ColumnStr == "" { if session.Statement.ColumnStr == "" {
colNames, args = buildConditions(session.Engine, table, bean, false, false, colNames, args = buildConditions(session.Engine, table, bean, false, false,
false, session.Statement.allUseBool, session.Statement.boolColumnMap) false, false, session.Statement.allUseBool, session.Statement.boolColumnMap)
} else { } else {
colNames, args, err = table.genCols(session, bean, true, true) colNames, args, err = table.genCols(session, bean, true, true)
if err != nil { if err != nil {
@ -2509,7 +2533,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
if len(condiBean) > 0 { if len(condiBean) > 0 {
condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true, condiColNames, condiArgs = buildConditions(session.Engine, session.Statement.RefTable, condiBean[0], true, true,
false, session.Statement.allUseBool, session.Statement.boolColumnMap) false, true, session.Statement.allUseBool, session.Statement.boolColumnMap)
} }
var condition = "" var condition = ""
@ -2697,7 +2721,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
table := session.Engine.autoMap(bean) table := session.Engine.autoMap(bean)
session.Statement.RefTable = table session.Statement.RefTable = table
colNames, args := buildConditions(session.Engine, table, bean, true, true, colNames, args := buildConditions(session.Engine, table, bean, true, true,
false, session.Statement.allUseBool, session.Statement.boolColumnMap) false, true, session.Statement.allUseBool, session.Statement.boolColumnMap)
var condition = "" var condition = ""

View File

@ -258,7 +258,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
// Auto generating conditions according a struct // Auto generating conditions according a struct
func buildConditions(engine *Engine, table *Table, bean interface{}, func buildConditions(engine *Engine, table *Table, bean interface{},
includeVersion bool, includeUpdated bool, includeNil bool, allUseBool bool, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, allUseBool bool,
boolColumnMap map[string]bool) ([]string, []interface{}) { boolColumnMap map[string]bool) ([]string, []interface{}) {
colNames := make([]string, 0) colNames := make([]string, 0)
@ -270,6 +270,14 @@ func buildConditions(engine *Engine, table *Table, bean interface{},
if !includeUpdated && col.IsUpdated { if !includeUpdated && col.IsUpdated {
continue continue
} }
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
//
fmt.Println(engine.dialect.DBType(), Text)
if engine.dialect.DBType() == MSSQL && col.SQLType.Name == Text {
continue
}
fieldValue := col.ValueOf(bean) fieldValue := col.ValueOf(bean)
fieldType := reflect.TypeOf(fieldValue.Interface()) fieldType := reflect.TypeOf(fieldValue.Interface())
@ -361,7 +369,7 @@ func buildConditions(engine *Engine, table *Table, bean interface{},
if fieldValue == reflect.Zero(fieldType) { if fieldValue == reflect.Zero(fieldType) {
continue continue
} }
if fieldValue.IsNil() || !fieldValue.IsValid() { if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
continue continue
} }
@ -607,7 +615,13 @@ func (statement *Statement) genColumnStr() string {
} }
func (statement *Statement) genCreateTableSQL() string { func (statement *Statement) genCreateTableSQL() string {
sql := "CREATE TABLE IF NOT EXISTS " + statement.Engine.Quote(statement.TableName()) + " (" var sql string
if statement.Engine.dialect.DBType() == MSSQL {
sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + statement.TableName() + "' ) CREATE TABLE"
} else {
sql = "CREATE TABLE IF NOT EXISTS "
}
sql += statement.Engine.Quote(statement.TableName()) + " ("
pkList := []string{} pkList := []string{}
@ -702,8 +716,13 @@ func (s *Statement) genDelIndexSQL() []string {
} }
func (s *Statement) genDropSQL() string { func (s *Statement) genDropSQL() string {
sql := "DROP TABLE IF EXISTS " + s.Engine.Quote(s.TableName()) + ";" if s.Engine.dialect.DBType() == MSSQL {
return sql return "IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'" +
s.TableName() + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1) " +
"DROP TABLE " + s.Engine.Quote(s.TableName()) + ";"
} else {
return "DROP TABLE IF EXISTS " + s.Engine.Quote(s.TableName()) + ";"
}
} }
// !nashtsai! REVIEW, Statement is a huge struct why is this method not passing *Statement? // !nashtsai! REVIEW, Statement is a huge struct why is this method not passing *Statement?
@ -712,7 +731,7 @@ func (statement *Statement) genGetSql(bean interface{}) (string, []interface{})
statement.RefTable = table statement.RefTable = table
colNames, args := buildConditions(statement.Engine, table, bean, true, true, colNames, args := buildConditions(statement.Engine, table, bean, true, true,
false, statement.allUseBool, statement.boolColumnMap) false, true, statement.allUseBool, statement.boolColumnMap)
statement.ConditionStr = strings.Join(colNames, " AND ") statement.ConditionStr = strings.Join(colNames, " AND ")
statement.BeanArgs = args statement.BeanArgs = args
@ -751,7 +770,7 @@ func (statement *Statement) genCountSql(bean interface{}) (string, []interface{}
statement.RefTable = table statement.RefTable = table
colNames, args := buildConditions(statement.Engine, table, bean, true, true, false, colNames, args := buildConditions(statement.Engine, table, bean, true, true, false,
statement.allUseBool, statement.boolColumnMap) true, statement.allUseBool, statement.boolColumnMap)
statement.ConditionStr = strings.Join(colNames, " AND ") statement.ConditionStr = strings.Join(colNames, " AND ")
statement.BeanArgs = args statement.BeanArgs = args
@ -797,11 +816,18 @@ func (statement *Statement) genSelectSql(columnStr string) (a string) {
if statement.OrderStr != "" { if statement.OrderStr != "" {
a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr) a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
} }
if statement.Engine.dialect.DBType() != MSSQL {
if statement.Start > 0 { if statement.Start > 0 {
a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start) a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
} else if statement.LimitN > 0 { } else if statement.LimitN > 0 {
a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN) a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
} }
} else {
/*SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY id desc) as row FROM "userinfo"
) a WHERE row > [start] and row <= [start+limit] order by id desc*/
}
return return
} }

View File

@ -34,6 +34,9 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
engine.Filters = append(engine.Filters, &QuoteFilter{}) engine.Filters = append(engine.Filters, &QuoteFilter{})
} else if driverName == MYMYSQL { } else if driverName == MYMYSQL {
engine.dialect = &mymysql{} engine.dialect = &mymysql{}
} else if driverName == "odbc" {
engine.dialect = &mssql{quoteFilter: &QuoteFilter{}}
engine.Filters = append(engine.Filters, &QuoteFilter{})
} else { } else {
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName)) return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
} }