1
0
Fork 0
forked from forgejo/forgejo

Added test environment for mssql (#4282)

* Added test environment for m$sql

* Added template for test environment for m$sql

* Fix password

* Fix password (again)

* Fix password (again again)

* Fix db

* Ci trigger (Looking at you drone....)

* Ci trigger (Looking at you drone....)

* Ci trigger (Looking at you drone....)

* Ci trigger (Looking at you drone....)

* Create master database for mssql integration tests

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Create database only if master do not exist

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Fix mssql integration tests by using custom database "gitea"

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Moved defer

* bump xorm

* updated xorm

* Fixed build
This commit is contained in:
kolaente 2018-12-12 02:01:41 +01:00 committed by Lunny Xiao
parent b1f3685015
commit 6db7dbd333
27 changed files with 383 additions and 66 deletions

30
vendor/github.com/go-xorm/xorm/context_cache.go generated vendored Normal file
View file

@ -0,0 +1,30 @@
// Copyright 2018 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
// ContextCache is the interface that operates the cache data.
type ContextCache interface {
// Put puts value into cache with key.
Put(key string, val interface{})
// Get gets cached value by given key.
Get(key string) interface{}
}
type memoryContextCache map[string]interface{}
// NewMemoryContextCache return memoryContextCache
func NewMemoryContextCache() memoryContextCache {
return make(map[string]interface{})
}
// Put puts value into cache with key.
func (m memoryContextCache) Put(key string, val interface{}) {
m[key] = val
}
// Get gets cached value by given key.
func (m memoryContextCache) Get(key string) interface{} {
return m[key]
}

View file

@ -218,7 +218,7 @@ func (db *mssql) SqlType(c *core.Column) string {
res = core.Bit
if strings.EqualFold(c.Default, "true") {
c.Default = "1"
} else {
} else if strings.EqualFold(c.Default, "false") {
c.Default = "0"
}
case core.Serial:

View file

@ -551,9 +551,12 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
if len(charset) == 0 {
charset = db.URI().Charset
} else if len(charset) > 0 {
}
if len(charset) != 0 {
sql += " DEFAULT CHARSET " + charset
}
if db.rowFormat != "" {
sql += " ROW_FORMAT=" + db.rowFormat

View file

@ -233,7 +233,7 @@ func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
}
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
//var unique string
// var unique string
quote := db.Quote
idxName := index.Name
@ -452,5 +452,9 @@ type sqlite3Driver struct {
}
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
if strings.Contains(dataSourceName, "?") {
dataSourceName = dataSourceName[:strings.Index(dataSourceName, "?")]
}
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
}

View file

@ -177,6 +177,14 @@ func (engine *Engine) QuoteStr() string {
return engine.dialect.QuoteStr()
}
func (engine *Engine) quoteColumns(columnStr string) string {
columns := strings.Split(columnStr, ",")
for i := 0; i < len(columns); i++ {
columns[i] = engine.Quote(strings.TrimSpace(columns[i]))
}
return strings.Join(columns, ",")
}
// Quote Use QuoteStr quote the string sql
func (engine *Engine) Quote(value string) string {
value = strings.TrimSpace(value)
@ -237,6 +245,11 @@ func (engine *Engine) AutoIncrStr() string {
return engine.dialect.AutoIncrStr()
}
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.db.SetConnMaxLifetime(d)
}
// SetMaxOpenConns is only available for go 1.2+
func (engine *Engine) SetMaxOpenConns(conns int) {
engine.db.SetMaxOpenConns(conns)
@ -1333,10 +1346,10 @@ func (engine *Engine) DropIndexes(bean interface{}) error {
}
// Exec raw sql
func (engine *Engine) Exec(sql string, args ...interface{}) (sql.Result, error) {
func (engine *Engine) Exec(sqlorArgs ...interface{}) (sql.Result, error) {
session := engine.NewSession()
defer session.Close()
return session.Exec(sql, args...)
return session.Exec(sqlorArgs...)
}
// Query a raw sql and return records as []map[string][]byte

View file

@ -5,6 +5,8 @@
package xorm
import (
"time"
"github.com/go-xorm/core"
)
@ -99,6 +101,14 @@ func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) {
}
}
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
eg.Engine.SetConnMaxLifetime(d)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetConnMaxLifetime(d)
}
}
// SetDefaultCacher set the default cacher
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
eg.Engine.SetDefaultCacher(cacher)

View file

@ -1,22 +0,0 @@
// 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.
// +build go1.6
package xorm
import "time"
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.db.SetConnMaxLifetime(d)
}
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
eg.Engine.SetConnMaxLifetime(d)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetConnMaxLifetime(d)
}
}

View file

