From 29dda47cbbb6da148dbd3412463dc979deffcbfa Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 24 Sep 2019 21:22:39 +0800 Subject: [PATCH] Fix label count (#8267) * fix label count * fix vendor * fix import order * update xorm to fix bug * fix tests * fix mssql bug --- go.mod | 4 +- go.sum | 8 +- models/issue.go | 5 - models/issue_label.go | 24 +- models/issue_label_test.go | 1 + vendor/github.com/go-xorm/xorm/.drone.yml | 140 +++++++++- .../go-xorm/xorm/dialect_postgres.go | 8 +- vendor/github.com/go-xorm/xorm/engine.go | 6 +- vendor/github.com/go-xorm/xorm/go.mod | 9 +- vendor/github.com/go-xorm/xorm/go.sum | 18 +- vendor/github.com/go-xorm/xorm/interface.go | 2 +- .../github.com/go-xorm/xorm/session_cols.go | 45 +-- .../github.com/go-xorm/xorm/session_insert.go | 263 +++++++++++------- .../github.com/go-xorm/xorm/session_update.go | 51 ++-- vendor/github.com/go-xorm/xorm/statement.go | 52 ++-- .../github.com/go-xorm/xorm/statement_args.go | 97 +++++++ .../go-xorm/xorm/statement_columnmap.go | 35 +++ .../go-xorm/xorm/statement_exprparam.go | 112 ++++++++ .../go-xorm/xorm/statement_quote.go | 19 ++ vendor/github.com/go-xorm/xorm/test_mssql.sh | 2 +- vendor/modules.txt | 4 +- vendor/xorm.io/builder/.drone.yml | 115 +++++--- vendor/xorm.io/builder/README.md | 26 +- vendor/xorm.io/builder/builder.go | 113 +------- vendor/xorm.io/builder/builder_insert.go | 58 ++++ vendor/xorm.io/builder/builder_join.go | 42 +++ vendor/xorm.io/builder/builder_select.go | 17 +- vendor/xorm.io/builder/builder_update.go | 11 +- vendor/xorm.io/builder/cond.go | 36 --- vendor/xorm.io/builder/cond_eq.go | 7 +- vendor/xorm.io/builder/cond_expr.go | 4 + vendor/xorm.io/builder/cond_neq.go | 2 +- vendor/xorm.io/builder/doc.go | 22 +- vendor/xorm.io/builder/error.go | 4 +- vendor/xorm.io/builder/go.mod | 2 + vendor/xorm.io/builder/sql.go | 14 +- vendor/xorm.io/builder/string_builder.go | 119 -------- vendor/xorm.io/builder/writer.go | 42 +++ 38 files changed, 959 insertions(+), 580 deletions(-) create mode 100644 vendor/github.com/go-xorm/xorm/statement_args.go create mode 100644 vendor/github.com/go-xorm/xorm/statement_columnmap.go create mode 100644 vendor/github.com/go-xorm/xorm/statement_exprparam.go create mode 100644 vendor/github.com/go-xorm/xorm/statement_quote.go create mode 100644 vendor/xorm.io/builder/builder_join.go delete mode 100644 vendor/xorm.io/builder/string_builder.go create mode 100644 vendor/xorm.io/builder/writer.go diff --git a/go.mod b/go.mod index 0b5dd381d..017e3f615 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.4.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/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 @@ -124,6 +124,6 @@ require ( gopkg.in/testfixtures.v2 v2.5.0 mvdan.cc/xurls/v2 v2.0.0 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 ) diff --git a/go.sum b/go.sum index a0eff427d..4607de2ce 100644 --- a/go.sum +++ b/go.sum @@ -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/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= 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.7-0.20190822154023-17592d96b35b/go.mod h1:nqz2TAsuOHWH2yk4FYWtacCGgdbrcdZ5mF1XadqEHls= +github.com/go-xorm/xorm v0.7.8-0.20190924080535-59ed80ce1a67 h1:mB5RWONyATkQ48+iQZ1lCZNPG3tABilyaEOxDm1QWyU= +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/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/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= 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.5.0+incompatible h1:BRJ4G3UPtvml5R1ey0biqqGuYUGayMYekm3woO75orY= 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/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= @@ -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= 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.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/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= diff --git a/models/issue.go b/models/issue.go index c4b15e9dd..77712c0fe 100644 --- a/models/issue.go +++ b/models/issue.go @@ -760,11 +760,6 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (er return err } 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 { return err } diff --git a/models/issue_label.go b/models/issue_label.go index f378f62e6..dab5ba282 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -14,6 +14,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "github.com/go-xorm/xorm" + "xorm.io/builder" ) 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 { - _, 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 } @@ -375,10 +389,6 @@ func newIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) (err return err } - label.NumIssues++ - if issue.IsClosed { - label.NumClosedIssues++ - } return updateLabel(e, label) } @@ -448,10 +458,6 @@ func deleteIssueLabel(e *xorm.Session, issue *Issue, label *Label, doer *User) ( return err } - label.NumIssues-- - if issue.IsClosed { - label.NumClosedIssues-- - } return updateLabel(e, label) } diff --git a/models/issue_label_test.go b/models/issue_label_test.go index 5cdc059cf..3cf6cc0e5 100644 --- a/models/issue_label_test.go +++ b/models/issue_label_test.go @@ -205,6 +205,7 @@ func TestNewIssueLabel(t *testing.T) { LabelID: label.ID, Content: "1", }) + label = AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label) assert.EqualValues(t, prevNumIssues+1, label.NumIssues) // re-add existing IssueLabel diff --git a/vendor/github.com/go-xorm/xorm/.drone.yml b/vendor/github.com/go-xorm/xorm/.drone.yml index 94ba92e60..6001ec595 100644 --- a/vendor/github.com/go-xorm/xorm/.drone.yml +++ b/vendor/github.com/go-xorm/xorm/.drone.yml @@ -103,7 +103,18 @@ steps: 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 -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: event: - push @@ -134,6 +145,19 @@ services: - 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: + event: + - push + - tag + - pull_request + --- kind: pipeline name: matrix-2 @@ -167,11 +191,13 @@ steps: - name: build pull: default image: golang:1.11 + environment: + GO111MODULE: "off" commands: - go get -t -d -v ./... - go get -u xorm.io/core - go get -u xorm.io/builder - - GO111MODULE=off go build -v + - go build -v when: event: - push @@ -181,9 +207,10 @@ steps: pull: default image: golang:1.11 environment: + GO111MODULE: "on" GOPROXY: "https://goproxy.cn" commands: - - GO111MODULE=on go build -v + - go build -v when: event: - push @@ -192,8 +219,10 @@ steps: - name: test-sqlite pull: default image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" when: @@ -204,6 +233,9 @@ steps: - name: test-mysql pull: default image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" @@ -215,6 +247,9 @@ steps: - name: test-mysql-utf8mb4 pull: default image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" @@ -226,6 +261,9 @@ steps: - name: test-mymysql pull: default image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" @@ -237,6 +275,9 @@ steps: - name: test-postgres pull: default image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" @@ -248,10 +289,28 @@ steps: - name: test-postgres-schema pull: default image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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 -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: event: - push @@ -282,6 +341,19 @@ services: - 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: + event: + - push + - tag + - pull_request + --- kind: pipeline name: matrix-3 @@ -315,11 +387,13 @@ steps: - name: build pull: default image: golang:1.12 + environment: + GO111MODULE: "off" commands: - go get -t -d -v ./... - go get -u xorm.io/core - go get -u xorm.io/builder - - GO111MODULE=off go build -v + - go build -v when: event: - push @@ -329,9 +403,10 @@ steps: pull: default image: golang:1.12 environment: - GOPROXY: "https://goproxy.cn" + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" commands: - - GO111MODULE=on go build -v + - go build -v when: event: - push @@ -340,8 +415,10 @@ steps: - name: test-sqlite pull: default image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" when: @@ -352,6 +429,9 @@ steps: - name: test-mysql pull: default image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" @@ -363,6 +443,9 @@ steps: - name: test-mysql-utf8mb4 pull: default image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" @@ -374,6 +457,9 @@ steps: - name: test-mymysql pull: default image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" @@ -385,6 +471,9 @@ steps: - name: test-postgres pull: default image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" @@ -396,10 +485,28 @@ steps: - name: test-postgres-schema pull: default image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" 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 -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: event: - push @@ -424,6 +531,19 @@ services: environment: POSTGRES_DB: xorm_test 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: event: - push diff --git a/vendor/github.com/go-xorm/xorm/dialect_postgres.go b/vendor/github.com/go-xorm/xorm/dialect_postgres.go index e1c377a06..3df682e81 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_postgres.go +++ b/vendor/github.com/go-xorm/xorm/dialect_postgres.go @@ -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) { 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 = 'u' THEN true ELSE false END AS uniquekey 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) var colName, isNullable, dataType string - var maxLenStr, colDefault, numPrecision, numRadix *string + var maxLenStr, colDefault *string 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 { 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 if maxLenStr != nil { maxLen, err = strconv.Atoi(*maxLenStr) diff --git a/vendor/github.com/go-xorm/xorm/engine.go b/vendor/github.com/go-xorm/xorm/engine.go index ebcab91bc..649fd1e30 100644 --- a/vendor/github.com/go-xorm/xorm/engine.go +++ b/vendor/github.com/go-xorm/xorm/engine.go @@ -190,14 +190,14 @@ func (engine *Engine) Quote(value string) string { return value } - buf := builder.StringBuilder{} + buf := strings.Builder{} engine.QuoteTo(&buf, value) return buf.String() } // 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 { return } @@ -729,7 +729,7 @@ func (engine *Engine) Decr(column string, arg ...interface{}) *Session { } // 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.isAutoClose = true return session.SetExpr(column, expression) diff --git a/vendor/github.com/go-xorm/xorm/go.mod b/vendor/github.com/go-xorm/xorm/go.mod index 9a30e7978..eb0d71ba1 100644 --- a/vendor/github.com/go-xorm/xorm/go.mod +++ b/vendor/github.com/go-xorm/xorm/go.mod @@ -1,19 +1,20 @@ module github.com/go-xorm/xorm +go 1.11 + require ( github.com/cockroachdb/apd v1.1.0 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 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/pgx v3.3.0+incompatible - github.com/kr/pretty v0.1.0 // indirect + github.com/jackc/pgx v3.6.0+incompatible github.com/lib/pq v1.0.0 github.com/mattn/go-sqlite3 v1.10.0 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/stretchr/testify v1.3.0 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 ) diff --git a/vendor/github.com/go-xorm/xorm/go.sum b/vendor/github.com/go-xorm/xorm/go.sum index 370dcd0b6..15f16fbc6 100644 --- a/vendor/github.com/go-xorm/xorm/go.sum +++ b/vendor/github.com/go-xorm/xorm/go.sum @@ -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-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/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.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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/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/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90= -github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackc/pgx v3.6.0+incompatible h1:bJeo4JdVbDAW8KB2m8XkFeo8CPipREoG37BwEoKGz+Q= +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/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/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/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/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 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-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 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/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 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/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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 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/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-20190102054323-c2f93a96b099/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.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/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= diff --git a/vendor/github.com/go-xorm/xorm/interface.go b/vendor/github.com/go-xorm/xorm/interface.go index 0928f66a9..a564db126 100644 --- a/vendor/github.com/go-xorm/xorm/interface.go +++ b/vendor/github.com/go-xorm/xorm/interface.go @@ -54,7 +54,7 @@ type Interface interface { QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) Rows(bean interface{}) (*Rows, error) - SetExpr(string, string) *Session + SetExpr(string, interface{}) *Session SQL(interface{}, ...interface{}) *Session Sum(bean interface{}, colName string) (float64, error) SumInt(bean interface{}, colName string) (int64, error) diff --git a/vendor/github.com/go-xorm/xorm/session_cols.go b/vendor/github.com/go-xorm/xorm/session_cols.go index dc3befcf6..1558074f3 100644 --- a/vendor/github.com/go-xorm/xorm/session_cols.go +++ b/vendor/github.com/go-xorm/xorm/session_cols.go @@ -12,49 +12,6 @@ import ( "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) { v, err := col.ValueOf(bean) if err != nil { @@ -132,7 +89,7 @@ func (session *Session) Decr(column string, arg ...interface{}) *Session { } // 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) return session } diff --git a/vendor/github.com/go-xorm/xorm/session_insert.go b/vendor/github.com/go-xorm/xorm/session_insert.go index 24b328314..de6452909 100644 --- a/vendor/github.com/go-xorm/xorm/session_insert.go +++ b/vendor/github.com/go-xorm/xorm/session_insert.go @@ -340,74 +340,96 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { if err != nil { 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 - colNames = append(colNames, v.colName) - exprColVals = append(exprColVals, v.expr) + exprs := session.statement.exprColumns + colPlaces := strings.Repeat("?, ", len(colNames)) + 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 output string if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 { 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() { - condSQL, condArgs, err := builder.ToSQL(session.statement.cond) - if err != nil { + if _, err := buf.WriteString(fmt.Sprintf(")%s SELECT ", output)); err != nil { return 0, err } - sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s SELECT %v FROM %v WHERE %v", - session.engine.Quote(tableName), - quoteColumns(colNames, session.engine.Quote, ","), - output, - colPlaces, - session.engine.Quote(tableName), - condSQL, - ) - args = append(args, condArgs...) + if err := session.statement.writeArgs(buf, args); err != nil { + return 0, err + } + + if len(exprs.args) > 0 { + if _, err := buf.WriteString(","); err != nil { + return 0, err + } + } + 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 { - sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s VALUES (%v)", - session.engine.Quote(tableName), - quoteColumns(colNames, session.engine.Quote, ","), + buf.Append(args...) + + if _, err := buf.WriteString(fmt.Sprintf(")%s VALUES (%v", output, - colPlaces) - } - } else { - if session.engine.dialect.DBType() == core.MYSQL { - sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName)) - } else { - sqlStr = fmt.Sprintf("INSERT INTO %s%s DEFAULT VALUES", session.engine.Quote(tableName), output) + colPlaces)); err != nil { + return 0, err + } + + if err := exprs.writeArgs(buf); err != nil { + return 0, err + } + + if _, err := buf.WriteString(")"); err != nil { + return 0, err + } } } 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{}) { if session.isAutoCommit { for _, closure := range session.afterClosures { @@ -611,9 +633,11 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac continue } - if _, ok := session.statement.incrColumns[col.Name]; ok { + if session.statement.incrColumns.isColExist(col.Name) { 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 } @@ -688,46 +712,66 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err } var columns = make([]string, 0, len(m)) + exprs := session.statement.exprColumns for k := range m { - columns = append(columns, k) + if !exprs.isColExist(k) { + columns = append(columns, k) + } } sort.Strings(columns) - qm := strings.Repeat("?,", len(columns)) - var args = make([]interface{}, 0, len(m)) for _, colName := range columns { args = append(args, m[colName]) } - // 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 - + w := builder.NewWriter() if session.statement.cond.IsValid() { - condSQL, condArgs, err := builder.ToSQL(session.statement.cond) - if err != nil { + if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); 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 } - 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 { - 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 { return 0, err } @@ -754,8 +798,11 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) { } var columns = make([]string, 0, len(m)) + exprs := session.statement.exprColumns for k := range m { - columns = append(columns, k) + if !exprs.isColExist(k) { + columns = append(columns, k) + } } sort.Strings(columns) @@ -764,37 +811,53 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) { args = append(args, m[colName]) } - qm := strings.Repeat("?,", len(columns)) - - // 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 - + w := builder.NewWriter() if session.statement.cond.IsValid() { - qm = "(" + qm[:len(qm)-1] + ")" - condSQL, condArgs, err := builder.ToSQL(session.statement.cond) - if err != nil { + if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); 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 } - 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 { - 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 { return 0, err } diff --git a/vendor/github.com/go-xorm/xorm/session_update.go b/vendor/github.com/go-xorm/xorm/session_update.go index 85b0bb0bf..c5c65a452 100644 --- a/vendor/github.com/go-xorm/xorm/session_update.go +++ b/vendor/github.com/go-xorm/xorm/session_update.go @@ -223,21 +223,31 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 } // for update action to like "column = column + ?" - incColumns := session.statement.getInc() - for _, v := range incColumns { - colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?") - args = append(args, v.arg) + incColumns := session.statement.incrColumns + for i, colName := range incColumns.colNames { + colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" + ?") + args = append(args, incColumns.args[i]) } // for update action to like "column = column - ?" - decColumns := session.statement.getDec() - for _, v := range decColumns { - colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" - ?") - args = append(args, v.arg) + decColumns := session.statement.decrColumns + for i, colName := range decColumns.colNames { + colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" - ?") + args = append(args, decColumns.args[i]) } // for update action to like "column = expression" - exprColumns := session.statement.getExpr() - for _, v := range exprColumns { - colNames = append(colNames, session.engine.Quote(v.colName)+" = "+v.expr) + exprColumns := session.statement.exprColumns + for i, colName := range exprColumns.colNames { + 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 { @@ -468,14 +478,17 @@ func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interfac continue } - if len(session.statement.columnMap) > 0 { - if !session.statement.columnMap.contain(col.Name) { - continue - } else if _, ok := session.statement.incrColumns[col.Name]; ok { - continue - } else if _, ok := session.statement.decrColumns[col.Name]; ok { - continue - } + // if only update specify columns + if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) { + continue + } + + if session.statement.incrColumns.isColExist(col.Name) { + 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 diff --git a/vendor/github.com/go-xorm/xorm/statement.go b/vendor/github.com/go-xorm/xorm/statement.go index 585378a8b..3cc0831ee 100644 --- a/vendor/github.com/go-xorm/xorm/statement.go +++ b/vendor/github.com/go-xorm/xorm/statement.go @@ -52,9 +52,9 @@ type Statement struct { omitColumnMap columnMap mustColumnMap map[string]bool nullableMap map[string]bool - incrColumns map[string]incrParam - decrColumns map[string]decrParam - exprColumns map[string]exprParam + incrColumns exprParams + decrColumns exprParams + exprColumns exprParams cond builder.Cond bufferSize int context ContextCache @@ -94,9 +94,9 @@ func (statement *Statement) Init() { statement.nullableMap = make(map[string]bool) statement.checkVersion = true statement.unscoped = false - statement.incrColumns = make(map[string]incrParam) - statement.decrColumns = make(map[string]decrParam) - statement.exprColumns = make(map[string]exprParam) + statement.incrColumns = exprParams{} + statement.decrColumns = exprParams{} + statement.exprColumns = exprParams{} statement.cond = builder.NewCond() statement.bufferSize = 0 statement.context = nil @@ -534,48 +534,30 @@ func (statement *Statement) ID(id interface{}) *Statement { // Incr Generate "Update ... Set column = column + arg" statement func (statement *Statement) Incr(column string, arg ...interface{}) *Statement { - k := strings.ToLower(column) if len(arg) > 0 { - statement.incrColumns[k] = incrParam{column, arg[0]} + statement.incrColumns.addParam(column, arg[0]) } else { - statement.incrColumns[k] = incrParam{column, 1} + statement.incrColumns.addParam(column, 1) } return statement } // Decr Generate "Update ... Set column = column - arg" statement func (statement *Statement) Decr(column string, arg ...interface{}) *Statement { - k := strings.ToLower(column) if len(arg) > 0 { - statement.decrColumns[k] = decrParam{column, arg[0]} + statement.decrColumns.addParam(column, arg[0]) } else { - statement.decrColumns[k] = decrParam{column, 1} + statement.decrColumns.addParam(column, 1) } return statement } // SetExpr Generate "Update ... Set column = {expression}" statement -func (statement *Statement) SetExpr(column string, expression string) *Statement { - k := strings.ToLower(column) - statement.exprColumns[k] = exprParam{column, expression} +func (statement *Statement) SetExpr(column string, expression interface{}) *Statement { + statement.exprColumns.addParam(column, expression) 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 { newColumns := make([]string, 0) quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") @@ -695,7 +677,7 @@ func (statement *Statement) OrderBy(order string) *Statement { // Desc generate `ORDER BY xx DESC` func (statement *Statement) Desc(colNames ...string) *Statement { - var buf builder.StringBuilder + var buf strings.Builder if len(statement.OrderStr) > 0 { 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. func (statement *Statement) Asc(colNames ...string) *Statement { - var buf builder.StringBuilder + var buf strings.Builder if len(statement.OrderStr) > 0 { 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 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 { fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP) } else { @@ -801,7 +783,7 @@ func (statement *Statement) genColumnStr() string { return "" } - var buf builder.StringBuilder + var buf strings.Builder columns := statement.RefTable.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) if len(mssqlCondi) > 0 { if len(whereStr) > 0 { diff --git a/vendor/github.com/go-xorm/xorm/statement_args.go b/vendor/github.com/go-xorm/xorm/statement_args.go new file mode 100644 index 000000000..4ce336f48 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/statement_args.go @@ -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 +} diff --git a/vendor/github.com/go-xorm/xorm/statement_columnmap.go b/vendor/github.com/go-xorm/xorm/statement_columnmap.go new file mode 100644 index 000000000..b6523b1e7 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/statement_columnmap.go @@ -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 +} diff --git a/vendor/github.com/go-xorm/xorm/statement_exprparam.go b/vendor/github.com/go-xorm/xorm/statement_exprparam.go new file mode 100644 index 000000000..0cddca024 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/statement_exprparam.go @@ -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 +} diff --git a/vendor/github.com/go-xorm/xorm/statement_quote.go b/vendor/github.com/go-xorm/xorm/statement_quote.go new file mode 100644 index 000000000..e22e0d147 --- /dev/null +++ b/vendor/github.com/go-xorm/xorm/statement_quote.go @@ -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 +} diff --git a/vendor/github.com/go-xorm/xorm/test_mssql.sh b/vendor/github.com/go-xorm/xorm/test_mssql.sh index 7f060cff3..e26e16411 100644 --- a/vendor/github.com/go-xorm/xorm/test_mssql.sh +++ b/vendor/github.com/go-xorm/xorm/test_mssql.sh @@ -1 +1 @@ -go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" \ No newline at end of file +go test -db=mssql -conn_str="server=localhost;user id=sa;password=MwantsaSecurePassword1;database=xorm_test" \ No newline at end of file diff --git a/vendor/modules.txt b/vendor/modules.txt index e300a9bbe..56df013a5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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/generator 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/gobwas/glob v0.2.3 github.com/gobwas/glob @@ -612,7 +612,7 @@ gopkg.in/yaml.v2 mvdan.cc/xurls/v2 # strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a strk.kbt.io/projects/go/libravatar -# xorm.io/builder v0.3.5 +# xorm.io/builder v0.3.6 xorm.io/builder # xorm.io/core v0.7.0 xorm.io/core diff --git a/vendor/xorm.io/builder/.drone.yml b/vendor/xorm.io/builder/.drone.yml index ca4037772..557dbf66f 100644 --- a/vendor/xorm.io/builder/.drone.yml +++ b/vendor/xorm.io/builder/.drone.yml @@ -1,37 +1,90 @@ +--- +kind: pipeline +name: go1.10 + workspace: base: /go - path: src/github.com/go-xorm/builder + path: src/xorm.io/builder -clone: - git: - image: plugins/git:next - depth: 50 - tags: true +steps: +- name: test + pull: default + image: golang:1.10 + 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: - - 1.8 - - 1.9 - - 1.10 - - 1.11 +--- +kind: pipeline +name: go1.11 -pipeline: - test: - image: golang:${GO_VERSION} - commands: - - go get -u github.com/golang/lint/golint - - go get -u github.com/stretchr/testify/assert - - go get -u github.com/go-xorm/sqlfiddle - - golint ./... - - go test -v -race -coverprofile=coverage.txt -covermode=atomic - when: - event: [ push, tag, pull_request ] +steps: +- name: test + pull: default + image: golang:1.11 + 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 -codecov: - image: robertstettner/drone-codecov - group: build - secrets: [ codecov_token ] - files: - - coverage.txt - when: - event: [ push, pull_request ] \ No newline at end of file +--- +kind: pipeline +name: go1.12 + +steps: +- name: test + pull: default + 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 \ No newline at end of file diff --git a/vendor/xorm.io/builder/README.md b/vendor/xorm.io/builder/README.md index cf516d1fd..53e540320 100644 --- a/vendor/xorm.io/builder/README.md +++ b/vendor/xorm.io/builder/README.md @@ -1,13 +1,13 @@ # 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) -[![](https://goreportcard.com/badge/github.com/go-xorm/builder)](https://goreportcard.com/report/github.com/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/xorm.io/builder)](https://goreportcard.com/report/xorm.io/builder) Package builder is a lightweight and fast SQL builder for Go and XORM. Make sure you have installed Go 1.8+ and then: - go get github.com/go-xorm/builder + go get xorm.io/builder # 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` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(Eq{"a":1}) // a=? [1] @@ -90,7 +90,7 @@ sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}}) * `Neq` is the same to `Eq` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(Neq{"a":1}) // a<>? [1] @@ -109,7 +109,7 @@ sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}}) * `Gt`, `Gte`, `Lt`, `Lte` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2})) // a>? AND b>=? [1, 2] @@ -120,7 +120,7 @@ sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2})) * `Like` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(Like{"a", "c"}) // a LIKE ? [%c%] @@ -129,7 +129,7 @@ sql, args, _ := ToSQL(Like{"a", "c"}) * `Expr` you can customerize your sql with `Expr` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(Expr("a = ? ", 1)) // a = ? [1] @@ -140,7 +140,7 @@ sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)}) * `In` and `NotIn` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(In("a", 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` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(IsNull{"a"}) // a IS NULL [] @@ -164,7 +164,7 @@ sql, args, _ := ToSQL(NotNull{"b"}) * `And(conds ...Cond)`, And can connect one or more condtions via And ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 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 ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 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` ```Go -import . "github.com/go-xorm/builder" +import . "xorm.io/builder" sql, args, _ := ToSQL(Between{"a", 1, 2}) // a BETWEEN 1 AND 2 diff --git a/vendor/xorm.io/builder/builder.go b/vendor/xorm.io/builder/builder.go index ffe86d4dc..4f1422284 100644 --- a/vendor/xorm.io/builder/builder.go +++ b/vendor/xorm.io/builder/builder.go @@ -7,7 +7,6 @@ package builder import ( sql2 "database/sql" "fmt" - "sort" ) type optype byte @@ -21,6 +20,7 @@ const ( unionType // union ) +// all databasees const ( POSTGRES = "postgres" SQLITE = "sqlite3" @@ -31,7 +31,7 @@ const ( type join struct { joinType string - joinTable string + joinTable interface{} joinCond Cond } @@ -60,7 +60,7 @@ type Builder struct { limitation *limit insertCols []string insertVals []interface{} - updates []Eq + updates []UpdateCond orderBy string groupBy string having string @@ -143,18 +143,6 @@ func (b *Builder) Into(tableName string) *Builder { 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 func (b *Builder) Union(unionTp string, unionCond *Builder) *Builder { var builder *Builder @@ -199,31 +187,6 @@ func (b *Builder) Limit(limitN int, offset ...int) *Builder { 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 func (b *Builder) Select(cols ...string) *Builder { b.selects = cols @@ -245,68 +208,12 @@ func (b *Builder) Or(cond Cond) *Builder { 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 -func (b *Builder) Update(updates ...Eq) *Builder { - b.updates = make([]Eq, 0, len(updates)) +func (b *Builder) Update(updates ...Cond) *Builder { + b.updates = make([]UpdateCond, 0, len(updates)) for _, update := range updates { - if update.IsValid() { - b.updates = append(b.updates, update) + if u, ok := update.(UpdateCond); ok && u.IsValid() { + b.updates = append(b.updates, u) } } 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 switch b.dialect { @@ -383,12 +290,12 @@ func (b *Builder) ToSQL() (string, []interface{}, error) { return sql, w.args, nil } -// ToBoundSQL +// ToBoundSQL generated a bound SQL string func (b *Builder) ToBoundSQL() (string, error) { w := NewWriter() if err := b.WriteTo(w); err != nil { return "", err } - return ConvertToBoundSQL(w.writer.String(), w.args) + return ConvertToBoundSQL(w.String(), w.args) } diff --git a/vendor/xorm.io/builder/builder_insert.go b/vendor/xorm.io/builder/builder_insert.go index 202cad51d..9558a8aca 100644 --- a/vendor/xorm.io/builder/builder_insert.go +++ b/vendor/xorm.io/builder/builder_insert.go @@ -7,6 +7,7 @@ package builder import ( "bytes" "fmt" + "sort" ) // Insert creates an insert Builder @@ -87,3 +88,60 @@ func (b *Builder) insertWriteTo(w Writer) error { 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 +} diff --git a/vendor/xorm.io/builder/builder_join.go b/vendor/xorm.io/builder/builder_join.go new file mode 100644 index 000000000..a6604c5f6 --- /dev/null +++ b/vendor/xorm.io/builder/builder_join.go @@ -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 +} diff --git a/vendor/xorm.io/builder/builder_select.go b/vendor/xorm.io/builder/builder_select.go index c33b38698..814d1b5af 100644 --- a/vendor/xorm.io/builder/builder_select.go +++ b/vendor/xorm.io/builder/builder_select.go @@ -80,8 +80,21 @@ func (b *Builder) selectWriteTo(w Writer) error { } for _, v := range b.joins { - if _, err := fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable); err != nil { - return err + b, ok := v.joinTable.(*Builder) + 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 { diff --git a/vendor/xorm.io/builder/builder_update.go b/vendor/xorm.io/builder/builder_update.go index 37b455152..9b6e10bc9 100644 --- a/vendor/xorm.io/builder/builder_update.go +++ b/vendor/xorm.io/builder/builder_update.go @@ -8,8 +8,14 @@ import ( "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 -func Update(updates ...Eq) *Builder { +func Update(updates ...Cond) *Builder { builder := &Builder{cond: NewCond()} return builder.Update(updates...) } @@ -27,7 +33,8 @@ func (b *Builder) updateWriteTo(w Writer) error { } for i, s := range b.updates { - if err := s.opWriteTo(",", w); err != nil { + + if err := s.OpWriteTo(",", w); err != nil { return err } diff --git a/vendor/xorm.io/builder/cond.go b/vendor/xorm.io/builder/cond.go index e44173bbd..149f5d8cf 100644 --- a/vendor/xorm.io/builder/cond.go +++ b/vendor/xorm.io/builder/cond.go @@ -4,42 +4,6 @@ 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 type Cond interface { WriteTo(Writer) error diff --git a/vendor/xorm.io/builder/cond_eq.go b/vendor/xorm.io/builder/cond_eq.go index 79d795e6d..32f04d5d4 100644 --- a/vendor/xorm.io/builder/cond_eq.go +++ b/vendor/xorm.io/builder/cond_eq.go @@ -20,7 +20,8 @@ type Eq map[string]interface{} 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 for _, k := range eq.sortedKeys() { v := eq[k] @@ -81,7 +82,7 @@ func (eq Eq) opWriteTo(op string, w Writer) error { // WriteTo writes SQL to Writer func (eq Eq) WriteTo(w Writer) error { - return eq.opWriteTo(" AND ", w) + return eq.OpWriteTo(" AND ", w) } // 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. // 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 { keys := make([]string, 0, len(eq)) for key := range eq { diff --git a/vendor/xorm.io/builder/cond_expr.go b/vendor/xorm.io/builder/cond_expr.go index e5ed572b1..8288aa044 100644 --- a/vendor/xorm.io/builder/cond_expr.go +++ b/vendor/xorm.io/builder/cond_expr.go @@ -18,6 +18,10 @@ func Expr(sql string, args ...interface{}) Cond { return expr{sql, args} } +func (expr expr) OpWriteTo(op string, w Writer) error { + return expr.WriteTo(w) +} + func (expr expr) WriteTo(w Writer) error { if _, err := fmt.Fprint(w, expr.sql); err != nil { return err diff --git a/vendor/xorm.io/builder/cond_neq.go b/vendor/xorm.io/builder/cond_neq.go index 3a8f3136d..687c59fc2 100644 --- a/vendor/xorm.io/builder/cond_neq.go +++ b/vendor/xorm.io/builder/cond_neq.go @@ -83,7 +83,7 @@ func (neq Neq) IsValid() bool { // sortedKeys returns all keys of this Neq sorted with sort.Strings. // 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 { keys := make([]string, 0, len(neq)) for key := range neq { diff --git a/vendor/xorm.io/builder/doc.go b/vendor/xorm.io/builder/doc.go index 162b150f1..6e7dd452b 100644 --- a/vendor/xorm.io/builder/doc.go +++ b/vendor/xorm.io/builder/doc.go @@ -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: - go get github.com/go-xorm/builder + go get xorm.io/builder 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 - import . "github.com/go-xorm/builder" + import . "xorm.io/builder" sql, args, _ := ToSQL(Eq{"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 - import . "github.com/go-xorm/builder" + import . "xorm.io/builder" sql, args, _ := ToSQL(Neq{"a":1}) // a<>? [1] @@ -48,7 +48,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported 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})) // a>? AND b>=? [1, 2] @@ -57,14 +57,14 @@ WARNNING: Currently, only query conditions are supported. Below is the supported 4. Like - import . "github.com/go-xorm/builder" + import . "xorm.io/builder" sql, args, _ := ToSQL(Like{"a", "c"}) // a LIKE ? [%c%] 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)) // a = ? [1] @@ -73,7 +73,7 @@ WARNNING: Currently, only query conditions are supported. Below is the supported 6. In and NotIn - import . "github.com/go-xorm/builder" + import . "xorm.io/builder" sql, args, _ := ToSQL(In("a", 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 - import . "github.com/go-xorm/builder" + import . "xorm.io/builder" sql, args, _ := ToSQL(IsNull{"a"}) // 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 - import . "github.com/go-xorm/builder" + import . "xorm.io/builder" sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2})) // a=? AND b LIKE ? AND d<>? [1, %c%, 2] 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})) // 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 - import . "github.com/go-xorm/builder" + import . "xorm.io/builder" sql, args, _ := ToSQL(Between("a", 1, 2)) // a BETWEEN 1 AND 2 diff --git a/vendor/xorm.io/builder/error.go b/vendor/xorm.io/builder/error.go index d830ee995..b0ded29f2 100644 --- a/vendor/xorm.io/builder/error.go +++ b/vendor/xorm.io/builder/error.go @@ -17,9 +17,9 @@ var ( ErrNeedMoreArguments = errors.New("Need more sql arguments") // ErrNoTableName no table name ErrNoTableName = errors.New("No table indicated") - // ErrNoColumnToInsert no column to update + // ErrNoColumnToUpdate no column 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") // ErrNotSupportDialectType not supported dialect type error ErrNotSupportDialectType = errors.New("Not supported dialect type") diff --git a/vendor/xorm.io/builder/go.mod b/vendor/xorm.io/builder/go.mod index 35e43b329..9c730113f 100644 --- a/vendor/xorm.io/builder/go.mod +++ b/vendor/xorm.io/builder/go.mod @@ -1,5 +1,7 @@ module xorm.io/builder +go 1.11 + require ( github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a github.com/stretchr/testify v1.3.0 diff --git a/vendor/xorm.io/builder/sql.go b/vendor/xorm.io/builder/sql.go index 083424276..4250fea18 100644 --- a/vendor/xorm.io/builder/sql.go +++ b/vendor/xorm.io/builder/sql.go @@ -8,6 +8,7 @@ import ( sql2 "database/sql" "fmt" "reflect" + "strings" "time" ) @@ -20,7 +21,7 @@ func condToSQL(cond Cond) (string, []interface{}, error) { if err := cond.WriteTo(w); err != nil { return "", nil, err } - return w.writer.String(), w.args, nil + return w.String(), w.args, nil } func condToBoundSQL(cond Cond) (string, error) { @@ -32,7 +33,7 @@ func condToBoundSQL(cond Cond) (string, error) { if err := cond.WriteTo(w); err != nil { 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 @@ -92,7 +93,7 @@ func noSQLQuoteNeeded(a interface{}) bool { // ConvertToBoundSQL will convert SQL and args to a bound SQL func ConvertToBoundSQL(sql string, args []interface{}) (string, error) { - buf := StringBuilder{} + buf := strings.Builder{} var i, j, start int for ; i < len(sql); i++ { if sql[i] == '?' { @@ -114,7 +115,10 @@ func ConvertToBoundSQL(sql string, args []interface{}) (string, error) { if noSQLQuoteNeeded(arg) { _, err = fmt.Fprint(&buf, arg) } 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 { return "", err @@ -131,7 +135,7 @@ func ConvertToBoundSQL(sql string, args []interface{}) (string, error) { // ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix func ConvertPlaceholder(sql, prefix string) (string, error) { - buf := StringBuilder{} + buf := strings.Builder{} var i, j, start int for ; i < len(sql); i++ { if sql[i] == '?' { diff --git a/vendor/xorm.io/builder/string_builder.go b/vendor/xorm.io/builder/string_builder.go deleted file mode 100644 index d4de8717e..000000000 --- a/vendor/xorm.io/builder/string_builder.go +++ /dev/null @@ -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 -} diff --git a/vendor/xorm.io/builder/writer.go b/vendor/xorm.io/builder/writer.go new file mode 100644 index 000000000..fb4fae5c5 --- /dev/null +++ b/vendor/xorm.io/builder/writer.go @@ -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 +}