Fix label count (#8267)

* fix label count

* fix vendor

* fix import order

* update xorm to fix bug

* fix tests

* fix mssql bug
This commit is contained in:
Lunny Xiao 2019-09-24 21:22:39 +08:00 committed by GitHub
parent 7cccada51e
commit 29dda47cbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 959 additions and 580 deletions

4
go.mod
View File

@ -48,7 +48,7 @@ require (
github.com/go-redis/redis v6.15.2+incompatible github.com/go-redis/redis v6.15.2+incompatible
github.com/go-sql-driver/mysql v1.4.1 github.com/go-sql-driver/mysql v1.4.1
github.com/go-swagger/go-swagger v0.20.1 github.com/go-swagger/go-swagger v0.20.1
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67
github.com/gobwas/glob v0.2.3 github.com/gobwas/glob v0.2.3
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
@ -124,6 +124,6 @@ require (
gopkg.in/testfixtures.v2 v2.5.0 gopkg.in/testfixtures.v2 v2.5.0
mvdan.cc/xurls/v2 v2.0.0 mvdan.cc/xurls/v2 v2.0.0
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
xorm.io/builder v0.3.5 xorm.io/builder v0.3.6
xorm.io/core v0.7.0 xorm.io/core v0.7.0
) )

8
go.sum
View File

@ -250,10 +250,11 @@ github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.m
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/go-xorm/xorm v0.7.6/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls= github.com/go-xorm/xorm v0.7.6/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls=
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b h1:Y0hWUheXDHpIs7BWtJcykO4d1VOsVDKg1PsP5YJwxxM= github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67 h1:mB5RWONyATkQ48+iQZ1lCZNPG3tABilyaEOxDm1QWyU=
github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls= github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67/go.mod h1:RSsmsVARCy4sayuKWFPaVNQMPYGLNRIK71YIVvgImL0=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA= github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA=
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -340,6 +341,7 @@ github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+Vzrr
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx v3.5.0+incompatible h1:BRJ4G3UPtvml5R1ey0biqqGuYUGayMYekm3woO75orY= github.com/jackc/pgx v3.5.0+incompatible h1:BRJ4G3UPtvml5R1ey0biqqGuYUGayMYekm3woO75orY=
github.com/jackc/pgx v3.5.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx v3.5.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06RVW8OMby+GrmW6K2nPO3AFHlEIdvJSd4= github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d h1:ig/iUfDDg06RVW8OMby+GrmW6K2nPO3AFHlEIdvJSd4=
github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
@ -818,5 +820,7 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a h1:8q33Shx
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A= xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=

View File

@ -760,11 +760,6 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (er
return err return err
} }
for idx := range issue.Labels { for idx := range issue.Labels {
if issue.IsClosed {
issue.Labels[idx].NumClosedIssues++
} else {
issue.Labels[idx].NumClosedIssues--
}
if err = updateLabel(e, issue.Labels[idx]); err != nil { if err = updateLabel(e, issue.Labels[idx]); err != nil {
return err return err
} }

View File

@ -14,6 +14,7 @@ import (
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"xorm.io/builder"
) )
var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})") var labelColorPattern = regexp.MustCompile("#([a-fA-F0-9]{6})")
@ -294,7 +295,20 @@ func GetLabelsByIssueID(issueID int64) ([]*Label, error) {
} }
func updateLabel(e Engine, l *Label) error { func updateLabel(e Engine, l *Label) error {
_, err := e.ID(l.ID).AllCols().Update(l) _, err := e.ID(l.ID).
SetExpr("num_issues",
builder.Select("count(*)").From("issue_label").
Where(builder.Eq{"label_id": l.ID}),
).
SetExpr("num_closed_issues",
builder.Select("count(*)").From("issue_label").
InnerJoin("issue", "issue_label.issue_id = issue.id").
Where(builder.Eq{
"issue_label.label_id": l.ID,
"issue.is_closed": true,
}),
).
AllCols().Update(l)
return err return err
} }
@ -375,10 +389,6 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (err
return err return err
} }
label.NumIssues++
if issue.IsClosed {
label.NumClosedIssues++
}
return updateLabel(e, label) return updateLabel(e, label)
} }
@ -448,10 +458,6 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (
return err return err
} }
label.NumIssues--
if issue.IsClosed {
label.NumClosedIssues--
}
return updateLabel(e, label) return updateLabel(e, label)
} }

View File

@ -205,6 +205,7 @@ func TestNewIssueLabel(t *testing.T) {
LabelID: label.ID, LabelID: label.ID,
Content: "1", Content: "1",
}) })
label = AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
assert.EqualValues(t, prevNumIssues+1, label.NumIssues) assert.EqualValues(t, prevNumIssues+1, label.NumIssues)
// re-add existing IssueLabel // re-add existing IssueLabel

View File

@ -103,7 +103,18 @@ steps:
commands: commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt when:
event:
- push
- pull_request
- name: test-mssql
pull: default
image: golang:1.10
commands:
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt
when: when:
event: event:
- push - push
@ -134,6 +145,19 @@ services:
- tag - tag
- pull_request - pull_request
- name: mssql
pull: default
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: yourStrong(!)Password
MSSQL_PID: Developer
when:
event:
- push
- tag
- pull_request
--- ---
kind: pipeline kind: pipeline
name: matrix-2 name: matrix-2
@ -167,11 +191,13 @@ steps:
- name: build - name: build
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment:
GO111MODULE: "off"
commands: commands:
- go get -t -d -v ./... - go get -t -d -v ./...
- go get -u xorm.io/core - go get -u xorm.io/core
- go get -u xorm.io/builder - go get -u xorm.io/builder
- GO111MODULE=off go build -v - go build -v
when: when:
event: event:
- push - push
@ -181,9 +207,10 @@ steps:
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment: environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn" GOPROXY: "https://goproxy.cn"
commands: commands:
- GO111MODULE=on go build -v - go build -v
when: when:
event: event:
- push - push
@ -192,8 +219,10 @@ steps:
- name: test-sqlite - name: test-sqlite
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- go get -u github.com/wadey/gocovmerge
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic" - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic"
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
when: when:
@ -204,6 +233,9 @@ steps:
- name: test-mysql - name: test-mysql
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
@ -215,6 +247,9 @@ steps:
- name: test-mysql-utf8mb4 - name: test-mysql-utf8mb4
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
@ -226,6 +261,9 @@ steps:
- name: test-mymysql - name: test-mymysql
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic" - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
@ -237,6 +275,9 @@ steps:
- name: test-postgres - name: test-postgres
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
@ -248,10 +289,28 @@ steps:
- name: test-postgres-schema - name: test-postgres-schema
pull: default pull: default
image: golang:1.11 image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt when:
event:
- push
- pull_request
- name: test-mssql
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
- go get github.com/wadey/gocovmerge
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt
when: when:
event: event:
- push - push
@ -282,6 +341,19 @@ services:
- tag - tag
- pull_request - pull_request
- name: mssql
pull: default
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: yourStrong(!)Password
MSSQL_PID: Developer
when:
event:
- push
- tag
- pull_request
--- ---
kind: pipeline kind: pipeline
name: matrix-3 name: matrix-3
@ -315,11 +387,13 @@ steps:
- name: build - name: build
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment:
GO111MODULE: "off"
commands: commands:
- go get -t -d -v ./... - go get -t -d -v ./...
- go get -u xorm.io/core - go get -u xorm.io/core
- go get -u xorm.io/builder - go get -u xorm.io/builder
- GO111MODULE=off go build -v - go build -v
when: when:
event: event:
- push - push
@ -329,9 +403,10 @@ steps:
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment: environment:
GOPROXY: "https://goproxy.cn" GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- GO111MODULE=on go build -v - go build -v
when: when:
event: event:
- push - push
@ -340,8 +415,10 @@ steps:
- name: test-sqlite - name: test-sqlite
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- go get -u github.com/wadey/gocovmerge
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic" - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic"
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
when: when:
@ -352,6 +429,9 @@ steps:
- name: test-mysql - name: test-mysql
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
@ -363,6 +443,9 @@ steps:
- name: test-mysql-utf8mb4 - name: test-mysql-utf8mb4
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
@ -374,6 +457,9 @@ steps:
- name: test-mymysql - name: test-mymysql
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic" - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
@ -385,6 +471,9 @@ steps:
- name: test-postgres - name: test-postgres
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
@ -396,10 +485,28 @@ steps:
- name: test-postgres-schema - name: test-postgres-schema
pull: default pull: default
image: golang:1.12 image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands: commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic" - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt when:
event:
- push
- pull_request
- name: test-mssql
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
- go get -u github.com/wadey/gocovmerge
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt
when: when:
event: event:
- push - push
@ -424,6 +531,19 @@ services:
environment: environment:
POSTGRES_DB: xorm_test POSTGRES_DB: xorm_test
POSTGRES_USER: postgres POSTGRES_USER: postgres
when:
event:
- push
- tag
- pull_request
- name: mssql
pull: default
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: yourStrong(!)Password
MSSQL_PID: Developer
when: when:
event: event:
- push - push