@ -27,7 +27,7 @@ type Interface interface {
Delete(interface{}) (int64, error)
Distinct(columns ...string) *Session
DropIndexes(bean interface{}) error
Exec(string, ...interface{}) (sql.Result, error)
Exec(sqlOrAgrs ...interface{}) (sql.Result, error)
Exist(bean ...interface{}) (bool, error)
Find(interface{}, ...interface{}) error
FindAndCount(interface{}, ...interface{}) (int64, error)
@ -72,6 +72,7 @@ type EngineInterface interface {
Before(func(interface{})) *Session
Charset(charset string) *Session
ClearCache(...interface{}) error
CreateTables(...interface{}) error
DBMetas() ([]*core.Table, error)
Dialect() core.Dialect
@ -83,16 +84,22 @@ type EngineInterface interface {
GetTableMapper() core.IMapper
GetTZDatabase() *time.Location
GetTZLocation() *time.Location
MapCacher(interface{}, core.Cacher) error
NewSession() *Session
NoAutoTime() *Session
Quote(string) string
SetCacher(string, core.Cacher)
SetConnMaxLifetime(time.Duration)
SetDefaultCacher(core.Cacher)
SetLogger(logger core.ILogger)
SetLogLevel(core.LogLevel)
SetMapper(core.IMapper)
SetMaxOpenConns(int)
SetMaxIdleConns(int)
SetSchema(string)
SetTZDatabase(tz *time.Location)
SetTZLocation(tz *time.Location)
ShowExecTime(...bool)
ShowSQL(show ...bool)
Sync(...interface{}) error
Sync2(...interface{}) error

View file

@ -102,6 +102,12 @@ func (session *Session) Close() {
}
}
// ContextCache enable context cache or not
func (session *Session) ContextCache(context ContextCache) *Session {
session.statement.context = context
return session
}
// IsClosed returns if session is closed
func (session *Session) IsClosed() bool {
return session.db == nil
@ -839,3 +845,12 @@ func (session *Session) Unscoped() *Session {
session.statement.Unscoped()
return session
}
func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) {
switch fieldValue.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
fieldValue.SetInt(fieldValue.Int() + 1)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
fieldValue.SetUint(fieldValue.Uint() + 1)
}
}

View file

@ -199,7 +199,7 @@ func (session *Session) Delete(bean interface{}) (int64, error) {
})
}
if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
if cacher := session.engine.getCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache {
session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
}

View file

@ -135,7 +135,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
if session.statement.JoinStr == "" {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
} else {
columnStr = session.statement.genColumnStr()
}
@ -143,7 +143,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
} else {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
} else {
columnStr = "*"
}
@ -176,7 +176,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
}
if session.canCache() {
if cacher := session.engine.getCacher(table.Name); cacher != nil &&
if cacher := session.engine.getCacher(session.statement.TableName()); cacher != nil &&
!session.statement.IsDistinct &&
!session.statement.unscoped {
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)

View file

@ -7,6 +7,7 @@ package xorm
import (
"database/sql"
"errors"
"fmt"
"reflect"
"strconv"
@ -57,7 +58,7 @@ func (session *Session) get(bean interface{}) (bool, error) {
table := session.statement.RefTable
if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
if cacher := session.engine.getCacher(table.Name); cacher != nil &&
if cacher := session.engine.getCacher(session.statement.TableName()); cacher != nil &&
!session.statement.unscoped {
has, err := session.cacheGet(bean, sqlStr, args...)
if err != ErrCacheFailed {
@ -66,7 +67,28 @@ func (session *Session) get(bean interface{}) (bool, error) {
}
}
return session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
context := session.statement.context
if context != nil {
res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
if res != nil {
structValue := reflect.Indirect(reflect.ValueOf(bean))
structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
session.lastSQL = ""
session.lastSQLArgs = nil
return true, nil
}
}
has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
if err != nil || !has {
return has, err
}
if context != nil {
context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean)
}
return true, nil
}
func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
@ -77,6 +99,9 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bea
defer rows.Close()
if !rows.Next() {
if rows.Err() != nil {
return false, rows.Err()
}
return false, nil
}

View file

@ -397,7 +397,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
if err != nil {
session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
session.incrVersionFieldValue(verValue)
}
}
@ -440,7 +440,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
if err != nil {
session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
session.incrVersionFieldValue(verValue)
}
}
@ -481,7 +481,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
if err != nil {
session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
session.incrVersionFieldValue(verValue)
}
}

View file

