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:
parent
b1f3685015
commit
6db7dbd333
23
.drone.yml
23
.drone.yml
|
@ -176,6 +176,20 @@ pipeline:
|
||||||
when:
|
when:
|
||||||
event: [ push, tag, pull_request ]
|
event: [ push, tag, pull_request ]
|
||||||
|
|
||||||
|
test-mssql:
|
||||||
|
image: golang:1.10
|
||||||
|
pull: true
|
||||||
|
group: test
|
||||||
|
environment:
|
||||||
|
TAGS: bindata
|
||||||
|
TEST_LDAP: "1"
|
||||||
|
commands:
|
||||||
|
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
|
||||||
|
- apt-get install -y git-lfs
|
||||||
|
- make test-mssql
|
||||||
|
when:
|
||||||
|
event: [ push, tag, pull_request ]
|
||||||
|
|
||||||
generate-coverage:
|
generate-coverage:
|
||||||
image: golang:1.11
|
image: golang:1.11
|
||||||
pull: true
|
pull: true
|
||||||
|
@ -347,6 +361,15 @@ services:
|
||||||
when:
|
when:
|
||||||
event: [ push, tag, pull_request ]
|
event: [ push, tag, pull_request ]
|
||||||
|
|
||||||
|
mssql:
|
||||||
|
image: microsoft/mssql-server-linux:latest
|
||||||
|
environment:
|
||||||
|
- ACCEPT_EULA=Y
|
||||||
|
- SA_PASSWORD=MwantsaSecurePassword1
|
||||||
|
- MSSQL_PID=Standard
|
||||||
|
when:
|
||||||
|
event: [ push, tag, pull_request ]
|
||||||
|
|
||||||
ldap:
|
ldap:
|
||||||
image: gitea/test-openldap:latest
|
image: gitea/test-openldap:latest
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -53,11 +53,14 @@ coverage.all
|
||||||
/integrations/gitea-integration-mysql
|
/integrations/gitea-integration-mysql
|
||||||
/integrations/gitea-integration-pgsql
|
/integrations/gitea-integration-pgsql
|
||||||
/integrations/gitea-integration-sqlite
|
/integrations/gitea-integration-sqlite
|
||||||
|
/integrations/gitea-integration-mssql
|
||||||
/integrations/indexers-mysql
|
/integrations/indexers-mysql
|
||||||
/integrations/indexers-pgsql
|
/integrations/indexers-pgsql
|
||||||
/integrations/indexers-sqlite
|
/integrations/indexers-sqlite
|
||||||
|
/integrations/indexers-mssql
|
||||||
/integrations/mysql.ini
|
/integrations/mysql.ini
|
||||||
/integrations/pgsql.ini
|
/integrations/pgsql.ini
|
||||||
|
/integrations/mssql.ini
|
||||||
/node_modules
|
/node_modules
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -406,11 +406,11 @@
|
||||||
version = "v0.6.0"
|
version = "v0.6.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:22a1ac7f654095f6817076eb975368bab5481e42554d0121ea37e28a86a3f83d"
|
digest = "1:931a62a1aacc37a5e4c309a111642ec4da47b4dc453cd4ba5481b12eedb04a5d"
|
||||||
name = "github.com/go-xorm/xorm"
|
name = "github.com/go-xorm/xorm"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
|
revision = "401f4ee8ff8cbc40a4754cb12192fbe4f02f3979"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
|
|
@ -38,8 +38,7 @@ ignored = ["google.golang.org/appengine*"]
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/go-xorm/xorm"
|
name = "github.com/go-xorm/xorm"
|
||||||
#version = "0.6.5"
|
revision = "401f4ee8ff8cbc40a4754cb12192fbe4f02f3979"
|
||||||
revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
|
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/go-sql-driver/mysql"
|
name = "github.com/go-sql-driver/mysql"
|
||||||
|
|
19
Makefile
19
Makefile
|
@ -54,6 +54,10 @@ TEST_PGSQL_HOST ?= pgsql:5432
|
||||||
TEST_PGSQL_DBNAME ?= testgitea
|
TEST_PGSQL_DBNAME ?= testgitea
|
||||||
TEST_PGSQL_USERNAME ?= postgres
|
TEST_PGSQL_USERNAME ?= postgres
|
||||||
TEST_PGSQL_PASSWORD ?= postgres
|
TEST_PGSQL_PASSWORD ?= postgres
|
||||||
|
TEST_MSSQL_HOST ?= mssql:1433
|
||||||
|
TEST_MSSQL_DBNAME ?= gitea
|
||||||
|
TEST_MSSQL_USERNAME ?= sa
|
||||||
|
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
|
||||||
|
|
||||||
ifeq ($(OS), Windows_NT)
|
ifeq ($(OS), Windows_NT)
|
||||||
EXECUTABLE := gitea.exe
|
EXECUTABLE := gitea.exe
|
||||||
|
@ -74,9 +78,9 @@ clean:
|
||||||
$(GO) clean -i ./...
|
$(GO) clean -i ./...
|
||||||
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA) \
|
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA) \
|
||||||
integrations*.test \
|
integrations*.test \
|
||||||
integrations/gitea-integration-pgsql/ integrations/gitea-integration-mysql/ integrations/gitea-integration-sqlite/ \
|
integrations/gitea-integration-pgsql/ integrations/gitea-integration-mysql/ integrations/gitea-integration-sqlite/ integrations/gitea-integration-mssql/ \
|
||||||
integrations/indexers-mysql/ integrations/indexers-pgsql integrations/indexers-sqlite \
|
integrations/indexers-mysql/ integrations/indexers-pgsql integrations/indexers-sqlite integrations/indexers-mssql \
|
||||||
integrations/mysql.ini integrations/pgsql.ini
|
integrations/mysql.ini integrations/pgsql.ini integrations/mssql.ini
|
||||||
|
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt:
|
fmt:
|
||||||
|
@ -204,6 +208,11 @@ generate-ini:
|
||||||
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
|
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
|
||||||
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
|
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
|
||||||
integrations/pgsql.ini.tmpl > integrations/pgsql.ini
|
integrations/pgsql.ini.tmpl > integrations/pgsql.ini
|
||||||
|
sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
|
||||||
|
-e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \
|
||||||
|
-e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \
|
||||||
|
-e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \
|
||||||
|
integrations/mssql.ini.tmpl > integrations/mssql.ini
|
||||||
|
|
||||||
.PHONY: test-mysql
|
.PHONY: test-mysql
|
||||||
test-mysql: integrations.test generate-ini
|
test-mysql: integrations.test generate-ini
|
||||||
|
@ -213,6 +222,10 @@ test-mysql: integrations.test generate-ini
|
||||||
test-pgsql: integrations.test generate-ini
|
test-pgsql: integrations.test generate-ini
|
||||||
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.test
|
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.test
|
||||||
|
|
||||||
|
.PHONY: test-mssql
|
||||||
|
test-mssql: integrations.test generate-ini
|
||||||
|
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.test
|
||||||
|
|
||||||
.PHONY: bench-sqlite
|
.PHONY: bench-sqlite
|
||||||
bench-sqlite: integrations.sqlite.test
|
bench-sqlite: integrations.sqlite.test
|
||||||
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||||
|
|
|
@ -47,6 +47,8 @@ func TestMain(m *testing.M) {
|
||||||
helper = &testfixtures.PostgreSQL{}
|
helper = &testfixtures.PostgreSQL{}
|
||||||
} else if setting.UseSQLite3 {
|
} else if setting.UseSQLite3 {
|
||||||
helper = &testfixtures.SQLite{}
|
helper = &testfixtures.SQLite{}
|
||||||
|
} else if setting.UseMSSQL {
|
||||||
|
helper = &testfixtures.SQLServer{}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Unsupported RDBMS for integration tests")
|
fmt.Println("Unsupported RDBMS for integration tests")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -130,6 +132,17 @@ func initIntegrationTest() {
|
||||||
if _, err = db.Exec("CREATE DATABASE testgitea"); err != nil {
|
if _, err = db.Exec("CREATE DATABASE testgitea"); err != nil {
|
||||||
log.Fatalf("db.Exec: %v", err)
|
log.Fatalf("db.Exec: %v", err)
|
||||||
}
|
}
|
||||||
|
case setting.UseMSSQL:
|
||||||
|
host, port := models.ParseMSSQLHostPort(models.DbCfg.Host)
|
||||||
|
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
|
||||||
|
host, port, "master", models.DbCfg.User, models.DbCfg.Passwd))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("sql.Open: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := db.Exec("If(db_id(N'gitea') IS NULL) BEGIN CREATE DATABASE gitea; END;"); err != nil {
|
||||||
|
log.Fatalf("db.Exec: %v", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
}
|
}
|
||||||
routers.GlobalInit()
|
routers.GlobalInit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
APP_NAME = Gitea: Git with a cup of tea
|
||||||
|
RUN_MODE = prod
|
||||||
|
|
||||||
|
[database]
|
||||||
|
DB_TYPE = mssql
|
||||||
|
HOST = {{TEST_MSSQL_HOST}}
|
||||||
|
NAME = {{TEST_MSSQL_DBNAME}}
|
||||||
|
USER = {{TEST_MSSQL_USERNAME}}
|
||||||
|
PASSWD = {{TEST_MSSQL_PASSWORD}}
|
||||||
|
SSL_MODE = disable
|
||||||
|
|
||||||
|
[indexer]
|
||||||
|
ISSUE_INDEXER_PATH = integrations/indexers-mssql/issues.bleve
|
||||||
|
REPO_INDEXER_ENABLED = true
|
||||||
|
REPO_INDEXER_PATH = integrations/indexers-mssql/repos.bleve
|
||||||
|
|
||||||
|
[repository]
|
||||||
|
ROOT = integrations/gitea-integration-mssql/gitea-repositories
|
||||||
|
|
||||||
|
[repository.local]
|
||||||
|
LOCAL_COPY_PATH = tmp/local-repo-mssql
|
||||||
|
LOCAL_WIKI_PATH = tmp/local-wiki-mssql
|
||||||
|
|
||||||
|
[server]
|
||||||
|
SSH_DOMAIN = localhost
|
||||||
|
HTTP_PORT = 3003
|
||||||
|
ROOT_URL = http://localhost:3003/
|
||||||
|
DISABLE_SSH = false
|
||||||
|
SSH_LISTEN_HOST = localhost
|
||||||
|
SSH_PORT = 2201
|
||||||
|
START_SSH_SERVER = true
|
||||||
|
LFS_START_SERVER = true
|
||||||
|
LFS_CONTENT_PATH = data/lfs-mssql
|
||||||
|
OFFLINE_MODE = false
|
||||||
|
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
|
||||||
|
APP_DATA_PATH = integrations/gitea-integration-mssql/data
|
||||||
|
|
||||||
|
[mailer]
|
||||||
|
ENABLED = false
|
||||||
|
|
||||||
|
[service]
|
||||||
|
REGISTER_EMAIL_CONFIRM = false
|
||||||
|
ENABLE_NOTIFY_MAIL = false
|
||||||
|
DISABLE_REGISTRATION = false
|
||||||
|
ENABLE_CAPTCHA = false
|
||||||
|
REQUIRE_SIGNIN_VIEW = false
|
||||||
|
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||||
|
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||||
|
NO_REPLY_ADDRESS = noreply.example.org
|
||||||
|
|
||||||
|
[picture]
|
||||||
|
DISABLE_GRAVATAR = false
|
||||||
|
ENABLE_FEDERATED_AVATAR = false
|
||||||
|
|
||||||
|
[session]
|
||||||
|
PROVIDER = file
|
||||||
|
PROVIDER_CONFIG = data/sessions-mssql
|
||||||
|
|
||||||
|
[log]
|
||||||
|
MODE = console,file
|
||||||
|
ROOT_PATH = mssql-log
|
||||||
|
|
||||||
|
[log.console]
|
||||||
|
LEVEL = Warn
|
||||||
|
|
||||||
|
[log.file]
|
||||||
|
LEVEL = Debug
|
||||||
|
|
||||||
|
[security]
|
||||||
|
INSTALL_LOCK = true
|
||||||
|
SECRET_KEY = 9pCviYTWSb
|
||||||
|
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
|
|
@ -36,7 +36,7 @@ type Engine interface {
|
||||||
Count(...interface{}) (int64, error)
|
Count(...interface{}) (int64, error)
|
||||||
Decr(column string, arg ...interface{}) *xorm.Session
|
Decr(column string, arg ...interface{}) *xorm.Session
|
||||||
Delete(interface{}) (int64, error)
|
Delete(interface{}) (int64, error)
|
||||||
Exec(string, ...interface{}) (sql.Result, error)
|
Exec(...interface{}) (sql.Result, error)
|
||||||
Find(interface{}, ...interface{}) error
|
Find(interface{}, ...interface{}) error
|
||||||
Get(interface{}) (bool, error)
|
Get(interface{}) (bool, error)
|
||||||
ID(interface{}) *xorm.Session
|
ID(interface{}) *xorm.Session
|
||||||
|
@ -200,7 +200,8 @@ func getPostgreSQLConnectionString(DBHost, DBUser, DBPasswd, DBName, DBParam, DB
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseMSSQLHostPort(info string) (string, string) {
|
// ParseMSSQLHostPort splits the host into host and port
|
||||||
|
func ParseMSSQLHostPort(info string) (string, string) {
|
||||||
host, port := "127.0.0.1", "1433"
|
host, port := "127.0.0.1", "1433"
|
||||||
if strings.Contains(info, ":") {
|
if strings.Contains(info, ":") {
|
||||||
host = strings.Split(info, ":")[0]
|
host = strings.Split(info, ":")[0]
|
||||||
|
@ -235,7 +236,7 @@ func getEngine() (*xorm.Engine, error) {
|
||||||
case "postgres":
|
case "postgres":
|
||||||
connStr = getPostgreSQLConnectionString(DbCfg.Host, DbCfg.User, DbCfg.Passwd, DbCfg.Name, Param, DbCfg.SSLMode)
|
connStr = getPostgreSQLConnectionString(DbCfg.Host, DbCfg.User, DbCfg.Passwd, DbCfg.Name, Param, DbCfg.SSLMode)
|
||||||
case "mssql":
|
case "mssql":
|
||||||
host, port := parseMSSQLHostPort(DbCfg.Host)
|
host, port := ParseMSSQLHostPort(DbCfg.Host)
|
||||||
connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, DbCfg.Name, DbCfg.User, DbCfg.Passwd)
|
connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, DbCfg.Name, DbCfg.User, DbCfg.Passwd)
|
||||||
case "sqlite3":
|
case "sqlite3":
|
||||||
if !EnableSQLite3 {
|
if !EnableSQLite3 {
|
||||||
|
|
|
@ -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]
|
||||||
|
}
|
|
@ -218,7 +218,7 @@ func (db *mssql) SqlType(c *core.Column) string {
|
||||||
res = core.Bit
|
res = core.Bit
|
||||||
if strings.EqualFold(c.Default, "true") {
|
if strings.EqualFold(c.Default, "true") {
|
||||||
c.Default = "1"
|
c.Default = "1"
|
||||||
} else {
|
} else if strings.EqualFold(c.Default, "false") {
|
||||||
c.Default = "0"
|
c.Default = "0"
|
||||||
}
|
}
|
||||||
case core.Serial:
|
case core.Serial:
|
||||||
|
|
|
@ -551,10 +551,13 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
|
||||||
|
|
||||||
if len(charset) == 0 {
|
if len(charset) == 0 {
|
||||||
charset = db.URI().Charset
|
charset = db.URI().Charset
|
||||||
} else if len(charset) > 0 {
|
}
|
||||||
|
if len(charset) != 0 {
|
||||||
sql += " DEFAULT CHARSET " + charset
|
sql += " DEFAULT CHARSET " + charset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if db.rowFormat != "" {
|
if db.rowFormat != "" {
|
||||||
sql += " ROW_FORMAT=" + db.rowFormat
|
sql += " ROW_FORMAT=" + db.rowFormat
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,7 @@ func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
|
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
|
||||||
//var unique string
|
// var unique string
|
||||||
quote := db.Quote
|
quote := db.Quote
|
||||||
idxName := index.Name
|
idxName := index.Name
|
||||||
|
|
||||||
|
@ -452,5 +452,9 @@ type sqlite3Driver struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
|
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
|
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,6 +177,14 @@ func (engine *Engine) QuoteStr() string {
|
||||||
return engine.dialect.QuoteStr()
|
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
|
// Quote Use QuoteStr quote the string sql
|
||||||
func (engine *Engine) Quote(value string) string {
|
func (engine *Engine) Quote(value string) string {
|
||||||
value = strings.TrimSpace(value)
|
value = strings.TrimSpace(value)
|
||||||
|
@ -237,6 +245,11 @@ func (engine *Engine) AutoIncrStr() string {
|
||||||
return engine.dialect.AutoIncrStr()
|
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+
|
// SetMaxOpenConns is only available for go 1.2+
|
||||||
func (engine *Engine) SetMaxOpenConns(conns int) {
|
func (engine *Engine) SetMaxOpenConns(conns int) {
|
||||||
engine.db.SetMaxOpenConns(conns)
|
engine.db.SetMaxOpenConns(conns)
|
||||||
|
@ -1333,10 +1346,10 @@ func (engine *Engine) DropIndexes(bean interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec raw sql
|
// 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()
|
session := engine.NewSession()
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
return session.Exec(sql, args...)
|
return session.Exec(sqlorArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query a raw sql and return records as []map[string][]byte
|
// Query a raw sql and return records as []map[string][]byte
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-xorm/core"
|
"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
|
// SetDefaultCacher set the default cacher
|
||||||
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
|
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
|
||||||
eg.Engine.SetDefaultCacher(cacher)
|
eg.Engine.SetDefaultCacher(cacher)
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,7 +27,7 @@ type Interface interface {
|
||||||
Delete(interface{}) (int64, error)
|
Delete(interface{}) (int64, error)
|
||||||
Distinct(columns ...string) *Session
|
Distinct(columns ...string) *Session
|
||||||
DropIndexes(bean interface{}) error
|
DropIndexes(bean interface{}) error
|
||||||
Exec(string, ...interface{}) (sql.Result, error)
|
Exec(sqlOrAgrs ...interface{}) (sql.Result, error)
|
||||||
Exist(bean ...interface{}) (bool, error)
|
Exist(bean ...interface{}) (bool, error)
|
||||||
Find(interface{}, ...interface{}) error
|
Find(interface{}, ...interface{}) error
|
||||||
FindAndCount(interface{}, ...interface{}) (int64, error)
|
FindAndCount(interface{}, ...interface{}) (int64, error)
|
||||||
|
@ -72,6 +72,7 @@ type EngineInterface interface {
|
||||||
|
|
||||||
Before(func(interface{})) *Session
|
Before(func(interface{})) *Session
|
||||||
Charset(charset string) *Session
|
Charset(charset string) *Session
|
||||||
|
ClearCache(...interface{}) error
|
||||||
CreateTables(...interface{}) error
|
CreateTables(...interface{}) error
|
||||||
DBMetas() ([]*core.Table, error)
|
DBMetas() ([]*core.Table, error)
|
||||||
Dialect() core.Dialect
|
Dialect() core.Dialect
|
||||||
|
@ -83,16 +84,22 @@ type EngineInterface interface {
|
||||||
GetTableMapper() core.IMapper
|
GetTableMapper() core.IMapper
|
||||||
GetTZDatabase() *time.Location
|
GetTZDatabase() *time.Location
|
||||||
GetTZLocation() *time.Location
|
GetTZLocation() *time.Location
|
||||||
|
MapCacher(interface{}, core.Cacher) error
|
||||||
NewSession() *Session
|
NewSession() *Session
|
||||||
NoAutoTime() *Session
|
NoAutoTime() *Session
|
||||||
Quote(string) string
|
Quote(string) string
|
||||||
SetCacher(string, core.Cacher)
|
SetCacher(string, core.Cacher)
|
||||||
|
SetConnMaxLifetime(time.Duration)
|
||||||
SetDefaultCacher(core.Cacher)
|
SetDefaultCacher(core.Cacher)
|
||||||
|
SetLogger(logger core.ILogger)
|
||||||
SetLogLevel(core.LogLevel)
|
SetLogLevel(core.LogLevel)
|
||||||
SetMapper(core.IMapper)
|
SetMapper(core.IMapper)
|
||||||
|
SetMaxOpenConns(int)
|
||||||
|
SetMaxIdleConns(int)
|
||||||
SetSchema(string)
|
SetSchema(string)
|
||||||
SetTZDatabase(tz *time.Location)
|
SetTZDatabase(tz *time.Location)
|
||||||
SetTZLocation(tz *time.Location)
|
SetTZLocation(tz *time.Location)
|
||||||
|
ShowExecTime(...bool)
|
||||||
ShowSQL(show ...bool)
|
ShowSQL(show ...bool)
|
||||||
Sync(...interface{}) error
|
Sync(...interface{}) error
|
||||||
Sync2(...interface{}) error
|
Sync2(...interface{}) error
|
||||||
|
|
|
@ -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
|
// IsClosed returns if session is closed
|
||||||
func (session *Session) IsClosed() bool {
|
func (session *Session) IsClosed() bool {
|
||||||
return session.db == nil
|
return session.db == nil
|
||||||
|
@ -839,3 +845,12 @@ func (session *Session) Unscoped() *Session {
|
||||||
session.statement.Unscoped()
|
session.statement.Unscoped()
|
||||||
return session
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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...)
|
session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||||
if session.statement.JoinStr == "" {
|
if session.statement.JoinStr == "" {
|
||||||
if columnStr == "" {
|
if columnStr == "" {
|
||||||
if session.statement.GroupByStr != "" {
|
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 {
|
} else {
|
||||||
columnStr = session.statement.genColumnStr()
|
columnStr = session.statement.genColumnStr()
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||||
} else {
|
} else {
|
||||||
if columnStr == "" {
|
if columnStr == "" {
|
||||||
if session.statement.GroupByStr != "" {
|
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 {
|
} else {
|
||||||
columnStr = "*"
|
columnStr = "*"
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
if session.canCache() {
|
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.IsDistinct &&
|
||||||
!session.statement.unscoped {
|
!session.statement.unscoped {
|
||||||
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
|
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
|
||||||
|
|
|
@ -7,6 +7,7 @@ package xorm
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ func (session *Session) get(bean interface{}) (bool, error) {
|
||||||
table := session.statement.RefTable
|
table := session.statement.RefTable
|
||||||
|
|
||||||
if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
|
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 {
|
!session.statement.unscoped {
|
||||||
has, err := session.cacheGet(bean, sqlStr, args...)
|
has, err := session.cacheGet(bean, sqlStr, args...)
|
||||||
if err != ErrCacheFailed {
|
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) {
|
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()
|
defer rows.Close()
|
||||||
|
|
||||||
if !rows.Next() {
|
if !rows.Next() {
|
||||||
|
if rows.Err() != nil {
|
||||||
|
return false, rows.Err()
|
||||||
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -397,7 +397,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.engine.logger.Error(err)
|
session.engine.logger.Error(err)
|
||||||
} else if verValue.IsValid() && verValue.CanSet() {
|
} 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 {
|
if err != nil {
|
||||||
session.engine.logger.Error(err)
|
session.engine.logger.Error(err)
|
||||||
} else if verValue.IsValid() && verValue.CanSet() {
|
} 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 {
|
if err != nil {
|
||||||
session.engine.logger.Error(err)
|
session.engine.logger.Error(err)
|
||||||
} else if verValue.IsValid() && verValue.CanSet() {
|
} else if verValue.IsValid() && verValue.CanSet() {
|
||||||
verValue.SetInt(1)
|
session.incrVersionFieldValue(verValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,7 @@ import (
|
||||||
|
|
||||||
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
|
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
|
||||||
if len(sqlorArgs) > 0 {
|
if len(sqlorArgs) > 0 {
|
||||||
switch sqlorArgs[0].(type) {
|
return convertSQLOrArgs(sqlorArgs...)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if session.statement.RawSQL != "" {
|
if session.statement.RawSQL != "" {
|
||||||
|
@ -45,7 +35,7 @@ func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interfa
|
||||||
if session.statement.JoinStr == "" {
|
if session.statement.JoinStr == "" {
|
||||||
if columnStr == "" {
|
if columnStr == "" {
|
||||||
if session.statement.GroupByStr != "" {
|
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 {
|
} else {
|
||||||
columnStr = session.statement.genColumnStr()
|
columnStr = session.statement.genColumnStr()
|
||||||
}
|
}
|
||||||
|
@ -53,7 +43,7 @@ func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interfa
|
||||||
} else {
|
} else {
|
||||||
if columnStr == "" {
|
if columnStr == "" {
|
||||||
if session.statement.GroupByStr != "" {
|
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 {
|
} else {
|
||||||
columnStr = "*"
|
columnStr = "*"
|
||||||
}
|
}
|
||||||
|
@ -176,6 +166,34 @@ func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string,
|
||||||
return result, nil
|
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) {
|
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
|
||||||
fields, err := rows.Columns()
|
fields, err := rows.Columns()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -192,6 +210,22 @@ func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error)
|
||||||
return resultsSlice, nil
|
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
|
// QueryString runs a raw sql and return records as []map[string]string
|
||||||
func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) {
|
func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]string, error) {
|
||||||
if session.isAutoClose {
|
if session.isAutoClose {
|
||||||
|
@ -212,6 +246,26 @@ func (session *Session) QueryString(sqlorArgs ...interface{}) ([]map[string]stri
|
||||||
return rows2Strings(rows)
|
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) {
|
func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
|
||||||
resultsMap = make(map[string]interface{}, len(fields))
|
resultsMap = make(map[string]interface{}, len(fields))
|
||||||
scanResultContainers := make([]interface{}, len(fields))
|
scanResultContainers := make([]interface{}, len(fields))
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-xorm/builder"
|
||||||
"github.com/go-xorm/core"
|
"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...)
|
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
|
// 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 {
|
if session.isAutoClose {
|
||||||
defer session.Close()
|
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...)
|
return session.exec(sqlStr, args...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string,
|
||||||
} else {
|
} else {
|
||||||
session.engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
|
session.engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
|
||||||
if col.IsVersion && session.statement.checkVersion {
|
if col.IsVersion && session.statement.checkVersion {
|
||||||
fieldValue.SetInt(fieldValue.Int() + 1)
|
session.incrVersionFieldValue(fieldValue)
|
||||||
} else {
|
} else {
|
||||||
fieldValue.Set(reflect.ValueOf(args[idx]))
|
fieldValue.Set(reflect.ValueOf(args[idx]))
|
||||||
}
|
}
|
||||||
|
@ -357,7 +357,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
|
||||||
return 0, err
|
return 0, err
|
||||||
} else if doIncVer {
|
} else if doIncVer {
|
||||||
if verValue != nil && verValue.IsValid() && verValue.CanSet() {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ type Statement struct {
|
||||||
exprColumns map[string]exprParam
|
exprColumns map[string]exprParam
|
||||||
cond builder.Cond
|
cond builder.Cond
|
||||||
bufferSize int
|
bufferSize int
|
||||||
|
context ContextCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init reset all the statement's fields
|
// Init reset all the statement's fields
|
||||||
|
@ -99,6 +100,7 @@ func (statement *Statement) Init() {
|
||||||
statement.exprColumns = make(map[string]exprParam)
|
statement.exprColumns = make(map[string]exprParam)
|
||||||
statement.cond = builder.NewCond()
|
statement.cond = builder.NewCond()
|
||||||
statement.bufferSize = 0
|
statement.bufferSize = 0
|
||||||
|
statement.context = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoAutoCondition if you do not want convert bean's field as query condition, then use this function
|
// 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(statement.JoinStr) == 0 {
|
||||||
if len(columnStr) == 0 {
|
if len(columnStr) == 0 {
|
||||||
if len(statement.GroupByStr) > 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 {
|
} else {
|
||||||
columnStr = statement.genColumnStr()
|
columnStr = statement.genColumnStr()
|
||||||
}
|
}
|
||||||
|
@ -941,7 +943,7 @@ func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{},
|
||||||
} else {
|
} else {
|
||||||
if len(columnStr) == 0 {
|
if len(columnStr) == 0 {
|
||||||
if len(statement.GroupByStr) > 0 {
|
if len(statement.GroupByStr) > 0 {
|
||||||
columnStr = statement.Engine.Quote(strings.Replace(statement.GroupByStr, ",", statement.Engine.Quote(","), -1))
|
columnStr = statement.Engine.quoteColumns(statement.GroupByStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
Loading…
Reference in New Issue