View File

@ -952,7 +952,7 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{tableName} args := []interface{}{tableName}
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix , s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length,
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey, CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
FROM pg_attribute f FROM pg_attribute f
@ -987,14 +987,14 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
col.Indexes = make(map[string]int) col.Indexes = make(map[string]int)
var colName, isNullable, dataType string var colName, isNullable, dataType string
var maxLenStr, colDefault, numPrecision, numRadix *string var maxLenStr, colDefault *string
var isPK, isUnique bool var isPK, isUnique bool
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &numPrecision, &numRadix, &isPK, &isUnique) err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &isPK, &isUnique)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, numPrecision, numRadix, isPK, isUnique) // fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, isPK, isUnique)
var maxLen int var maxLen int
if maxLenStr != nil { if maxLenStr != nil {
maxLen, err = strconv.Atoi(*maxLenStr) maxLen, err = strconv.Atoi(*maxLenStr)

View File

@ -190,14 +190,14 @@ func (engine *Engine) Quote(value string) string {
return value return value
} }
buf := builder.StringBuilder{} buf := strings.Builder{}
engine.QuoteTo(&buf, value) engine.QuoteTo(&buf, value)
return buf.String() return buf.String()
} }
// QuoteTo quotes string and writes into the buffer // QuoteTo quotes string and writes into the buffer
func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) { func (engine *Engine) QuoteTo(buf *strings.Builder, value string) {
if buf == nil { if buf == nil {
return return
} }
@ -729,7 +729,7 @@ func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
} }
// SetExpr provides a update string like "column = {expression}" // SetExpr provides a update string like "column = {expression}"
func (engine *Engine) SetExpr(column string, expression string) *Session { func (engine *Engine) SetExpr(column string, expression interface{}) *Session {
session := engine.NewSession() session := engine.NewSession()
session.isAutoClose = true session.isAutoClose = true
return session.SetExpr(column, expression) return session.SetExpr(column, expression)

View File

@ -1,19 +1,20 @@
module github.com/go-xorm/xorm module github.com/go-xorm/xorm
go 1.11
require ( require (
github.com/cockroachdb/apd v1.1.0 // indirect github.com/cockroachdb/apd v1.1.0 // indirect
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
github.com/go-sql-driver/mysql v1.4.1 github.com/go-sql-driver/mysql v1.4.1
github.com/gofrs/uuid v3.2.0+incompatible // indirect
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
github.com/jackc/pgx v3.3.0+incompatible github.com/jackc/pgx v3.6.0+incompatible
github.com/kr/pretty v0.1.0 // indirect
github.com/lib/pq v1.0.0 github.com/lib/pq v1.0.0
github.com/mattn/go-sqlite3 v1.10.0 github.com/mattn/go-sqlite3 v1.10.0
github.com/pkg/errors v0.8.1 // indirect github.com/pkg/errors v0.8.1 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0
github.com/ziutek/mymysql v1.5.4 github.com/ziutek/mymysql v1.5.4
xorm.io/builder v0.3.5 xorm.io/builder v0.3.6
xorm.io/core v0.7.0 xorm.io/core v0.7.0
) )

View File

@ -28,6 +28,8 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@ -48,18 +50,13 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90= github.com/jackc/pgx v3.6.0+incompatible h1:bJeo4JdVbDAW8KB2m8XkFeo8CPipREoG37BwEoKGz+Q=
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
@ -84,8 +81,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@ -133,6 +128,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -162,7 +158,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=

View File

@ -54,7 +54,7 @@ type Interface interface {
QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error)
QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error)
Rows(bean interface{}) (*Rows, error) Rows(bean interface{}) (*Rows, error)
SetExpr(string, string) *Session SetExpr(string, interface{}) *Session
SQL(interface{}, ...interface{}) *Session SQL(interface{}, ...interface{}) *Session
Sum(bean interface{}, colName string) (float64, error) Sum(bean interface{}, colName string) (float64, error)
SumInt(bean interface{}, colName string) (int64, error) SumInt(bean interface{}, colName string) (int64, error)

View File

@ -12,49 +12,6 @@ import (
"xorm.io/core" "xorm.io/core"
) )
type incrParam struct {
colName string
arg interface{}
}
type decrParam struct {
colName string
arg interface{}
}
type exprParam struct {
colName string
expr string
}
type columnMap []string
func (m columnMap) contain(colName string) bool {
if len(m) == 0 {
return false
}
n := len(colName)
for _, mk := range m {
if len(mk) != n {
continue
}
if strings.EqualFold(mk, colName) {
return true
}
}
return false
}
func (m *columnMap) add(colName string) bool {
if m.contain(colName) {
return false
}
*m = append(*m, colName)
return true
}
func setColumnInt(bean interface{}, col *core.Column, t int64) { func setColumnInt(bean interface{}, col *core.Column, t int64) {
v, err := col.ValueOf(bean) v, err := col.ValueOf(bean)
if err != nil { if err != nil {
@ -132,7 +89,7 @@ func (session *Session) Decr(column string, arg ...interface{}) *Session {
} }
// SetExpr provides a query string like "column = {expression}" // SetExpr provides a query string like "column = {expression}"
func (session *Session) SetExpr(column string, expression string) *Session { func (session *Session) SetExpr(column string, expression interface{}) *Session {
session.statement.SetExpr(column, expression) session.statement.SetExpr(column, expression)
return session return session
} }

View File

@ -340,74 +340,96 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
// insert expr columns, override if exists
exprColumns := session.statement.getExpr()
exprColVals := make([]string, 0, len(exprColumns))
for _, v := range exprColumns {
// remove the expr columns
for i, colName := range colNames {
if colName == strings.Trim(v.colName, "`") {
colNames = append(colNames[:i], colNames[i+1:]...)
args = append(args[:i], args[i+1:]...)
}
}
// append expr column to the end exprs := session.statement.exprColumns
colNames = append(colNames, v.colName) colPlaces := strings.Repeat("?, ", len(colNames))
exprColVals = append(exprColVals, v.expr) if exprs.Len() <= 0 && len(colPlaces) > 0 {
colPlaces = colPlaces[0 : len(colPlaces)-2]
} }
colPlaces := strings.Repeat("?, ", len(colNames)-len(exprColumns))
if len(exprColVals) > 0 {
colPlaces = colPlaces + strings.Join(exprColVals, ", ")
} else {
if len(colPlaces) > 0 {
colPlaces = colPlaces[0 : len(colPlaces)-2]
}
}
var sqlStr string
var tableName = session.statement.TableName() var tableName = session.statement.TableName()
var output string var output string
if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 { if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 {
output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement) output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement)
} }
if len(colPlaces) > 0 { var buf = builder.NewWriter()
if _, err := buf.WriteString(fmt.Sprintf("INSERT INTO %s", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if len(colPlaces) <= 0 {
if session.engine.dialect.DBType() == core.MYSQL {
if _, err := buf.WriteString(" VALUES ()"); err != nil {
return 0, err
}
} else {
if _, err := buf.WriteString(fmt.Sprintf("%s DEFAULT VALUES", output)); err != nil {
return 0, err
}
}
} else {
if _, err := buf.WriteString(" ("); err != nil {
return 0, err
}
if err := writeStrings(buf, append(colNames, exprs.colNames...), "`", "`"); err != nil {
return 0, err
}
if session.statement.cond.IsValid() { if session.statement.cond.IsValid() {
condSQL, condArgs, err := builder.ToSQL(session.statement.cond) if _, err := buf.WriteString(fmt.Sprintf(")%s SELECT ", output)); err != nil {
if err != nil {
return 0, err return 0, err
} }
sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s SELECT %v FROM %v WHERE %v", if err := session.statement.writeArgs(buf, args); err != nil {
session.engine.Quote(tableName), return 0, err
quoteColumns(colNames, session.engine.Quote, ","), }
output,
colPlaces, if len(exprs.args) > 0 {
session.engine.Quote(tableName), if _, err := buf.WriteString(","); err != nil {
condSQL, return 0, err
) }
args = append(args, condArgs...) }
if err := exprs.writeArgs(buf); err != nil {
return 0, err
}
if _, err := buf.WriteString(fmt.Sprintf(" FROM %v WHERE ", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := session.statement.cond.WriteTo(buf); err != nil {
return 0, err
}
} else { } else {
sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s VALUES (%v)", buf.Append(args...)
session.engine.Quote(tableName),
quoteColumns(colNames, session.engine.Quote, ","), if _, err := buf.WriteString(fmt.Sprintf(")%s VALUES (%v",
output, output,
colPlaces) colPlaces)); err != nil {
} return 0, err
} else { }
if session.engine.dialect.DBType() == core.MYSQL {
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName)) if err := exprs.writeArgs(buf); err != nil {
} else { return 0, err
sqlStr = fmt.Sprintf("INSERT INTO %s%s DEFAULT VALUES", session.engine.Quote(tableName), output) }
if _, err := buf.WriteString(")"); err != nil {
return 0, err
}
} }
} }
if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES { if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES {
sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement) if _, err := buf.WriteString(" RETURNING " + session.engine.Quote(table.AutoIncrement)); err != nil {
return 0, err
}
} }
sqlStr := buf.String()
args = buf.Args()
handleAfterInsertProcessorFunc := func(bean interface{}) { handleAfterInsertProcessorFunc := func(bean interface{}) {
if session.isAutoCommit { if session.isAutoCommit {
for _, closure := range session.afterClosures { for _, closure := range session.afterClosures {
@ -611,9 +633,11 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
continue continue
} }
if _, ok := session.statement.incrColumns[col.Name]; ok { if session.statement.incrColumns.isColExist(col.Name) {
continue continue
} else if _, ok := session.statement.decrColumns[col.Name]; ok { } else if session.statement.decrColumns.isColExist(col.Name) {
continue
} else if session.statement.exprColumns.isColExist(col.Name) {
continue continue
} }
@ -688,46 +712,66 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err
} }
var columns = make([]string, 0, len(m)) var columns = make([]string, 0, len(m))
exprs := session.statement.exprColumns
for k := range m { for k := range m {
columns = append(columns, k) if !exprs.isColExist(k) {
columns = append(columns, k)
}
} }
sort.Strings(columns) sort.Strings(columns)
qm := strings.Repeat("?,", len(columns))
var args = make([]interface{}, 0, len(m)) var args = make([]interface{}, 0, len(m))
for _, colName := range columns { for _, colName := range columns {
args = append(args, m[colName]) args = append(args, m[colName])
} }
// insert expr columns, override if exists w := builder.NewWriter()
exprColumns := session.statement.getExpr()
for _, col := range exprColumns {
columns = append(columns, strings.Trim(col.colName, "`"))
qm = qm + col.expr + ","
}
qm = qm[:len(qm)-1]
var sql string
if session.statement.cond.IsValid() { if session.statement.cond.IsValid() {
condSQL, condArgs, err := builder.ToSQL(session.statement.cond) if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
if err != nil { return 0, err
}
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
return 0, err
}
if _, err := w.WriteString(") SELECT "); err != nil {
return 0, err
}
if err := session.statement.writeArgs(w, args); err != nil {
return 0, err
}
if len(exprs.args) > 0 {
if _, err := w.WriteString(","); err != nil {
return 0, err
}
if err := exprs.writeArgs(w); err != nil {
return 0, err
}
}
if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := session.statement.cond.WriteTo(w); err != nil {
return 0, err return 0, err
} }
sql = fmt.Sprintf("INSERT INTO %s (`%s`) SELECT %s FROM %s WHERE %s",
session.engine.Quote(tableName),
strings.Join(columns, "`,`"),
qm,
session.engine.Quote(tableName),
condSQL,
)
args = append(args, condArgs...)
} else { } else {
sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm) qm := strings.Repeat("?,", len(columns))
qm = qm[:len(qm)-1]
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil {
return 0, err
}
w.Append(args...)
} }
sql := w.String()
args = w.Args()
if err := session.cacheInsert(tableName); err != nil { if err := session.cacheInsert(tableName); err != nil {
return 0, err return 0, err
} }
@ -754,8 +798,11 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
} }
var columns = make([]string, 0, len(m)) var columns = make([]string, 0, len(m))
exprs := session.statement.exprColumns
for k := range m { for k := range m {
columns = append(columns, k) if !exprs.isColExist(k) {
columns = append(columns, k)
}
} }
sort.Strings(columns) sort.Strings(columns)
@ -764,37 +811,53 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
args = append(args, m[colName]) args = append(args, m[colName])
} }
qm := strings.Repeat("?,", len(columns)) w := builder.NewWriter()
// insert expr columns, override if exists
exprColumns := session.statement.getExpr()
for _, col := range exprColumns {
columns = append(columns, strings.Trim(col.colName, "`"))
qm = qm + col.expr + ","
}
qm = qm[:len(qm)-1]
var sql string
if session.statement.cond.IsValid() { if session.statement.cond.IsValid() {
qm = "(" + qm[:len(qm)-1] + ")" if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
condSQL, condArgs, err := builder.ToSQL(session.statement.cond) return 0, err
if err != nil { }
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
return 0, err
}
if _, err := w.WriteString(") SELECT "); err != nil {
return 0, err
}
if err := session.statement.writeArgs(w, args); err != nil {
return 0, err
}
if len(exprs.args) > 0 {
if _, err := w.WriteString(","); err != nil {
return 0, err
}
if err := exprs.writeArgs(w); err != nil {
return 0, err
}
}
if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := session.statement.cond.WriteTo(w); err != nil {
return 0, err return 0, err
} }
sql = fmt.Sprintf("INSERT INTO %s (`%s`) SELECT %s FROM %s WHERE %s",
session.engine.Quote(tableName),
strings.Join(columns, "`,`"),
qm,
session.engine.Quote(tableName),
condSQL,
)
args = append(args, condArgs...)
} else { } else {
sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm) qm := strings.Repeat("?,", len(columns))
qm = qm[:len(qm)-1]
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil {
return 0, err
}
w.Append(args...)
} }
sql := w.String()
args = w.Args()
if err := session.cacheInsert(tableName); err != nil { if err := session.cacheInsert(tableName); err != nil {
return 0, err return 0, err
} }