@ -17,17 +17,7 @@ import (
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
if len(sqlorArgs) > 0 {
switch sqlorArgs[0].(type) {
case string:
return sqlorArgs[0].(string), sqlorArgs[1:], nil
case *builder.Builder:
return sqlorArgs[0].(*builder.Builder).ToSQL()
case builder.Builder:
bd := sqlorArgs[0].(builder.Builder)
return bd.ToSQL()
default:
return "", nil, ErrUnSupportedType
}
return convertSQLOrArgs(sqlorArgs...)
}
if session.statement.RawSQL != "" {
@ -45,7 +35,7 @@ func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interfa
if session.statement.JoinStr == "" {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
} else {
columnStr = session.statement.genColumnStr()
}
@ -53,7 +43,7 @@ func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interfa
} else {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
} else {
columnStr = "*"
}
@ -176,6 +166,34 @@ func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string,
return result, nil
}
func row2sliceStr(rows *core.Rows, fields []string) (results []string, err error) {
result := make([]string, 0, 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 i := 0; i < len(fields); i++ {
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[i]))
// if row is null then as empty string
if rawValue.Interface() == nil {
result = append(result, "")
continue
}
if data, err := value2String(&rawValue); err == nil {
result = append(result, 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 {
@ -192,6 +210,22 @@ func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error)
return resultsSlice, nil
}
func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
for rows.Next() {
record, err := row2sliceStr(rows, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, record)
}
return resultsSlice, nil
}
// QueryString runs a raw sql and return records as []map[string]string
func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) {
if session.isAutoClose {
@ -212,6 +246,26 @@ func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]stri
return rows2Strings(rows)
}
// QuerySliceString runs a raw sql and return records as [][]string
func (session *Session) QuerySliceString(sqlorArgs ...interface{}) ([][]string, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return rows2SliceString(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))

View file

@ -9,6 +9,7 @@ import (
"reflect"
"time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
@ -193,11 +194,34 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er
return session.DB().Exec(sqlStr, args...)
}
func convertSQLOrArgs(sqlorArgs ...interface{}) (string, []interface{}, error) {
switch sqlorArgs[0].(type) {
case string:
return sqlorArgs[0].(string), sqlorArgs[1:], nil
case *builder.Builder:
return sqlorArgs[0].(*builder.Builder).ToSQL()
case builder.Builder:
bd := sqlorArgs[0].(builder.Builder)
return bd.ToSQL()
}
return "", nil, ErrUnSupportedType
}
// Exec raw sql
func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
func (session *Session) Exec(sqlorArgs ...interface{}) (sql.Result, error) {
if session.isAutoClose {
defer session.Close()
}
if len(sqlorArgs) == 0 {
return nil, ErrUnSupportedType
}
sqlStr, args, err := convertSQLOrArgs(sqlorArgs...)
if err != nil {
return nil, err
}
return session.exec(sqlStr, args...)
}

View file

@ -116,7 +116,7 @@ func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string,
} else {
session.engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
if col.IsVersion && session.statement.checkVersion {
fieldValue.SetInt(fieldValue.Int() + 1)
session.incrVersionFieldValue(fieldValue)
} else {
fieldValue.Set(reflect.ValueOf(args[idx]))
}
@ -357,7 +357,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
return 0, err
} else if doIncVer {
if verValue != nil && verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(verValue.Int() + 1)
session.incrVersionFieldValue(verValue)
}
}
@ -443,7 +443,7 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac
}
}
if col.IsDeleted || col.IsCreated {
if (col.IsDeleted && !session.statement.unscoped) || col.IsCreated {
continue
}

View file

@ -59,6 +59,7 @@ type Statement struct {
exprColumns map[string]exprParam
cond builder.Cond
bufferSize int
context ContextCache
}
// Init reset all the statement's fields
@ -99,6 +100,7 @@ func (statement *Statement) Init() {
statement.exprColumns = make(map[string]exprParam)
statement.cond = builder.NewCond()
statement.bufferSize = 0
statement.context = nil
}
// NoAutoCondition if you do not want convert bean's field as query condition, then use this function
@ -933,7 +935,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
if len(statement.JoinStr) == 0 {
if len(columnStr) == 0 {
if len(statement.GroupByStr) > 0 {
columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
columnStr = statement.Engine.quoteColumns(statement.GroupByStr)
} else {
columnStr = statement.genColumnStr()
}
@ -941,7 +943,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
} else {
if len(columnStr) == 0 {
if len(statement.GroupByStr) > 0 {
columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
columnStr = statement.Engine.quoteColumns(statement.GroupByStr)
}
}
}

26
vendor/github.com/go-xorm/xorm/transaction.go generated vendored Normal file
View file

@ -0,0 +1,26 @@
// Copyright 2018 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
// Transaction Execute sql wrapped in a transaction(abbr as tx), tx will automatic commit if no errors occurred
func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interface{}, error) {
session := engine.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
return nil, err
}
result, err := f(session)
if err != nil {
return nil, err
}
if err := session.Commit(); err != nil {
return nil, err
}
return result, nil
}

View file

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.8
package xorm
import (