View File

@ -223,21 +223,31 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
} }
// for update action to like "column = column + ?" // for update action to like "column = column + ?"
incColumns := session.statement.getInc() incColumns := session.statement.incrColumns
for _, v := range incColumns { for i, colName := range incColumns.colNames {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?") colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" + ?")
args = append(args, v.arg) args = append(args, incColumns.args[i])
} }
// for update action to like "column = column - ?" // for update action to like "column = column - ?"
decColumns := session.statement.getDec() decColumns := session.statement.decrColumns
for _, v := range decColumns { for i, colName := range decColumns.colNames {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" - ?") colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" - ?")
args = append(args, v.arg) args = append(args, decColumns.args[i])
} }
// for update action to like "column = expression" // for update action to like "column = expression"
exprColumns := session.statement.getExpr() exprColumns := session.statement.exprColumns
for _, v := range exprColumns { for i, colName := range exprColumns.colNames {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+v.expr) switch tp := exprColumns.args[i].(type) {
case string:
colNames = append(colNames, session.engine.Quote(colName)+" = "+tp)
case *builder.Builder:
subQuery, subArgs, err := builder.ToSQL(tp)
if err != nil {
return 0, err
}
colNames = append(colNames, session.engine.Quote(colName)+" = ("+subQuery+")")
args = append(args, subArgs...)
}
} }
if err = session.statement.processIDParam(); err != nil { if err = session.statement.processIDParam(); err != nil {
@ -468,14 +478,17 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac
continue continue
} }
if len(session.statement.columnMap) > 0 { // if only update specify columns
if !session.statement.columnMap.contain(col.Name) { if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
continue continue
} else if _, ok := session.statement.incrColumns[col.Name]; ok { }
continue
} else if _, ok := session.statement.decrColumns[col.Name]; ok { if session.statement.incrColumns.isColExist(col.Name) {
continue continue
} } else if session.statement.decrColumns.isColExist(col.Name) {
continue
} else if session.statement.exprColumns.isColExist(col.Name) {
continue
} }
// !evalphobia! set fieldValue as nil when column is nullable and zero-value // !evalphobia! set fieldValue as nil when column is nullable and zero-value

View File

@ -52,9 +52,9 @@ type Statement struct {
omitColumnMap columnMap omitColumnMap columnMap
mustColumnMap map[string]bool mustColumnMap map[string]bool
nullableMap map[string]bool nullableMap map[string]bool
incrColumns map[string]incrParam incrColumns exprParams
decrColumns map[string]decrParam decrColumns exprParams
exprColumns map[string]exprParam exprColumns exprParams
cond builder.Cond cond builder.Cond
bufferSize int bufferSize int
context ContextCache context ContextCache
@ -94,9 +94,9 @@ func (statement *Statement) Init() {
statement.nullableMap = make(map[string]bool) statement.nullableMap = make(map[string]bool)
statement.checkVersion = true statement.checkVersion = true
statement.unscoped = false statement.unscoped = false
statement.incrColumns = make(map[string]incrParam) statement.incrColumns = exprParams{}
statement.decrColumns = make(map[string]decrParam) statement.decrColumns = exprParams{}
statement.exprColumns = make(map[string]exprParam) statement.exprColumns = exprParams{}
statement.cond = builder.NewCond() statement.cond = builder.NewCond()
statement.bufferSize = 0 statement.bufferSize = 0
statement.context = nil statement.context = nil
@ -534,48 +534,30 @@ func (statement *Statement) ID(id interface{}) *Statement {
// Incr Generate "Update ... Set column = column + arg" statement // Incr Generate "Update ... Set column = column + arg" statement
func (statement *Statement) Incr(column string, arg ...interface{}) *Statement { func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
k := strings.ToLower(column)
if len(arg) > 0 { if len(arg) > 0 {
statement.incrColumns[k] = incrParam{column, arg[0]} statement.incrColumns.addParam(column, arg[0])
} else { } else {
statement.incrColumns[k] = incrParam{column, 1} statement.incrColumns.addParam(column, 1)
} }
return statement return statement
} }
// Decr Generate "Update ... Set column = column - arg" statement // Decr Generate "Update ... Set column = column - arg" statement
func (statement *Statement) Decr(column string, arg ...interface{}) *Statement { func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
k := strings.ToLower(column)
if len(arg) > 0 { if len(arg) > 0 {
statement.decrColumns[k] = decrParam{column, arg[0]} statement.decrColumns.addParam(column, arg[0])
} else { } else {
statement.decrColumns[k] = decrParam{column, 1} statement.decrColumns.addParam(column, 1)
} }
return statement return statement
} }
// SetExpr Generate "Update ... Set column = {expression}" statement // SetExpr Generate "Update ... Set column = {expression}" statement
func (statement *Statement) SetExpr(column string, expression string) *Statement { func (statement *Statement) SetExpr(column string, expression interface{}) *Statement {
k := strings.ToLower(column) statement.exprColumns.addParam(column, expression)
statement.exprColumns[k] = exprParam{column, expression}
return statement return statement
} }
// Generate "Update ... Set column = column + arg" statement
func (statement *Statement) getInc() map[string]incrParam {
return statement.incrColumns
}
// Generate "Update ... Set column = column - arg" statement
func (statement *Statement) getDec() map[string]decrParam {
return statement.decrColumns
}
// Generate "Update ... Set column = {expression}" statement
func (statement *Statement) getExpr() map[string]exprParam {
return statement.exprColumns
}
func (statement *Statement) col2NewColsWithQuote(columns ...string) []string { func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
newColumns := make([]string, 0) newColumns := make([]string, 0)
quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`")
@ -695,7 +677,7 @@ func (statement *Statement) OrderBy(order string) *Statement {
// Desc generate `ORDER BY xx DESC` // Desc generate `ORDER BY xx DESC`
func (statement *Statement) Desc(colNames ...string) *Statement { func (statement *Statement) Desc(colNames ...string) *Statement {
var buf builder.StringBuilder var buf strings.Builder
if len(statement.OrderStr) > 0 { if len(statement.OrderStr) > 0 {
fmt.Fprint(&buf, statement.OrderStr, ", ") fmt.Fprint(&buf, statement.OrderStr, ", ")
} }
@ -707,7 +689,7 @@ func (statement *Statement) Desc(colNames ...string) *Statement {
// Asc provide asc order by query condition, the input parameters are columns. // Asc provide asc order by query condition, the input parameters are columns.
func (statement *Statement) Asc(colNames ...string) *Statement { func (statement *Statement) Asc(colNames ...string) *Statement {
var buf builder.StringBuilder var buf strings.Builder
if len(statement.OrderStr) > 0 { if len(statement.OrderStr) > 0 {
fmt.Fprint(&buf, statement.OrderStr, ", ") fmt.Fprint(&buf, statement.OrderStr, ", ")
} }
@ -736,7 +718,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN // Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement { func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
var buf builder.StringBuilder var buf strings.Builder
if len(statement.JoinStr) > 0 { if len(statement.JoinStr) > 0 {
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP) fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
} else { } else {
@ -801,7 +783,7 @@ func (statement *Statement) genColumnStr() string {
return "" return ""
} }
var buf builder.StringBuilder var buf strings.Builder
columns := statement.RefTable.Columns() columns := statement.RefTable.Columns()
for _, col := range columns { for _, col := range columns {
@ -1118,7 +1100,7 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n
} }
} }
var buf builder.StringBuilder var buf strings.Builder
fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr) fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
if len(mssqlCondi) > 0 { if len(mssqlCondi) > 0 {
if len(whereStr) > 0 { if len(whereStr) > 0 {

97
vendor/github.com/go-xorm/xorm/statement_args.go generated vendored Normal file
View File

@ -0,0 +1,97 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
"fmt"
"xorm.io/builder"
"xorm.io/core"
)
func (statement *Statement) writeArg(w *builder.BytesWriter, arg interface{}) error {
switch argv := arg.(type) {
case string:
if _, err := w.WriteString("'" + argv + "'"); err != nil {
return err
}
case bool:
if statement.Engine.dialect.DBType() == core.MSSQL {
if argv {
if _, err := w.WriteString("1"); err != nil {
return err
}
} else {
if _, err := w.WriteString("0"); err != nil {
return err
}
}
} else {
if argv {
if _, err := w.WriteString("true"); err != nil {
return err
}
} else {
if _, err := w.WriteString("false"); err != nil {
return err
}
}
}
case *builder.Builder:
if _, err := w.WriteString("("); err != nil {
return err
}
if err := argv.WriteTo(w); err != nil {
return err
}
if _, err := w.WriteString(")"); err != nil {
return err
}
default:
if _, err := w.WriteString(fmt.Sprintf("%v", argv)); err != nil {
return err
}
}
return nil
}
func (statement *Statement) writeArgs(w *builder.BytesWriter, args []interface{}) error {
for i, arg := range args {
if err := statement.writeArg(w, arg); err != nil {
return err
}
if i+1 != len(args) {
if _, err := w.WriteString(","); err != nil {
return err
}
}
}
return nil
}
func writeStrings(w *builder.BytesWriter, cols []string, leftQuote, rightQuote string) error {
for i, colName := range cols {
if len(leftQuote) > 0 && colName[0] != '`' {
if _, err := w.WriteString(leftQuote); err != nil {
return err
}
}
if _, err := w.WriteString(colName); err != nil {
return err
}
if len(rightQuote) > 0 && colName[len(colName)-1] != '`' {
if _, err := w.WriteString(rightQuote); err != nil {
return err
}
}
if i+1 != len(cols) {
if _, err := w.WriteString(","); err != nil {
return err
}
}
}
return nil
}

35
vendor/github.com/go-xorm/xorm/statement_columnmap.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import "strings"
type columnMap []string
func (m columnMap) contain(colName string) bool {
if len(m) == 0 {
return false
}
n := len(colName)
for _, mk := range m {
if len(mk) != n {
continue
}
if strings.EqualFold(mk, colName) {
return true
}
}
return false
}
func (m *columnMap) add(colName string) bool {
if m.contain(colName) {
return false
}
*m = append(*m, colName)
return true
}

112
vendor/github.com/go-xorm/xorm/statement_exprparam.go generated vendored Normal file
View File

@ -0,0 +1,112 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
"fmt"
"strings"
"xorm.io/builder"
)
type ErrUnsupportedExprType struct {
tp string
}
func (err ErrUnsupportedExprType) Error() string {
return fmt.Sprintf("Unsupported expression type: %v", err.tp)
}
type exprParam struct {
colName string
arg interface{}
}
type exprParams struct {
colNames []string
args []interface{}
}
func (exprs *exprParams) Len() int {
return len(exprs.colNames)
}
func (exprs *exprParams) addParam(colName string, arg interface{}) {
exprs.colNames = append(exprs.colNames, colName)
exprs.args = append(exprs.args, arg)
}
func (exprs *exprParams) isColExist(colName string) bool {
for _, name := range exprs.colNames {
if strings.EqualFold(trimQuote(name), trimQuote(colName)) {
return true
}
}
return false
}
func (exprs *exprParams) getByName(colName string) (exprParam, bool) {
for i, name := range exprs.colNames {
if strings.EqualFold(name, colName) {
return exprParam{name, exprs.args[i]}, true
}
}
return exprParam{}, false
}
func (exprs *exprParams) writeArgs(w *builder.BytesWriter) error {
for _, expr := range exprs.args {
switch arg := expr.(type) {
case *builder.Builder:
if _, err := w.WriteString("("); err != nil {
return err
}
if err := arg.WriteTo(w); err != nil {
return err
}
if _, err := w.WriteString(")"); err != nil {
return err
}
default:
if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil {
return err
}
}
}
return nil
}
func (exprs *exprParams) writeNameArgs(w *builder.BytesWriter) error {
for i, colName := range exprs.colNames {
if _, err := w.WriteString(colName); err != nil {
return err
}
if _, err := w.WriteString("="); err != nil {
return err
}
switch arg := exprs.args[i].(type) {
case *builder.Builder:
if _, err := w.WriteString("("); err != nil {
return err
}
if err := arg.WriteTo(w); err != nil {
return err
}
if _, err := w.WriteString("("); err != nil {
return err
}
default:
w.Append(exprs.args[i])
}
if i+1 != len(exprs.colNames) {
if _, err := w.WriteString(","); err != nil {
return err
}
}
}
return nil
}

19
vendor/github.com/go-xorm/xorm/statement_quote.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2019 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
func trimQuote(s string) string {
if len(s) == 0 {
return s
}
if s[0] == '`' {
s = s[1:]
}
if len(s) > 0 && s[len(s)-1] == '`' {
return s[:len(s)-1]
}
return s
}

View File

@ -1 +1 @@
go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" go test -db=mssql -conn_str="server=localhost;user id=sa;password=MwantsaSecurePassword1;database=xorm_test"

4
vendor/modules.txt vendored
View File

@ -198,7 +198,7 @@ github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd
github.com/go-swagger/go-swagger/codescan github.com/go-swagger/go-swagger/codescan
github.com/go-swagger/go-swagger/generator github.com/go-swagger/go-swagger/generator
github.com/go-swagger/go-swagger/scan github.com/go-swagger/go-swagger/scan
# github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b # github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67
github.com/go-xorm/xorm github.com/go-xorm/xorm
# github.com/gobwas/glob v0.2.3 # github.com/gobwas/glob v0.2.3
github.com/gobwas/glob github.com/gobwas/glob
@ -612,7 +612,7 @@ gopkg.in/yaml.v2
mvdan.cc/xurls/v2 mvdan.cc/xurls/v2
# strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a # strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
strk.kbt.io/projects/go/libravatar strk.kbt.io/projects/go/libravatar
# xorm.io/builder v0.3.5 # xorm.io/builder v0.3.6
xorm.io/builder xorm.io/builder
# xorm.io/core v0.7.0 # xorm.io/core v0.7.0
xorm.io/core xorm.io/core

115
vendor/xorm.io/builder/.drone.yml generated vendored
View File

@ -1,37 +1,90 @@
---
kind: pipeline
name: go1.10
workspace: workspace:
base: /go base: /go
path: src/github.com/go-xorm/builder path: src/xorm.io/builder
clone: steps:
git: - name: test
image: plugins/git:next pull: default
depth: 50 image: golang:1.10
tags: true commands:
- go get -u golang.org/x/lint/golint
- go get -u github.com/stretchr/testify/assert
- go get -u github.com/go-xorm/sqlfiddle
- golint ./...
- go vet
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
when:
event:
- push
- tag
- pull_request
matrix: ---
GO_VERSION: kind: pipeline
- 1.8 name: go1.11
- 1.9
- 1.10
- 1.11
pipeline: steps:
test: - name: test
image: golang:${GO_VERSION} pull: default
commands: image: golang:1.11
- go get -u github.com/golang/lint/golint commands:
- go get -u github.com/stretchr/testify/assert - go get -u golang.org/x/lint/golint
- go get -u github.com/go-xorm/sqlfiddle - golint ./...
- golint ./... - go vet
- go test -v -race -coverprofile=coverage.txt -covermode=atomic - go test -v -race -coverprofile=coverage.txt -covermode=atomic
when: environment:
event: [ push, tag, pull_request ] GOPROXY: https://goproxy.cn
GO111MODULE: "on"
when:
event:
- push
- tag
- pull_request
codecov: ---
image: robertstettner/drone-codecov kind: pipeline
group: build name: go1.12
secrets: [ codecov_token ]
files: steps:
- coverage.txt - name: test
when: pull: default
event: [ push, pull_request ] image: golang:1.12
commands:
- go get -u golang.org/x/lint/golint
- golint ./...
- go vet
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
environment:
GOPROXY: https://goproxy.cn
GO111MODULE: "on"
when:
event:
- push
- tag
- pull_request
---
kind: pipeline
name: go1.13
steps:
- name: test
pull: default
image: golang:1.13
commands:
- go get -u golang.org/x/lint/golint
- golint ./...
- go vet
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
environment:
GOPROXY: https://goproxy.cn
GO111MODULE: "on"
when:
event:
- push
- tag
- pull_request

26
vendor/xorm.io/builder/README.md generated vendored
View File

@ -1,13 +1,13 @@
# SQL builder # SQL builder
[![GitCI.cn](https://gitci.cn/api/badges/go-xorm/builder/status.svg)](https://gitci.cn/go-xorm/builder) [![codecov](https://codecov.io/gh/go-xorm/builder/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/builder) [![Build Status](https://drone.gitea.com/api/badges/xorm/builder/status.svg)](https://drone.gitea.com/xorm/builder) [![](http://gocover.io/_badge/xorm.io/builder)](http://gocover.io/xorm.io/builder)
[![](https://goreportcard.com/badge/github.com/go-xorm/builder)](https://goreportcard.com/report/github.com/go-xorm/builder) [![](https://goreportcard.com/badge/xorm.io/builder)](https://goreportcard.com/report/xorm.io/builder)
Package builder is a lightweight and fast SQL builder for Go and XORM. Package builder is a lightweight and fast SQL builder for Go and XORM.
Make sure you have installed Go 1.8+ and then: Make sure you have installed Go 1.8+ and then:
go get github.com/go-xorm/builder go get xorm.io/builder
# Insert # Insert
@ -71,7 +71,7 @@ sql, args, err := Select("*").From("a").Where(Eq{"status": "1"}).
* `Eq` is a redefine of a map, you can give one or more conditions to `Eq` * `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Eq{"a":1}) sql, args, _ := ToSQL(Eq{"a":1})
// a=? [1] // a=? [1]
@ -90,7 +90,7 @@ sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
* `Neq` is the same to `Eq` * `Neq` is the same to `Eq`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Neq{"a":1}) sql, args, _ := ToSQL(Neq{"a":1})
// a<>? [1] // a<>? [1]
@ -109,7 +109,7 @@ sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
* `Gt`, `Gte`, `Lt`, `Lte` * `Gt`, `Gte`, `Lt`, `Lte`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2})) sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
// a>? AND b>=? [1, 2] // a>? AND b>=? [1, 2]
@ -120,7 +120,7 @@ sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
* `Like` * `Like`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Like{"a", "c"}) sql, args, _ := ToSQL(Like{"a", "c"})
// a LIKE ? [%c%] // a LIKE ? [%c%]
@ -129,7 +129,7 @@ sql, args, _ := ToSQL(Like{"a", "c"})
* `Expr` you can customerize your sql with `Expr` * `Expr` you can customerize your sql with `Expr`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Expr("a = ? ", 1)) sql, args, _ := ToSQL(Expr("a = ? ", 1))
// a = ? [1] // a = ? [1]
@ -140,7 +140,7 @@ sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
* `In` and `NotIn` * `In` and `NotIn`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(In("a", 1, 2, 3)) sql, args, _ := ToSQL(In("a", 1, 2, 3))
// a IN (?,?,?) [1,2,3] // a IN (?,?,?) [1,2,3]
@ -153,7 +153,7 @@ sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
* `IsNull` and `NotNull` * `IsNull` and `NotNull`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(IsNull{"a"}) sql, args, _ := ToSQL(IsNull{"a"})
// a IS NULL [] // a IS NULL []
@ -164,7 +164,7 @@ sql, args, _ := ToSQL(NotNull{"b"})
* `And(conds ...Cond)`, And can connect one or more condtions via And * `And(conds ...Cond)`, And can connect one or more condtions via And
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2})) sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? AND b LIKE ? AND d<>? [1, %c%, 2] // a=? AND b LIKE ? AND d<>? [1, %c%, 2]
@ -173,7 +173,7 @@ sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
* `Or(conds ...Cond)`, Or can connect one or more conditions via Or * `Or(conds ...Cond)`, Or can connect one or more conditions via Or
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2})) sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? OR b LIKE ? OR d<>? [1, %c%, 2] // a=? OR b LIKE ? OR d<>? [1, %c%, 2]
@ -184,7 +184,7 @@ sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
* `Between` * `Between`
```Go ```Go
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Between{"a", 1, 2}) sql, args, _ := ToSQL(Between{"a", 1, 2})
// a BETWEEN 1 AND 2 // a BETWEEN 1 AND 2

113
vendor/xorm.io/builder/builder.go generated vendored
View File

@ -7,7 +7,6 @@ package builder
import ( import (
sql2 "database/sql" sql2 "database/sql"
"fmt" "fmt"
"sort"
) )
type optype byte type optype byte
@ -21,6 +20,7 @@ const (
unionType // union unionType // union
) )
// all databasees
const ( const (
POSTGRES = "postgres" POSTGRES = "postgres"
SQLITE = "sqlite3" SQLITE = "sqlite3"
@ -31,7 +31,7 @@ const (
type join struct { type join struct {
joinType string joinType string
joinTable string joinTable interface{}
joinCond Cond joinCond Cond
} }
@ -60,7 +60,7 @@ type Builder struct {
limitation *limit limitation *limit
insertCols []string insertCols []string
insertVals []interface{} insertVals []interface{}
updates []Eq updates []UpdateCond
orderBy string orderBy string
groupBy string groupBy string
having string having string
@ -143,18 +143,6 @@ func (b *Builder) Into(tableName string) *Builder {
return b return b
} }
// Join sets join table and conditions
func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builder {
switch joinCond.(type) {
case Cond:
b.joins = append(b.joins, join{joinType, joinTable, joinCond.(Cond)})
case string:
b.joins = append(b.joins, join{joinType, joinTable, Expr(joinCond.(string))})
}
return b
}
// Union sets union conditions // Union sets union conditions
func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder { func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder {
var builder *Builder var builder *Builder
@ -199,31 +187,6 @@ func (b *Builder) Limit(limitN int, offset ...int) *Builder {
return b return b
} }
// InnerJoin sets inner join
func (b *Builder) InnerJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("INNER", joinTable, joinCond)
}
// LeftJoin sets left join SQL
func (b *Builder) LeftJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("LEFT", joinTable, joinCond)
}
// RightJoin sets right join SQL
func (b *Builder) RightJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("RIGHT", joinTable, joinCond)
}
// CrossJoin sets cross join SQL
func (b *Builder) CrossJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("CROSS", joinTable, joinCond)
}
// FullJoin sets full join SQL
func (b *Builder) FullJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("FULL", joinTable, joinCond)
}
// Select sets select SQL // Select sets select SQL
func (b *Builder) Select(cols ...string) *Builder { func (b *Builder) Select(cols ...string) *Builder {
b.selects = cols b.selects = cols
@ -245,68 +208,12 @@ func (b *Builder) Or(cond Cond) *Builder {
return b return b
} }
type insertColsSorter struct {
cols []string
vals []interface{}
}
func (s insertColsSorter) Len() int {
return len(s.cols)
}
func (s insertColsSorter) Swap(i, j int) {
s.cols[i], s.cols[j] = s.cols[j], s.cols[i]
s.vals[i], s.vals[j] = s.vals[j], s.vals[i]
}
func (s insertColsSorter) Less(i, j int) bool {
return s.cols[i] < s.cols[j]
}
// Insert sets insert SQL
func (b *Builder) Insert(eq ...interface{}) *Builder {
if len(eq) > 0 {
var paramType = -1
for _, e := range eq {
switch t := e.(type) {
case Eq:
if paramType == -1 {
paramType = 0
}
if paramType != 0 {
break
}
for k, v := range t {
b.insertCols = append(b.insertCols, k)
b.insertVals = append(b.insertVals, v)
}
case string:
if paramType == -1 {
paramType = 1
}
if paramType != 1 {
break
}
b.insertCols = append(b.insertCols, t)
}
}
}
if len(b.insertCols) == len(b.insertVals) {
sort.Sort(insertColsSorter{
cols: b.insertCols,
vals: b.insertVals,
})
}
b.optype = insertType
return b
}
// Update sets update SQL // Update sets update SQL
func (b *Builder) Update(updates ...Eq) *Builder { func (b *Builder) Update(updates ...Cond) *Builder {
b.updates = make([]Eq, 0, len(updates)) b.updates = make([]UpdateCond, 0, len(updates))
for _, update := range updates { for _, update := range updates {
if update.IsValid() { if u, ok := update.(UpdateCond); ok && u.IsValid() {
b.updates = append(b.updates, update) b.updates = append(b.updates, u)
} }
} }
b.optype = updateType b.optype = updateType
@ -354,7 +261,7 @@ func (b *Builder) ToSQL() (string, []interface{}, error) {
} }
} }
var sql = w.writer.String() var sql = w.String()
var err error var err error
switch b.dialect { switch b.dialect {
@ -383,12 +290,12 @@ func (b *Builder) ToSQL() (string, []interface{}, error) {
return sql, w.args, nil return sql, w.args, nil
} }
// ToBoundSQL // ToBoundSQL generated a bound SQL string
func (b *Builder) ToBoundSQL() (string, error) { func (b *Builder) ToBoundSQL() (string, error) {
w := NewWriter() w := NewWriter()
if err := b.WriteTo(w); err != nil { if err := b.WriteTo(w); err != nil {
return "", err return "", err
} }
return ConvertToBoundSQL(w.writer.String(), w.args) return ConvertToBoundSQL(w.String(), w.args)
} }

View File

@ -7,6 +7,7 @@ package builder
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"sort"
) )
// Insert creates an insert Builder // Insert creates an insert Builder
@ -87,3 +88,60 @@ func (b *Builder) insertWriteTo(w Writer) error {
return nil return nil
} }
type insertColsSorter struct {
cols []string
vals []interface{}
}
func (s insertColsSorter) Len() int {
return len(s.cols)
}
func (s insertColsSorter) Swap(i, j int) {
s.cols[i], s.cols[j] = s.cols[j], s.cols[i]
s.vals[i], s.vals[j] = s.vals[j], s.vals[i]
}
func (s insertColsSorter) Less(i, j int) bool {
return s.cols[i] < s.cols[j]
}
// Insert sets insert SQL
func (b *Builder) Insert(eq ...interface{}) *Builder {
if len(eq) > 0 {
var paramType = -1
for _, e := range eq {
switch t := e.(type) {
case Eq:
if paramType == -1 {
paramType = 0
}
if paramType != 0 {
break
}
for k, v := range t {
b.insertCols = append(b.insertCols, k)
b.insertVals = append(b.insertVals, v)
}
case string:
if paramType == -1 {
paramType = 1
}
if paramType != 1 {
break
}
b.insertCols = append(b.insertCols, t)
}
}
}
if len(b.insertCols) == len(b.insertVals) {
sort.Sort(insertColsSorter{
cols: b.insertCols,
vals: b.insertVals,
})
}
b.optype = insertType
return b
}

42
vendor/xorm.io/builder/builder_join.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2019 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 builder
// InnerJoin sets inner join
func (b *Builder) InnerJoin(joinTable, joinCond interface{}) *Builder {
return b.Join("INNER", joinTable, joinCond)
}
// LeftJoin sets left join SQL
func (b *Builder) LeftJoin(joinTable, joinCond interface{}) *Builder {
return b.Join("LEFT", joinTable, joinCond)
}
// RightJoin sets right join SQL
func (b *Builder) RightJoin(joinTable, joinCond interface{}) *Builder {
return b.Join("RIGHT", joinTable, joinCond)
}
// CrossJoin sets cross join SQL
func (b *Builder) CrossJoin(joinTable, joinCond interface{}) *Builder {
return b.Join("CROSS", joinTable, joinCond)
}
// FullJoin sets full join SQL
func (b *Builder) FullJoin(joinTable, joinCond interface{}) *Builder {
return b.Join("FULL", joinTable, joinCond)
}
// Join sets join table and conditions
func (b *Builder) Join(joinType string, joinTable, joinCond interface{}) *Builder {
switch joinCond.(type) {
case Cond:
b.joins = append(b.joins, join{joinType, joinTable, joinCond.(Cond)})
case string:
b.joins = append(b.joins, join{joinType, joinTable, Expr(joinCond.(string))})
}
return b
}

View File

@ -80,8 +80,21 @@ func (b *Builder) selectWriteTo(w Writer) error {
} }
for _, v := range b.joins { for _, v := range b.joins {
if _, err := fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable); err != nil { b, ok := v.joinTable.(*Builder)
return err if ok {
if _, err := fmt.Fprintf(w, " %s JOIN (", v.joinType); err != nil {
return err
}
if err := b.WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ") ON "); err != nil {
return err
}
} else {
if _, err := fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable); err != nil {
return err
}
} }
if err := v.joinCond.WriteTo(w); err != nil { if err := v.joinCond.WriteTo(w); err != nil {

View File

@ -8,8 +8,14 @@ import (
"fmt" "fmt"
) )
// UpdateCond defines an interface that cond could be used with update
type UpdateCond interface {
IsValid() bool
OpWriteTo(op string, w Writer) error
}
// Update creates an update Builder // Update creates an update Builder
func Update(updates ...Eq) *Builder { func Update(updates ...Cond) *Builder {
builder := &Builder{cond: NewCond()} builder := &Builder{cond: NewCond()}
return builder.Update(updates...) return builder.Update(updates...)
} }
@ -27,7 +33,8 @@ func (b *Builder) updateWriteTo(w Writer) error {
} }
for i, s := range b.updates { for i, s := range b.updates {
if err := s.opWriteTo(",", w); err != nil {
if err := s.OpWriteTo(",", w); err != nil {
return err return err
} }

36
vendor/xorm.io/builder/cond.go generated vendored
View File

@ -4,42 +4,6 @@
package builder package builder
import (
"io"
)
// Writer defines the interface
type Writer interface {
io.Writer
Append(...interface{})
}
var _ Writer = NewWriter()
// BytesWriter implments Writer and save SQL in bytes.Buffer
type BytesWriter struct {
writer *StringBuilder
args []interface{}
}
// NewWriter creates a new string writer
func NewWriter() *BytesWriter {
w := &BytesWriter{
writer: &StringBuilder{},
}
return w
}
// Write writes data to Writer
func (s *BytesWriter) Write(buf []byte) (int, error) {
return s.writer.Write(buf)
}
// Append appends args to Writer
func (s *BytesWriter) Append(args ...interface{}) {
s.args = append(s.args, args...)
}
// Cond defines an interface // Cond defines an interface
type Cond interface { type Cond interface {
WriteTo(Writer) error WriteTo(Writer) error

7
vendor/xorm.io/builder/cond_eq.go generated vendored
View File

@ -20,7 +20,8 @@ type Eq map[string]interface{}
var _ Cond = Eq{} var _ Cond = Eq{}
func (eq Eq) opWriteTo(op string, w Writer) error { // OpWriteTo writes conditions with special operator
func (eq Eq) OpWriteTo(op string, w Writer) error {
var i = 0 var i = 0
for _, k := range eq.sortedKeys() { for _, k := range eq.sortedKeys() {
v := eq[k] v := eq[k]
@ -81,7 +82,7 @@ func (eq Eq) opWriteTo(op string, w Writer) error {
// WriteTo writes SQL to Writer // WriteTo writes SQL to Writer
func (eq Eq) WriteTo(w Writer) error { func (eq Eq) WriteTo(w Writer) error {
return eq.opWriteTo(" AND ", w) return eq.OpWriteTo(" AND ", w)
} }
// And implements And with other conditions // And implements And with other conditions
@ -101,7 +102,7 @@ func (eq Eq) IsValid() bool {
// sortedKeys returns all keys of this Eq sorted with sort.Strings. // sortedKeys returns all keys of this Eq sorted with sort.Strings.
// It is used internally for consistent ordering when generating // It is used internally for consistent ordering when generating
// SQL, see https://github.com/go-xorm/builder/issues/10 // SQL, see https://gitea.com/xorm/builder/issues/10
func (eq Eq) sortedKeys() []string { func (eq Eq) sortedKeys() []string {
keys := make([]string, 0, len(eq)) keys := make([]string, 0, len(eq))
for key := range eq { for key := range eq {

View File

@ -18,6 +18,10 @@ func Expr(sql string, args ...interface{}) Cond {
return expr{sql, args} return expr{sql, args}
} }
func (expr expr) OpWriteTo(op string, w Writer) error {
return expr.WriteTo(w)
}
func (expr expr) WriteTo(w Writer) error { func (expr expr) WriteTo(w Writer) error {
if _, err := fmt.Fprint(w, expr.sql); err != nil { if _, err := fmt.Fprint(w, expr.sql); err != nil {
return err return err

2
vendor/xorm.io/builder/cond_neq.go generated vendored
View File

@ -83,7 +83,7 @@ func (neq Neq) IsValid() bool {
// sortedKeys returns all keys of this Neq sorted with sort.Strings. // sortedKeys returns all keys of this Neq sorted with sort.Strings.
// It is used internally for consistent ordering when generating // It is used internally for consistent ordering when generating
// SQL, see https://github.com/go-xorm/builder/issues/10 // SQL, see https://gitea.com/xorm/builder/issues/10
func (neq Neq) sortedKeys() []string { func (neq Neq) sortedKeys() []string {
keys := make([]string, 0, len(neq)) keys := make([]string, 0, len(neq))
for key := range neq { for key := range neq {

22
vendor/xorm.io/builder/doc.go generated vendored
View File

@ -8,13 +8,13 @@ Package builder is a simple and powerful sql builder for Go.
Make sure you have installed Go 1.1+ and then: Make sure you have installed Go 1.1+ and then:
go get github.com/go-xorm/builder go get xorm.io/builder
WARNNING: Currently, only query conditions are supported. Below is the supported conditions. WARNNING: Currently, only query conditions are supported. Below is the supported conditions.
1. Eq is a redefine of a map, you can give one or more conditions to Eq 1. Eq is a redefine of a map, you can give one or more conditions to Eq
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Eq{"a":1}) sql, args, _ := ToSQL(Eq{"a":1})
// a=? [1] // a=? [1]
@ -31,7 +31,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
2. Neq is the same to Eq 2. Neq is the same to Eq
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Neq{"a":1}) sql, args, _ := ToSQL(Neq{"a":1})
// a<>? [1] // a<>? [1]
@ -48,7 +48,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
3. Gt, Gte, Lt, Lte 3. Gt, Gte, Lt, Lte
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2})) sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
// a>? AND b>=? [1, 2] // a>? AND b>=? [1, 2]
@ -57,14 +57,14 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
4. Like 4. Like
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Like{"a", "c"}) sql, args, _ := ToSQL(Like{"a", "c"})
// a LIKE ? [%c%] // a LIKE ? [%c%]
5. Expr you can customerize your sql with Expr 5. Expr you can customerize your sql with Expr
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Expr("a = ? ", 1)) sql, args, _ := ToSQL(Expr("a = ? ", 1))
// a = ? [1] // a = ? [1]
@ -73,7 +73,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
6. In and NotIn 6. In and NotIn
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(In("a", 1, 2, 3)) sql, args, _ := ToSQL(In("a", 1, 2, 3))
// a IN (?,?,?) [1,2,3] // a IN (?,?,?) [1,2,3]
@ -84,7 +84,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
7. IsNull and NotNull 7. IsNull and NotNull
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(IsNull{"a"}) sql, args, _ := ToSQL(IsNull{"a"})
// a IS NULL [] // a IS NULL []
@ -93,14 +93,14 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
8. And(conds ...Cond), And can connect one or more condtions via AND 8. And(conds ...Cond), And can connect one or more condtions via AND
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2})) sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? AND b LIKE ? AND d<>? [1, %c%, 2] // a=? AND b LIKE ? AND d<>? [1, %c%, 2]
9. Or(conds ...Cond), Or can connect one or more conditions via Or 9. Or(conds ...Cond), Or can connect one or more conditions via Or
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2})) sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? OR b LIKE ? OR d<>? [1, %c%, 2] // a=? OR b LIKE ? OR d<>? [1, %c%, 2]
@ -109,7 +109,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported
10. Between 10. Between
import . "github.com/go-xorm/builder" import . "xorm.io/builder"
sql, args, _ := ToSQL(Between("a", 1, 2)) sql, args, _ := ToSQL(Between("a", 1, 2))
// a BETWEEN 1 AND 2 // a BETWEEN 1 AND 2

4
vendor/xorm.io/builder/error.go generated vendored
View File

@ -17,9 +17,9 @@ var (
ErrNeedMoreArguments = errors.New("Need more sql arguments") ErrNeedMoreArguments = errors.New("Need more sql arguments")
// ErrNoTableName no table name // ErrNoTableName no table name
ErrNoTableName = errors.New("No table indicated") ErrNoTableName = errors.New("No table indicated")
// ErrNoColumnToInsert no column to update // ErrNoColumnToUpdate no column to update
ErrNoColumnToUpdate = errors.New("No column(s) to update") ErrNoColumnToUpdate = errors.New("No column(s) to update")
// ErrNoColumnToInsert no column to update // ErrNoColumnToInsert no column to insert
ErrNoColumnToInsert = errors.New("No column(s) to insert") ErrNoColumnToInsert = errors.New("No column(s) to insert")
// ErrNotSupportDialectType not supported dialect type error // ErrNotSupportDialectType not supported dialect type error
ErrNotSupportDialectType = errors.New("Not supported dialect type") ErrNotSupportDialectType = errors.New("Not supported dialect type")

2
vendor/xorm.io/builder/go.mod generated vendored
View File

@ -1,5 +1,7 @@
module xorm.io/builder module xorm.io/builder
go 1.11
require ( require (
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0

14
vendor/xorm.io/builder/sql.go generated vendored
View File

@ -8,6 +8,7 @@ import (
sql2 "database/sql" sql2 "database/sql"
"fmt" "fmt"
"reflect" "reflect"
"strings"
"time" "time"
) )
@ -20,7 +21,7 @@ func condToSQL(cond Cond) (string, []interface{}, error) {
if err := cond.WriteTo(w); err != nil { if err := cond.WriteTo(w); err != nil {
return "", nil, err return "", nil, err
} }
return w.writer.String(), w.args, nil return w.String(), w.args, nil
} }
func condToBoundSQL(cond Cond) (string, error) { func condToBoundSQL(cond Cond) (string, error) {
@ -32,7 +33,7 @@ func condToBoundSQL(cond Cond) (string, error) {
if err := cond.WriteTo(w); err != nil { if err := cond.WriteTo(w); err != nil {
return "", err return "", err
} }
return ConvertToBoundSQL(w.writer.String(), w.args) return ConvertToBoundSQL(w.String(), w.args)
} }
// ToSQL convert a builder or conditions to SQL and args // ToSQL convert a builder or conditions to SQL and args
@ -92,7 +93,7 @@ func noSQLQuoteNeeded(a interface{}) bool {
// ConvertToBoundSQL will convert SQL and args to a bound SQL // ConvertToBoundSQL will convert SQL and args to a bound SQL
func ConvertToBoundSQL(sql string, args []interface{}) (string, error) { func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
buf := StringBuilder{} buf := strings.Builder{}
var i, j, start int var i, j, start int
for ; i < len(sql); i++ { for ; i < len(sql); i++ {
if sql[i] == '?' { if sql[i] == '?' {
@ -114,7 +115,10 @@ func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
if noSQLQuoteNeeded(arg) { if noSQLQuoteNeeded(arg) {
_, err = fmt.Fprint(&buf, arg) _, err = fmt.Fprint(&buf, arg)
} else { } else {
_, err = fmt.Fprintf(&buf, "'%v'", arg) // replace ' -> '' (standard replacement) to avoid critical SQL injection,
// NOTICE: may allow some injection like % (or _) in LIKE query
_, err = fmt.Fprintf(&buf, "'%v'", strings.Replace(fmt.Sprintf("%v", arg), "'",
"''", -1))
} }
if err != nil { if err != nil {
return "", err return "", err
@ -131,7 +135,7 @@ func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
// ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix // ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
func ConvertPlaceholder(sql, prefix string) (string, error) { func ConvertPlaceholder(sql, prefix string) (string, error) {
buf := StringBuilder{} buf := strings.Builder{}
var i, j, start int var i, j, start int
for ; i < len(sql); i++ { for ; i < len(sql); i++ {
if sql[i] == '?' { if sql[i] == '?' {

View File

@ -1,119 +0,0 @@
// Copyright 2017 The Go 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 builder
import (
"unicode/utf8"
"unsafe"
)
// A StringBuilder is used to efficiently build a string using Write methods.
// It minimizes memory copying. The zero value is ready to use.
// Do not copy a non-zero Builder.
type StringBuilder struct {
addr *StringBuilder // of receiver, to detect copies by value
buf []byte
}
// noescape hides a pointer from escape analysis. noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input. noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
// This was copied from the runtime; see issues 23382 and 7921.
//go:nosplit
func noescape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
return unsafe.Pointer(x ^ 0)
}
func (b *StringBuilder) copyCheck() {
if b.addr == nil {
// This hack works around a failing of Go's escape analysis
// that was causing b to escape and be heap allocated.
// See issue 23382.
// TODO: once issue 7921 is fixed, this should be reverted to
// just "b.addr = b".
b.addr = (*StringBuilder)(noescape(unsafe.Pointer(b)))
} else if b.addr != b {
panic("strings: illegal use of non-zero Builder copied by value")
}
}
// String returns the accumulated string.
func (b *StringBuilder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}
// Len returns the number of accumulated bytes; b.Len() == len(b.String()).
func (b *StringBuilder) Len() int { return len(b.buf) }
// Reset resets the Builder to be empty.
func (b *StringBuilder) Reset() {
b.addr = nil
b.buf = nil
}
// grow copies the buffer to a new, larger buffer so that there are at least n
// bytes of capacity beyond len(b.buf).
func (b *StringBuilder) grow(n int) {
buf := make([]byte, len(b.buf), 2*cap(b.buf)+n)
copy(buf, b.buf)
b.buf = buf
}
// Grow grows b's capacity, if necessary, to guarantee space for
// another n bytes. After Grow(n), at least n bytes can be written to b
// without another allocation. If n is negative, Grow panics.
func (b *StringBuilder) Grow(n int) {
b.copyCheck()
if n < 0 {
panic("strings.Builder.Grow: negative count")
}
if cap(b.buf)-len(b.buf) < n {
b.grow(n)
}
}
// Write appends the contents of p to b's buffer.
// Write always returns len(p), nil.
func (b *StringBuilder) Write(p []byte) (int, error) {
b.copyCheck()
b.buf = append(b.buf, p...)
return len(p), nil
}
// WriteByte appends the byte c to b's buffer.
// The returned error is always nil.
func (b *StringBuilder) WriteByte(c byte) error {
b.copyCheck()
b.buf = append(b.buf, c)
return nil
}
// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.
// It returns the length of r and a nil error.
func (b *StringBuilder) WriteRune(r rune) (int, error) {
b.copyCheck()
if r < utf8.RuneSelf {
b.buf = append(b.buf, byte(r))
return 1, nil
}
l := len(b.buf)
if cap(b.buf)-l < utf8.UTFMax {
b.grow(utf8.UTFMax)
}
n := utf8.EncodeRune(b.buf[l:l+utf8.UTFMax], r)
b.buf = b.buf[:l+n]
return n, nil
}
// WriteString appends the contents of s to b's buffer.
// It returns the length of s and a nil error.
func (b *StringBuilder) WriteString(s string) (int, error) {
b.copyCheck()
b.buf = append(b.buf, s...)
return len(s), nil
}

42
vendor/xorm.io/builder/writer.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2019 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 builder
import (
"io"
"strings"
)
// Writer defines the interface
type Writer interface {
io.Writer
Append(...interface{})
}
var _ Writer = NewWriter()
// BytesWriter implments Writer and save SQL in bytes.Buffer
type BytesWriter struct {
*strings.Builder
args []interface{}
}
// NewWriter creates a new string writer
func NewWriter() *BytesWriter {
w := &BytesWriter{
Builder: &strings.Builder{},
}
return w
}
// Append appends args to Writer
func (w *BytesWriter) Append(args ...interface{}) {
w.args = append(w.args, args...)
}
// Args returns args
func (w *BytesWriter) Args() []interface{} {
return w.args
}