* Retry create issue to cope with duplicate keys * Use .SetExpr().Where().Insert()tags/v1.21.12.1
| @@ -45,7 +45,7 @@ require ( | |||
| github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect | |||
| github.com/go-redis/redis v6.15.2+incompatible | |||
| github.com/go-sql-driver/mysql v1.4.1 | |||
| github.com/go-xorm/xorm v0.7.4 | |||
| github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b | |||
| github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 | |||
| github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 | |||
| github.com/google/go-github/v24 v24.0.1 | |||
| @@ -117,5 +117,5 @@ require ( | |||
| 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/core v0.6.3 | |||
| xorm.io/core v0.7.0 | |||
| ) | |||
| @@ -143,6 +143,8 @@ github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk | |||
| github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= | |||
| github.com/go-xorm/xorm v0.7.4 h1:g/NgC590SzqV5VKmdRDNe/K3Holw3YJUCXX28r+rFGw= | |||
| github.com/go-xorm/xorm v0.7.4/go.mod h1:vpza5fydeRgt+stvo9qgMhSNohYqmNt0I1/D6hkCekA= | |||
| 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/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= | |||
| @@ -430,6 +432,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h | |||
| golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
| golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
| golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
| golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
| golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
| @@ -446,6 +449,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm | |||
| golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= | |||
| golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
| golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
| golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
| golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
| golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= | |||
| golang.org/x/tools v0.0.0-20190731214159-1e85ed8060aa h1:kwa/4M1dbmhZqOIqYiTtbA6JrvPwo1+jqlub2qDXX90= | |||
| @@ -454,6 +458,7 @@ google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMt | |||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | |||
| google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= | |||
| google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
| google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | |||
| @@ -509,3 +514,5 @@ xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A= | |||
| xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= | |||
| xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M= | |||
| xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo= | |||
| xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= | |||
| xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= | |||
| @@ -5,7 +5,6 @@ | |||
| package models | |||
| import ( | |||
| "errors" | |||
| "fmt" | |||
| "path" | |||
| "regexp" | |||
| @@ -74,6 +73,7 @@ var ( | |||
| const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)` | |||
| const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)` | |||
| const issueMaxDupIndexAttempts = 3 | |||
| func init() { | |||
| issueTasksPat = regexp.MustCompile(issueTasksRegexpStr) | |||
| @@ -1031,36 +1031,9 @@ type NewIssueOptions struct { | |||
| IsPull bool | |||
| } | |||
| // GetMaxIndexOfIssue returns the max index on issue | |||
| func GetMaxIndexOfIssue(repoID int64) (int64, error) { | |||
| return getMaxIndexOfIssue(x, repoID) | |||
| } | |||
| func getMaxIndexOfIssue(e Engine, repoID int64) (int64, error) { | |||
| var ( | |||
| maxIndex int64 | |||
| has bool | |||
| err error | |||
| ) | |||
| has, err = e.SQL("SELECT COALESCE((SELECT MAX(`index`) FROM issue WHERE repo_id = ?),0)", repoID).Get(&maxIndex) | |||
| if err != nil { | |||
| return 0, err | |||
| } else if !has { | |||
| return 0, errors.New("Retrieve Max index from issue failed") | |||
| } | |||
| return maxIndex, nil | |||
| } | |||
| func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { | |||
| opts.Issue.Title = strings.TrimSpace(opts.Issue.Title) | |||
| maxIndex, err := getMaxIndexOfIssue(e, opts.Issue.RepoID) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| opts.Issue.Index = maxIndex + 1 | |||
| if opts.Issue.MilestoneID > 0 { | |||
| milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID) | |||
| if err != nil && !IsErrMilestoneNotExist(err) { | |||
| @@ -1109,10 +1082,31 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { | |||
| } | |||
| // Milestone and assignee validation should happen before insert actual object. | |||
| if _, err = e.Insert(opts.Issue); err != nil { | |||
| // There's no good way to identify a duplicate key error in database/sql; brute force some retries | |||
| dupIndexAttempts := issueMaxDupIndexAttempts | |||
| for { | |||
| _, err := e.SetExpr("`index`", "coalesce(MAX(`index`),0)+1"). | |||
| Where("repo_id=?", opts.Issue.RepoID). | |||
| Insert(opts.Issue) | |||
| if err == nil { | |||
| break | |||
| } | |||
| dupIndexAttempts-- | |||
| if dupIndexAttempts <= 0 { | |||
| return err | |||
| } | |||
| } | |||
| inserted, err := getIssueByID(e, opts.Issue.ID) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| // Patch Index with the value calculated by the database | |||
| opts.Issue.Index = inserted.Index | |||
| if opts.Issue.MilestoneID > 0 { | |||
| if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil { | |||
| return err | |||
| @@ -252,15 +252,8 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption | |||
| deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix()) | |||
| } | |||
| maxIndex, err := models.GetMaxIndexOfIssue(repo.ID) | |||
| if err != nil { | |||
| ctx.ServerError("GetPatch", err) | |||
| return | |||
| } | |||
| prIssue := &models.Issue{ | |||
| RepoID: repo.ID, | |||
| Index: maxIndex + 1, | |||
| Title: form.Title, | |||
| PosterID: ctx.User.ID, | |||
| Poster: ctx.User, | |||
| @@ -710,15 +710,8 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) | |||
| return | |||
| } | |||
| maxIndex, err := models.GetMaxIndexOfIssue(repo.ID) | |||
| if err != nil { | |||
| ctx.ServerError("GetPatch", err) | |||
| return | |||
| } | |||
| pullIssue := &models.Issue{ | |||
| RepoID: repo.ID, | |||
| Index: maxIndex + 1, | |||
| Title: form.Title, | |||
| PosterID: ctx.User.ID, | |||
| Poster: ctx.User, | |||
| @@ -1,125 +1,431 @@ | |||
| --- | |||
| kind: pipeline | |||
| name: matrix-1 | |||
| platform: | |||
| os: linux | |||
| arch: amd64 | |||
| clone: | |||
| disable: true | |||
| workspace: | |||
| base: /go | |||
| path: src/github.com/go-xorm/xorm | |||
| steps: | |||
| - name: git | |||
| pull: default | |||
| image: plugins/git:next | |||
| settings: | |||
| depth: 50 | |||
| tags: true | |||
| - name: init_postgres | |||
| pull: default | |||
| image: postgres:9.5 | |||
| commands: | |||
| - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" | |||
| - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" | |||
| - name: build | |||
| pull: default | |||
| image: golang:1.10 | |||
| commands: | |||
| - go get -t -d -v ./... | |||
| - go get -u xorm.io/core | |||
| - go get -u xorm.io/builder | |||
| - go build -v | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-sqlite | |||
| pull: default | |||
| image: golang:1.10 | |||
| 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: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mysql | |||
| pull: default | |||
| image: golang:1.10 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mysql-utf8mb4 | |||
| pull: default | |||
| image: golang:1.10 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mymysql | |||
| pull: default | |||
| image: golang:1.10 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-postgres | |||
| pull: default | |||
| image: golang:1.10 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-postgres-schema | |||
| pull: default | |||
| image: golang:1.10 | |||
| 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 | |||
| services: | |||
| - name: mysql | |||
| pull: default | |||
| image: mysql:5.7 | |||
| environment: | |||
| MYSQL_ALLOW_EMPTY_PASSWORD: yes | |||
| MYSQL_DATABASE: xorm_test | |||
| when: | |||
| event: | |||
| - push | |||
| - tag | |||
| - pull_request | |||
| - name: pgsql | |||
| pull: default | |||
| image: postgres:9.5 | |||
| environment: | |||
| POSTGRES_DB: xorm_test | |||
| POSTGRES_USER: postgres | |||
| when: | |||
| event: | |||
| - push | |||
| - tag | |||
| - pull_request | |||
| --- | |||
| kind: pipeline | |||
| name: matrix-2 | |||
| platform: | |||
| os: linux | |||
| arch: amd64 | |||
| clone: | |||
| disable: true | |||
| workspace: | |||
| base: /go | |||
| path: src/github.com/go-xorm/xorm | |||
| steps: | |||
| - name: git | |||
| pull: default | |||
| image: plugins/git:next | |||
| settings: | |||
| depth: 50 | |||
| tags: true | |||
| - name: init_postgres | |||
| pull: default | |||
| image: postgres:9.5 | |||
| commands: | |||
| - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" | |||
| - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" | |||
| - name: build | |||
| pull: default | |||
| image: golang:1.11 | |||
| commands: | |||
| - go get -t -d -v ./... | |||
| - go get -u xorm.io/core | |||
| - go get -u xorm.io/builder | |||
| - GO111MODULE=off go build -v | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: build-gomod | |||
| pull: default | |||
| image: golang:1.11 | |||
| environment: | |||
| GOPROXY: "https://goproxy.cn" | |||
| commands: | |||
| - GO111MODULE=on go build -v | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-sqlite | |||
| pull: default | |||
| image: golang:1.11 | |||
| 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: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mysql | |||
| pull: default | |||
| image: golang:1.11 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mysql-utf8mb4 | |||
| pull: default | |||
| image: golang:1.11 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mymysql | |||
| pull: default | |||
| image: golang:1.11 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-postgres | |||
| pull: default | |||
| image: golang:1.11 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-postgres-schema | |||
| pull: default | |||
| image: golang:1.11 | |||
| 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 | |||
| services: | |||
| - name: mysql | |||
| pull: default | |||
| image: mysql:5.7 | |||
| environment: | |||
| MYSQL_ALLOW_EMPTY_PASSWORD: yes | |||
| MYSQL_DATABASE: xorm_test | |||
| when: | |||
| event: | |||
| - push | |||
| - tag | |||
| - pull_request | |||
| - name: pgsql | |||
| pull: default | |||
| image: postgres:9.5 | |||
| environment: | |||
| POSTGRES_DB: xorm_test | |||
| POSTGRES_USER: postgres | |||
| when: | |||
| event: | |||
| - push | |||
| - tag | |||
| - pull_request | |||
| --- | |||
| kind: pipeline | |||
| name: matrix-3 | |||
| platform: | |||
| os: linux | |||
| arch: amd64 | |||
| clone: | |||
| git: | |||
| image: plugins/git:next | |||
| disable: true | |||
| workspace: | |||
| base: /go | |||
| path: src/github.com/go-xorm/xorm | |||
| steps: | |||
| - name: git | |||
| pull: default | |||
| image: plugins/git:next | |||
| settings: | |||
| depth: 50 | |||
| tags: true | |||
| - name: init_postgres | |||
| pull: default | |||
| image: postgres:9.5 | |||
| commands: | |||
| - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" | |||
| - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" | |||
| - name: build | |||
| pull: default | |||
| image: golang:1.12 | |||
| commands: | |||
| - go get -t -d -v ./... | |||
| - go get -u xorm.io/core | |||
| - go get -u xorm.io/builder | |||
| - GO111MODULE=off go build -v | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: build-gomod | |||
| pull: default | |||
| image: golang:1.12 | |||
| environment: | |||
| GOPROXY: "https://goproxy.cn" | |||
| commands: | |||
| - GO111MODULE=on go build -v | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-sqlite | |||
| pull: default | |||
| image: golang:1.12 | |||
| 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: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mysql | |||
| pull: default | |||
| image: golang:1.12 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mysql-utf8mb4 | |||
| pull: default | |||
| image: golang:1.12 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-mymysql | |||
| pull: default | |||
| image: golang:1.12 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-postgres | |||
| pull: default | |||
| image: golang:1.12 | |||
| 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" | |||
| when: | |||
| event: | |||
| - push | |||
| - pull_request | |||
| - name: test-postgres-schema | |||
| pull: default | |||
| image: golang:1.12 | |||
| 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 | |||
| services: | |||
| mysql: | |||
| image: mysql:5.7 | |||
| environment: | |||
| - MYSQL_DATABASE=xorm_test | |||
| - MYSQL_ALLOW_EMPTY_PASSWORD=yes | |||
| when: | |||
| event: [ push, tag, pull_request ] | |||
| pgsql: | |||
| image: postgres:9.5 | |||
| environment: | |||
| - POSTGRES_USER=postgres | |||
| - POSTGRES_DB=xorm_test | |||
| when: | |||
| event: [ push, tag, pull_request ] | |||
| #mssql: | |||
| # image: microsoft/mssql-server-linux:2017-CU11 | |||
| # environment: | |||
| # - ACCEPT_EULA=Y | |||
| # - SA_PASSWORD=yourStrong(!)Password | |||
| # - MSSQL_PID=Developer | |||
| # commands: | |||
| # - echo 'CREATE DATABASE xorm_test' > create.sql | |||
| # - /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P yourStrong(!)Password -i "create.sql" | |||
| matrix: | |||
| GO_VERSION: | |||
| - 1.8 | |||
| - 1.9 | |||
| - 1.10 | |||
| - 1.11 | |||
| pipeline: | |||
| init_postgres: | |||
| image: postgres:9.5 | |||
| commands: | |||
| # wait for postgres service to become available | |||
| - | | |||
| until psql -U postgres -d xorm_test -h pgsql \ | |||
| -c "SELECT 1;" >/dev/null 2>&1; do sleep 1; done | |||
| # query the database | |||
| - | | |||
| psql -U postgres -d xorm_test -h pgsql \ | |||
| -c "create schema xorm;" | |||
| build: | |||
| image: golang:${GO_VERSION} | |||
| commands: | |||
| - go get -t -d -v ./... | |||
| - go get -u xorm.io/core | |||
| - go get -u xorm.io/builder | |||
| - go build -v | |||
| when: | |||
| event: [ push, pull_request ] | |||
| test-sqlite: | |||
| image: golang:${GO_VERSION} | |||
| 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: | |||
| event: [ push, pull_request ] | |||
| test-mysql: | |||
| image: golang:${GO_VERSION} | |||
| 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 | |||
| when: | |||
| event: [ push, pull_request ] | |||
| test-mysql-utf8mb4: | |||
| image: golang:${GO_VERSION} | |||
| 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 | |||
| when: | |||
| event: [ push, pull_request ] | |||
| test-mymysql: | |||
| image: golang:${GO_VERSION} | |||
| 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 | |||
| when: | |||
| event: [ push, pull_request ] | |||
| test-postgres: | |||
| image: golang:${GO_VERSION} | |||
| 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 | |||
| when: | |||
| event: [ push, pull_request ] | |||
| test-postgres-schema: | |||
| image: golang:${GO_VERSION} | |||
| 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 ] | |||
| #coverage: | |||
| # image: robertstettner/drone-codecov | |||
| # secrets: [ codecov_token ] | |||
| # files: | |||
| # - coverage.txt | |||
| # when: | |||
| # event: [ push, pull_request ] | |||
| # branch: [ master ] | |||
| - name: mysql | |||
| pull: default | |||
| image: mysql:5.7 | |||
| environment: | |||
| MYSQL_ALLOW_EMPTY_PASSWORD: yes | |||
| MYSQL_DATABASE: xorm_test | |||
| when: | |||
| event: | |||
| - push | |||
| - tag | |||
| - pull_request | |||
| - name: pgsql | |||
| pull: default | |||
| image: postgres:9.5 | |||
| environment: | |||
| POSTGRES_DB: xorm_test | |||
| POSTGRES_USER: postgres | |||
| when: | |||
| event: | |||
| - push | |||
| - tag | |||
| - pull_request | |||
| @@ -284,6 +284,13 @@ counts, err := engine.Count(&user) | |||
| // SELECT count(*) AS total FROM user | |||
| ``` | |||
| * `FindAndCount` combines function `Find` with `Count` which is usually used in query by page | |||
| ```Go | |||
| var users []User | |||
| counts, err := engine.FindAndCount(&users) | |||
| ``` | |||
| * `Sum` sum functions | |||
| ```Go | |||
| @@ -16,191 +16,191 @@ import ( | |||
| var ( | |||
| mssqlReservedWords = map[string]bool{ | |||
| "ADD": true, | |||
| "EXTERNAL": true, | |||
| "PROCEDURE": true, | |||
| "ALL": true, | |||
| "FETCH": true, | |||
| "PUBLIC": true, | |||
| "ALTER": true, | |||
| "FILE": true, | |||
| "RAISERROR": true, | |||
| "AND": true, | |||
| "FILLFACTOR": true, | |||
| "READ": true, | |||
| "ANY": true, | |||
| "FOR": true, | |||
| "READTEXT": true, | |||
| "AS": true, | |||
| "FOREIGN": true, | |||
| "RECONFIGURE": true, | |||
| "ASC": true, | |||
| "FREETEXT": true, | |||
| "REFERENCES": true, | |||
| "AUTHORIZATION": true, | |||
| "FREETEXTTABLE": true, | |||
| "REPLICATION": true, | |||
| "BACKUP": true, | |||
| "FROM": true, | |||
| "RESTORE": true, | |||
| "BEGIN": true, | |||
| "FULL": true, | |||
| "RESTRICT": true, | |||
| "BETWEEN": true, | |||
| "FUNCTION": true, | |||
| "RETURN": true, | |||
| "BREAK": true, | |||
| "GOTO": true, | |||
| "REVERT": true, | |||
| "BROWSE": true, | |||
| "GRANT": true, | |||
| "REVOKE": true, | |||
| "BULK": true, | |||
| "GROUP": true, | |||
| "RIGHT": true, | |||
| "BY": true, | |||
| "HAVING": true, | |||
| "ROLLBACK": true, | |||
| "CASCADE": true, | |||
| "HOLDLOCK": true, | |||
| "ROWCOUNT": true, | |||
| "CASE": true, | |||
| "IDENTITY": true, | |||
| "ROWGUIDCOL": true, | |||
| "CHECK": true, | |||
| "IDENTITY_INSERT": true, | |||
| "RULE": true, | |||
| "CHECKPOINT": true, | |||
| "IDENTITYCOL": true, | |||
| "SAVE": true, | |||
| "CLOSE": true, | |||
| "IF": true, | |||
| "SCHEMA": true, | |||
| "CLUSTERED": true, | |||
| "IN": true, | |||
| "SECURITYAUDIT": true, | |||
| "COALESCE": true, | |||
| "INDEX": true, | |||
| "SELECT": true, | |||
| "COLLATE": true, | |||
| "INNER": true, | |||
| "SEMANTICKEYPHRASETABLE": true, | |||
| "COLUMN": true, | |||
| "INSERT": true, | |||
| "ADD": true, | |||
| "EXTERNAL": true, | |||
| "PROCEDURE": true, | |||
| "ALL": true, | |||
| "FETCH": true, | |||
| "PUBLIC": true, | |||
| "ALTER": true, | |||
| "FILE": true, | |||
| "RAISERROR": true, | |||
| "AND": true, | |||
| "FILLFACTOR": true, | |||
| "READ": true, | |||
| "ANY": true, | |||
| "FOR": true, | |||
| "READTEXT": true, | |||
| "AS": true, | |||
| "FOREIGN": true, | |||
| "RECONFIGURE": true, | |||
| "ASC": true, | |||
| "FREETEXT": true, | |||
| "REFERENCES": true, | |||
| "AUTHORIZATION": true, | |||
| "FREETEXTTABLE": true, | |||
| "REPLICATION": true, | |||
| "BACKUP": true, | |||
| "FROM": true, | |||
| "RESTORE": true, | |||
| "BEGIN": true, | |||
| "FULL": true, | |||
| "RESTRICT": true, | |||
| "BETWEEN": true, | |||
| "FUNCTION": true, | |||
| "RETURN": true, | |||
| "BREAK": true, | |||
| "GOTO": true, | |||
| "REVERT": true, | |||
| "BROWSE": true, | |||
| "GRANT": true, | |||
| "REVOKE": true, | |||
| "BULK": true, | |||
| "GROUP": true, | |||
| "RIGHT": true, | |||
| "BY": true, | |||
| "HAVING": true, | |||
| "ROLLBACK": true, | |||
| "CASCADE": true, | |||
| "HOLDLOCK": true, | |||
| "ROWCOUNT": true, | |||
| "CASE": true, | |||
| "IDENTITY": true, | |||
| "ROWGUIDCOL": true, | |||
| "CHECK": true, | |||
| "IDENTITY_INSERT": true, | |||
| "RULE": true, | |||
| "CHECKPOINT": true, | |||
| "IDENTITYCOL": true, | |||
| "SAVE": true, | |||
| "CLOSE": true, | |||
| "IF": true, | |||
| "SCHEMA": true, | |||
| "CLUSTERED": true, | |||
| "IN": true, | |||
| "SECURITYAUDIT": true, | |||
| "COALESCE": true, | |||
| "INDEX": true, | |||
| "SELECT": true, | |||
| "COLLATE": true, | |||
| "INNER": true, | |||
| "SEMANTICKEYPHRASETABLE": true, | |||
| "COLUMN": true, | |||
| "INSERT": true, | |||
| "SEMANTICSIMILARITYDETAILSTABLE": true, | |||
| "COMMIT": true, | |||
| "INTERSECT": true, | |||
| "SEMANTICSIMILARITYTABLE": true, | |||
| "COMPUTE": true, | |||
| "INTO": true, | |||
| "SESSION_USER": true, | |||
| "CONSTRAINT": true, | |||
| "IS": true, | |||
| "SET": true, | |||
| "CONTAINS": true, | |||
| "JOIN": true, | |||
| "SETUSER": true, | |||
| "CONTAINSTABLE": true, | |||
| "KEY": true, | |||
| "SHUTDOWN": true, | |||
| "CONTINUE": true, | |||
| "KILL": true, | |||
| "SOME": true, | |||
| "CONVERT": true, | |||
| "LEFT": true, | |||
| "STATISTICS": true, | |||
| "CREATE": true, | |||
| "LIKE": true, | |||
| "SYSTEM_USER": true, | |||
| "CROSS": true, | |||
| "LINENO": true, | |||
| "TABLE": true, | |||
| "CURRENT": true, | |||
| "LOAD": true, | |||
| "TABLESAMPLE": true, | |||
| "CURRENT_DATE": true, | |||
| "MERGE": true, | |||
| "TEXTSIZE": true, | |||
| "CURRENT_TIME": true, | |||
| "NATIONAL": true, | |||
| "THEN": true, | |||
| "CURRENT_TIMESTAMP": true, | |||
| "NOCHECK": true, | |||
| "TO": true, | |||
| "CURRENT_USER": true, | |||
| "NONCLUSTERED": true, | |||
| "TOP": true, | |||
| "CURSOR": true, | |||
| "NOT": true, | |||
| "TRAN": true, | |||
| "DATABASE": true, | |||
| "NULL": true, | |||
| "TRANSACTION": true, | |||
| "DBCC": true, | |||
| "NULLIF": true, | |||
| "TRIGGER": true, | |||
| "DEALLOCATE": true, | |||
| "OF": true, | |||
| "TRUNCATE": true, | |||
| "DECLARE": true, | |||
| "OFF": true, | |||
| "TRY_CONVERT": true, | |||
| "DEFAULT": true, | |||
| "OFFSETS": true, | |||
| "TSEQUAL": true, | |||
| "DELETE": true, | |||
| "ON": true, | |||
| "UNION": true, | |||
| "DENY": true, | |||
| "OPEN": true, | |||
| "UNIQUE": true, | |||
| "DESC": true, | |||
| "OPENDATASOURCE": true, | |||
| "UNPIVOT": true, | |||
| "DISK": true, | |||
| "OPENQUERY": true, | |||
| "UPDATE": true, | |||
| "DISTINCT": true, | |||
| "OPENROWSET": true, | |||
| "UPDATETEXT": true, | |||
| "DISTRIBUTED": true, | |||
| "OPENXML": true, | |||
| "USE": true, | |||
| "DOUBLE": true, | |||
| "OPTION": true, | |||
| "USER": true, | |||
| "DROP": true, | |||
| "OR": true, | |||
| "VALUES": true, | |||
| "DUMP": true, | |||
| "ORDER": true, | |||
| "VARYING": true, | |||
| "ELSE": true, | |||
| "OUTER": true, | |||
| "VIEW": true, | |||
| "END": true, | |||
| "OVER": true, | |||
| "WAITFOR": true, | |||
| "ERRLVL": true, | |||
| "PERCENT": true, | |||
| "WHEN": true, | |||
| "ESCAPE": true, | |||
| "PIVOT": true, | |||
| "WHERE": true, | |||
| "EXCEPT": true, | |||
| "PLAN": true, | |||
| "WHILE": true, | |||
| "EXEC": true, | |||
| "PRECISION": true, | |||
| "WITH": true, | |||
| "EXECUTE": true, | |||
| "PRIMARY": true, | |||
| "WITHIN": true, | |||
| "EXISTS": true, | |||
| "PRINT": true, | |||
| "WRITETEXT": true, | |||
| "EXIT": true, | |||
| "PROC": true, | |||
| "COMMIT": true, | |||
| "INTERSECT": true, | |||
| "SEMANTICSIMILARITYTABLE": true, | |||
| "COMPUTE": true, | |||
| "INTO": true, | |||
| "SESSION_USER": true, | |||
| "CONSTRAINT": true, | |||
| "IS": true, | |||
| "SET": true, | |||
| "CONTAINS": true, | |||
| "JOIN": true, | |||
| "SETUSER": true, | |||
| "CONTAINSTABLE": true, | |||
| "KEY": true, | |||
| "SHUTDOWN": true, | |||
| "CONTINUE": true, | |||
| "KILL": true, | |||
| "SOME": true, | |||
| "CONVERT": true, | |||
| "LEFT": true, | |||
| "STATISTICS": true, | |||
| "CREATE": true, | |||
| "LIKE": true, | |||
| "SYSTEM_USER": true, | |||
| "CROSS": true, | |||
| "LINENO": true, | |||
| "TABLE": true, | |||
| "CURRENT": true, | |||
| "LOAD": true, | |||
| "TABLESAMPLE": true, | |||
| "CURRENT_DATE": true, | |||
| "MERGE": true, | |||
| "TEXTSIZE": true, | |||
| "CURRENT_TIME": true, | |||
| "NATIONAL": true, | |||
| "THEN": true, | |||
| "CURRENT_TIMESTAMP": true, | |||
| "NOCHECK": true, | |||
| "TO": true, | |||
| "CURRENT_USER": true, | |||
| "NONCLUSTERED": true, | |||
| "TOP": true, | |||
| "CURSOR": true, | |||
| "NOT": true, | |||
| "TRAN": true, | |||
| "DATABASE": true, | |||
| "NULL": true, | |||
| "TRANSACTION": true, | |||
| "DBCC": true, | |||
| "NULLIF": true, | |||
| "TRIGGER": true, | |||
| "DEALLOCATE": true, | |||
| "OF": true, | |||
| "TRUNCATE": true, | |||
| "DECLARE": true, | |||
| "OFF": true, | |||
| "TRY_CONVERT": true, | |||
| "DEFAULT": true, | |||
| "OFFSETS": true, | |||
| "TSEQUAL": true, | |||
| "DELETE": true, | |||
| "ON": true, | |||
| "UNION": true, | |||
| "DENY": true, | |||
| "OPEN": true, | |||
| "UNIQUE": true, | |||
| "DESC": true, | |||
| "OPENDATASOURCE": true, | |||
| "UNPIVOT": true, | |||
| "DISK": true, | |||
| "OPENQUERY": true, | |||
| "UPDATE": true, | |||
| "DISTINCT": true, | |||
| "OPENROWSET": true, | |||
| "UPDATETEXT": true, | |||
| "DISTRIBUTED": true, | |||
| "OPENXML": true, | |||
| "USE": true, | |||
| "DOUBLE": true, | |||
| "OPTION": true, | |||
| "USER": true, | |||
| "DROP": true, | |||
| "OR": true, | |||
| "VALUES": true, | |||
| "DUMP": true, | |||
| "ORDER": true, | |||
| "VARYING": true, | |||
| "ELSE": true, | |||
| "OUTER": true, | |||
| "VIEW": true, | |||
| "END": true, | |||
| "OVER": true, | |||
| "WAITFOR": true, | |||
| "ERRLVL": true, | |||
| "PERCENT": true, | |||
| "WHEN": true, | |||
| "ESCAPE": true, | |||
| "PIVOT": true, | |||
| "WHERE": true, | |||
| "EXCEPT": true, | |||
| "PLAN": true, | |||
| "WHILE": true, | |||
| "EXEC": true, | |||
| "PRECISION": true, | |||
| "WITH": true, | |||
| "EXECUTE": true, | |||
| "PRIMARY": true, | |||
| "WITHIN": true, | |||
| "EXISTS": true, | |||
| "PRINT": true, | |||
| "WRITETEXT": true, | |||
| "EXIT": true, | |||
| "PROC": true, | |||
| } | |||
| ) | |||
| @@ -286,10 +286,6 @@ func (db *mssql) Quote(name string) string { | |||
| return "\"" + name + "\"" | |||
| } | |||
| func (db *mssql) QuoteStr() string { | |||
| return "\"" | |||
| } | |||
| func (db *mssql) SupportEngine() bool { | |||
| return false | |||
| } | |||
| @@ -507,7 +503,7 @@ func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, chars | |||
| sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE " | |||
| sql += db.QuoteStr() + tableName + db.QuoteStr() + " (" | |||
| sql += db.Quote(tableName) + " (" | |||
| pkList := table.PrimaryKeys | |||
| @@ -220,7 +220,7 @@ func (db *mysql) SqlType(c *core.Column) string { | |||
| case core.TimeStampz: | |||
| res = core.Char | |||
| c.Length = 64 | |||
| case core.Enum: //mysql enum | |||
| case core.Enum: // mysql enum | |||
| res = core.Enum | |||
| res += "(" | |||
| opts := "" | |||
| @@ -229,7 +229,7 @@ func (db *mysql) SqlType(c *core.Column) string { | |||
| } | |||
| res += strings.TrimLeft(opts, ",") | |||
| res += ")" | |||
| case core.Set: //mysql set | |||
| case core.Set: // mysql set | |||
| res = core.Set | |||
| res += "(" | |||
| opts := "" | |||
| @@ -278,10 +278,6 @@ func (db *mysql) Quote(name string) string { | |||
| return "`" + name + "`" | |||
| } | |||
| func (db *mysql) QuoteStr() string { | |||
| return "`" | |||
| } | |||
| func (db *mysql) SupportEngine() bool { | |||
| return true | |||
| } | |||
| @@ -360,7 +356,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column | |||
| var len1, len2 int | |||
| if len(cts) == 2 { | |||
| idx := strings.Index(cts[1], ")") | |||
| if colType == core.Enum && cts[1][0] == '\'' { //enum | |||
| if colType == core.Enum && cts[1][0] == '\'' { // enum | |||
| options := strings.Split(cts[1][0:idx], ",") | |||
| col.EnumOptions = make(map[string]int) | |||
| for k, v := range options { | |||
| @@ -408,7 +404,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column | |||
| col.IsPrimaryKey = true | |||
| } | |||
| if colKey == "UNI" { | |||
| //col.is | |||
| // col.is | |||
| } | |||
| if extra == "auto_increment" { | |||
| @@ -554,12 +550,10 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars | |||
| if len(charset) == 0 { | |||
| charset = db.URI().Charset | |||
| } | |||
| } | |||
| if len(charset) != 0 { | |||
| sql += " DEFAULT CHARSET " + charset | |||
| } | |||
| if db.rowFormat != "" { | |||
| sql += " ROW_FORMAT=" + db.rowFormat | |||
| @@ -633,7 +627,7 @@ func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error | |||
| `\/(?P<dbname>.*?)` + // /dbname | |||
| `(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1¶mN=valueN] | |||
| matches := dsnPattern.FindStringSubmatch(dataSourceName) | |||
| //tlsConfigRegister := make(map[string]*tls.Config) | |||
| // tlsConfigRegister := make(map[string]*tls.Config) | |||
| names := dsnPattern.SubexpNames() | |||
| uri := &core.Uri{DbType: core.MYSQL} | |||
| @@ -230,271 +230,271 @@ var ( | |||
| "LOGGING": true, | |||
| "LOGICAL_READS_PER_CALL": true, | |||
| "LOGICAL_READS_PER_SESSION": true, | |||
| "LONG": true, | |||
| "MANAGE": true, | |||
| "MASTER": true, | |||
| "MAX": true, | |||
| "MAXARCHLOGS": true, | |||
| "MAXDATAFILES": true, | |||
| "MAXEXTENTS": true, | |||
| "MAXINSTANCES": true, | |||
| "MAXLOGFILES": true, | |||
| "MAXLOGHISTORY": true, | |||
| "MAXLOGMEMBERS": true, | |||
| "MAXSIZE": true, | |||
| "MAXTRANS": true, | |||
| "MAXVALUE": true, | |||
| "MIN": true, | |||
| "MEMBER": true, | |||
| "MINIMUM": true, | |||
| "MINEXTENTS": true, | |||
| "MINUS": true, | |||
| "MINVALUE": true, | |||
| "MLSLABEL": true, | |||
| "MLS_LABEL_FORMAT": true, | |||
| "MODE": true, | |||
| "MODIFY": true, | |||
| "MOUNT": true, | |||
| "MOVE": true, | |||
| "MTS_DISPATCHERS": true, | |||
| "MULTISET": true, | |||
| "NATIONAL": true, | |||
| "NCHAR": true, | |||
| "NCHAR_CS": true, | |||
| "NCLOB": true, | |||
| "NEEDED": true, | |||
| "NESTED": true, | |||
| "NETWORK": true, | |||
| "NEW": true, | |||
| "NEXT": true, | |||
| "NOARCHIVELOG": true, | |||
| "NOAUDIT": true, | |||
| "NOCACHE": true, | |||
| "NOCOMPRESS": true, | |||
| "NOCYCLE": true, | |||
| "NOFORCE": true, | |||
| "NOLOGGING": true, | |||
| "NOMAXVALUE": true, | |||
| "NOMINVALUE": true, | |||
| "NONE": true, | |||
| "NOORDER": true, | |||
| "NOOVERRIDE": true, | |||
| "NOPARALLEL": true, | |||
| "NOREVERSE": true, | |||
| "NORMAL": true, | |||
| "NOSORT": true, | |||
| "NOT": true, | |||
| "NOTHING": true, | |||
| "NOWAIT": true, | |||
| "NULL": true, | |||
| "NUMBER": true, | |||
| "NUMERIC": true, | |||
| "NVARCHAR2": true, | |||
| "OBJECT": true, | |||
| "OBJNO": true, | |||
| "OBJNO_REUSE": true, | |||
| "OF": true, | |||
| "OFF": true, | |||
| "OFFLINE": true, | |||
| "OID": true, | |||
| "OIDINDEX": true, | |||
| "OLD": true, | |||
| "ON": true, | |||
| "ONLINE": true, | |||
| "ONLY": true, | |||
| "OPCODE": true, | |||
| "OPEN": true, | |||
| "OPTIMAL": true, | |||
| "OPTIMIZER_GOAL": true, | |||
| "OPTION": true, | |||
| "OR": true, | |||
| "ORDER": true, | |||
| "ORGANIZATION": true, | |||
| "OSLABEL": true, | |||
| "OVERFLOW": true, | |||
| "OWN": true, | |||
| "PACKAGE": true, | |||
| "PARALLEL": true, | |||
| "PARTITION": true, | |||
| "PASSWORD": true, | |||
| "PASSWORD_GRACE_TIME": true, | |||
| "PASSWORD_LIFE_TIME": true, | |||
| "PASSWORD_LOCK_TIME": true, | |||
| "PASSWORD_REUSE_MAX": true, | |||
| "PASSWORD_REUSE_TIME": true, | |||
| "PASSWORD_VERIFY_FUNCTION": true, | |||
| "PCTFREE": true, | |||
| "PCTINCREASE": true, | |||
| "PCTTHRESHOLD": true, | |||
| "PCTUSED": true, | |||
| "PCTVERSION": true, | |||
| "PERCENT": true, | |||
| "PERMANENT": true, | |||
| "PLAN": true, | |||
| "PLSQL_DEBUG": true, | |||
| "POST_TRANSACTION": true, | |||
| "PRECISION": true, | |||
| "PRESERVE": true, | |||
| "PRIMARY": true, | |||
| "PRIOR": true, | |||
| "PRIVATE": true, | |||
| "PRIVATE_SGA": true, | |||
| "PRIVILEGE": true, | |||
| "PRIVILEGES": true, | |||
| "PROCEDURE": true, | |||
| "PROFILE": true, | |||
| "PUBLIC": true, | |||
| "PURGE": true, | |||
| "QUEUE": true, | |||
| "QUOTA": true, | |||
| "RANGE": true, | |||
| "RAW": true, | |||
| "RBA": true, | |||
| "READ": true, | |||
| "READUP": true, | |||
| "REAL": true, | |||
| "REBUILD": true, | |||
| "RECOVER": true, | |||
| "RECOVERABLE": true, | |||
| "RECOVERY": true, | |||
| "REF": true, | |||
| "REFERENCES": true, | |||
| "REFERENCING": true, | |||
| "REFRESH": true, | |||
| "RENAME": true, | |||
| "REPLACE": true, | |||
| "RESET": true, | |||
| "RESETLOGS": true, | |||
| "RESIZE": true, | |||
| "RESOURCE": true, | |||
| "RESTRICTED": true, | |||
| "RETURN": true, | |||
| "RETURNING": true, | |||
| "REUSE": true, | |||
| "REVERSE": true, | |||
| "REVOKE": true, | |||
| "ROLE": true, | |||
| "ROLES": true, | |||
| "ROLLBACK": true, | |||
| "ROW": true, | |||
| "ROWID": true, | |||
| "ROWNUM": true, | |||
| "ROWS": true, | |||
| "RULE": true, | |||
| "SAMPLE": true, | |||
| "SAVEPOINT": true, | |||
| "SB4": true, | |||
| "SCAN_INSTANCES": true, | |||
| "SCHEMA": true, | |||
| "SCN": true, | |||
| "SCOPE": true, | |||
| "SD_ALL": true, | |||
| "SD_INHIBIT": true, | |||
| "SD_SHOW": true, | |||
| "SEGMENT": true, | |||
| "SEG_BLOCK": true, | |||
| "SEG_FILE": true, | |||
| "SELECT": true, | |||
| "SEQUENCE": true, | |||
| "SERIALIZABLE": true, | |||
| "SESSION": true, | |||
| "SESSION_CACHED_CURSORS": true, | |||
| "SESSIONS_PER_USER": true, | |||
| "SET": true, | |||
| "SHARE": true, | |||
| "SHARED": true, | |||
| "SHARED_POOL": true, | |||
| "SHRINK": true, | |||
| "SIZE": true, | |||
| "SKIP": true, | |||
| "SKIP_UNUSABLE_INDEXES": true, | |||
| "SMALLINT": true, | |||
| "SNAPSHOT": true, | |||
| "SOME": true, | |||
| "SORT": true, | |||
| "SPECIFICATION": true, | |||
| "SPLIT": true, | |||
| "SQL_TRACE": true, | |||
| "STANDBY": true, | |||
| "START": true, | |||
| "STATEMENT_ID": true, | |||
| "STATISTICS": true, | |||
| "STOP": true, | |||
| "STORAGE": true, | |||
| "STORE": true, | |||
| "STRUCTURE": true, | |||
| "SUCCESSFUL": true, | |||
| "SWITCH": true, | |||
| "SYS_OP_ENFORCE_NOT_NULL$": true, | |||
| "SYS_OP_NTCIMG$": true, | |||
| "SYNONYM": true, | |||
| "SYSDATE": true, | |||
| "SYSDBA": true, | |||
| "SYSOPER": true, | |||
| "SYSTEM": true, | |||
| "TABLE": true, | |||
| "TABLES": true, | |||
| "TABLESPACE": true, | |||
| "TABLESPACE_NO": true, | |||
| "TABNO": true, | |||
| "TEMPORARY": true, | |||
| "THAN": true, | |||
| "THE": true, | |||
| "THEN": true, | |||
| "THREAD": true, | |||
| "TIMESTAMP": true, | |||
| "TIME": true, | |||
| "TO": true, | |||
| "TOPLEVEL": true, | |||
| "TRACE": true, | |||
| "TRACING": true, | |||
| "TRANSACTION": true, | |||
| "TRANSITIONAL": true, | |||
| "TRIGGER": true, | |||
| "TRIGGERS": true, | |||
| "TRUE": true, | |||
| "TRUNCATE": true, | |||
| "TX": true, | |||
| "TYPE": true, | |||
| "UB2": true, | |||
| "UBA": true, | |||
| "UID": true, | |||
| "UNARCHIVED": true, | |||
| "UNDO": true, | |||
| "UNION": true, | |||
| "UNIQUE": true, | |||
| "UNLIMITED": true, | |||
| "UNLOCK": true, | |||
| "UNRECOVERABLE": true, | |||
| "UNTIL": true, | |||
| "UNUSABLE": true, | |||
| "UNUSED": true, | |||
| "UPDATABLE": true, | |||
| "UPDATE": true, | |||
| "USAGE": true, | |||
| "USE": true, | |||
| "USER": true, | |||
| "USING": true, | |||
| "VALIDATE": true, | |||
| "VALIDATION": true, | |||
| "VALUE": true, | |||
| "VALUES": true, | |||
| "VARCHAR": true, | |||
| "VARCHAR2": true, | |||
| "VARYING": true, | |||
| "VIEW": true, | |||
| "WHEN": true, | |||
| "WHENEVER": true, | |||
| "WHERE": true, | |||
| "WITH": true, | |||
| "WITHOUT": true, | |||
| "WORK": true, | |||
| "WRITE": true, | |||
| "WRITEDOWN": true, | |||
| "WRITEUP": true, | |||
| "XID": true, | |||
| "YEAR": true, | |||
| "ZONE": true, | |||
| "LONG": true, | |||
| "MANAGE": true, | |||
| "MASTER": true, | |||
| "MAX": true, | |||
| "MAXARCHLOGS": true, | |||
| "MAXDATAFILES": true, | |||
| "MAXEXTENTS": true, | |||
| "MAXINSTANCES": true, | |||
| "MAXLOGFILES": true, | |||
| "MAXLOGHISTORY": true, | |||
| "MAXLOGMEMBERS": true, | |||
| "MAXSIZE": true, | |||
| "MAXTRANS": true, | |||
| "MAXVALUE": true, | |||
| "MIN": true, | |||
| "MEMBER": true, | |||
| "MINIMUM": true, | |||
| "MINEXTENTS": true, | |||
| "MINUS": true, | |||
| "MINVALUE": true, | |||
| "MLSLABEL": true, | |||
| "MLS_LABEL_FORMAT": true, | |||
| "MODE": true, | |||
| "MODIFY": true, | |||
| "MOUNT": true, | |||
| "MOVE": true, | |||
| "MTS_DISPATCHERS": true, | |||
| "MULTISET": true, | |||
| "NATIONAL": true, | |||
| "NCHAR": true, | |||
| "NCHAR_CS": true, | |||
| "NCLOB": true, | |||
| "NEEDED": true, | |||
| "NESTED": true, | |||
| "NETWORK": true, | |||
| "NEW": true, | |||
| "NEXT": true, | |||
| "NOARCHIVELOG": true, | |||
| "NOAUDIT": true, | |||
| "NOCACHE": true, | |||
| "NOCOMPRESS": true, | |||
| "NOCYCLE": true, | |||
| "NOFORCE": true, | |||
| "NOLOGGING": true, | |||
| "NOMAXVALUE": true, | |||
| "NOMINVALUE": true, | |||
| "NONE": true, | |||
| "NOORDER": true, | |||
| "NOOVERRIDE": true, | |||
| "NOPARALLEL": true, | |||
| "NOREVERSE": true, | |||
| "NORMAL": true, | |||
| "NOSORT": true, | |||
| "NOT": true, | |||
| "NOTHING": true, | |||
| "NOWAIT": true, | |||
| "NULL": true, | |||
| "NUMBER": true, | |||
| "NUMERIC": true, | |||
| "NVARCHAR2": true, | |||
| "OBJECT": true, | |||
| "OBJNO": true, | |||
| "OBJNO_REUSE": true, | |||
| "OF": true, | |||
| "OFF": true, | |||
| "OFFLINE": true, | |||
| "OID": true, | |||
| "OIDINDEX": true, | |||
| "OLD": true, | |||
| "ON": true, | |||
| "ONLINE": true, | |||
| "ONLY": true, | |||
| "OPCODE": true, | |||
| "OPEN": true, | |||
| "OPTIMAL": true, | |||
| "OPTIMIZER_GOAL": true, | |||
| "OPTION": true, | |||
| "OR": true, | |||
| "ORDER": true, | |||
| "ORGANIZATION": true, | |||
| "OSLABEL": true, | |||
| "OVERFLOW": true, | |||
| "OWN": true, | |||
| "PACKAGE": true, | |||
| "PARALLEL": true, | |||
| "PARTITION": true, | |||
| "PASSWORD": true, | |||
| "PASSWORD_GRACE_TIME": true, | |||
| "PASSWORD_LIFE_TIME": true, | |||
| "PASSWORD_LOCK_TIME": true, | |||
| "PASSWORD_REUSE_MAX": true, | |||
| "PASSWORD_REUSE_TIME": true, | |||
| "PASSWORD_VERIFY_FUNCTION": true, | |||
| "PCTFREE": true, | |||
| "PCTINCREASE": true, | |||
| "PCTTHRESHOLD": true, | |||
| "PCTUSED": true, | |||
| "PCTVERSION": true, | |||
| "PERCENT": true, | |||
| "PERMANENT": true, | |||
| "PLAN": true, | |||
| "PLSQL_DEBUG": true, | |||
| "POST_TRANSACTION": true, | |||
| "PRECISION": true, | |||
| "PRESERVE": true, | |||
| "PRIMARY": true, | |||
| "PRIOR": true, | |||
| "PRIVATE": true, | |||
| "PRIVATE_SGA": true, | |||
| "PRIVILEGE": true, | |||
| "PRIVILEGES": true, | |||
| "PROCEDURE": true, | |||
| "PROFILE": true, | |||
| "PUBLIC": true, | |||
| "PURGE": true, | |||
| "QUEUE": true, | |||
| "QUOTA": true, | |||
| "RANGE": true, | |||
| "RAW": true, | |||
| "RBA": true, | |||
| "READ": true, | |||
| "READUP": true, | |||
| "REAL": true, | |||
| "REBUILD": true, | |||
| "RECOVER": true, | |||
| "RECOVERABLE": true, | |||
| "RECOVERY": true, | |||
| "REF": true, | |||
| "REFERENCES": true, | |||
| "REFERENCING": true, | |||
| "REFRESH": true, | |||
| "RENAME": true, | |||
| "REPLACE": true, | |||
| "RESET": true, | |||
| "RESETLOGS": true, | |||
| "RESIZE": true, | |||
| "RESOURCE": true, | |||
| "RESTRICTED": true, | |||
| "RETURN": true, | |||
| "RETURNING": true, | |||
| "REUSE": true, | |||
| "REVERSE": true, | |||
| "REVOKE": true, | |||
| "ROLE": true, | |||
| "ROLES": true, | |||
| "ROLLBACK": true, | |||
| "ROW": true, | |||
| "ROWID": true, | |||
| "ROWNUM": true, | |||
| "ROWS": true, | |||
| "RULE": true, | |||
| "SAMPLE": true, | |||
| "SAVEPOINT": true, | |||
| "SB4": true, | |||
| "SCAN_INSTANCES": true, | |||
| "SCHEMA": true, | |||
| "SCN": true, | |||
| "SCOPE": true, | |||
| "SD_ALL": true, | |||
| "SD_INHIBIT": true, | |||
| "SD_SHOW": true, | |||
| "SEGMENT": true, | |||
| "SEG_BLOCK": true, | |||
| "SEG_FILE": true, | |||
| "SELECT": true, | |||
| "SEQUENCE": true, | |||
| "SERIALIZABLE": true, | |||
| "SESSION": true, | |||
| "SESSION_CACHED_CURSORS": true, | |||
| "SESSIONS_PER_USER": true, | |||
| "SET": true, | |||
| "SHARE": true, | |||
| "SHARED": true, | |||
| "SHARED_POOL": true, | |||
| "SHRINK": true, | |||
| "SIZE": true, | |||
| "SKIP": true, | |||
| "SKIP_UNUSABLE_INDEXES": true, | |||
| "SMALLINT": true, | |||
| "SNAPSHOT": true, | |||
| "SOME": true, | |||
| "SORT": true, | |||
| "SPECIFICATION": true, | |||
| "SPLIT": true, | |||
| "SQL_TRACE": true, | |||
| "STANDBY": true, | |||
| "START": true, | |||
| "STATEMENT_ID": true, | |||
| "STATISTICS": true, | |||
| "STOP": true, | |||
| "STORAGE": true, | |||
| "STORE": true, | |||
| "STRUCTURE": true, | |||
| "SUCCESSFUL": true, | |||
| "SWITCH": true, | |||
| "SYS_OP_ENFORCE_NOT_NULL$": true, | |||
| "SYS_OP_NTCIMG$": true, | |||
| "SYNONYM": true, | |||
| "SYSDATE": true, | |||
| "SYSDBA": true, | |||
| "SYSOPER": true, | |||
| "SYSTEM": true, | |||
| "TABLE": true, | |||
| "TABLES": true, | |||
| "TABLESPACE": true, | |||
| "TABLESPACE_NO": true, | |||
| "TABNO": true, | |||
| "TEMPORARY": true, | |||
| "THAN": true, | |||
| "THE": true, | |||
| "THEN": true, | |||
| "THREAD": true, | |||
| "TIMESTAMP": true, | |||
| "TIME": true, | |||
| "TO": true, | |||
| "TOPLEVEL": true, | |||
| "TRACE": true, | |||
| "TRACING": true, | |||
| "TRANSACTION": true, | |||
| "TRANSITIONAL": true, | |||
| "TRIGGER": true, | |||
| "TRIGGERS": true, | |||
| "TRUE": true, | |||
| "TRUNCATE": true, | |||
| "TX": true, | |||
| "TYPE": true, | |||
| "UB2": true, | |||
| "UBA": true, | |||
| "UID": true, | |||
| "UNARCHIVED": true, | |||
| "UNDO": true, | |||
| "UNION": true, | |||
| "UNIQUE": true, | |||
| "UNLIMITED": true, | |||
| "UNLOCK": true, | |||
| "UNRECOVERABLE": true, | |||
| "UNTIL": true, | |||
| "UNUSABLE": true, | |||
| "UNUSED": true, | |||
| "UPDATABLE": true, | |||
| "UPDATE": true, | |||
| "USAGE": true, | |||
| "USE": true, | |||
| "USER": true, | |||
| "USING": true, | |||
| "VALIDATE": true, | |||
| "VALIDATION": true, | |||
| "VALUE": true, | |||
| "VALUES": true, | |||
| "VARCHAR": true, | |||
| "VARCHAR2": true, | |||
| "VARYING": true, | |||
| "VIEW": true, | |||
| "WHEN": true, | |||
| "WHENEVER": true, | |||
| "WHERE": true, | |||
| "WITH": true, | |||
| "WITHOUT": true, | |||
| "WORK": true, | |||
| "WRITE": true, | |||
| "WRITEDOWN": true, | |||
| "WRITEUP": true, | |||
| "XID": true, | |||
| "YEAR": true, | |||
| "ZONE": true, | |||
| } | |||
| ) | |||
| @@ -552,11 +552,7 @@ func (db *oracle) IsReserved(name string) bool { | |||
| } | |||
| func (db *oracle) Quote(name string) string { | |||
| return "\"" + name + "\"" | |||
| } | |||
| func (db *oracle) QuoteStr() string { | |||
| return "\"" | |||
| return "[" + name + "]" | |||
| } | |||
| func (db *oracle) SupportEngine() bool { | |||
| @@ -596,7 +592,7 @@ func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, char | |||
| sql += col.String(b.dialect) | |||
| } else {*/ | |||
| sql += col.StringNoPk(db) | |||
| //} | |||
| // } | |||
| sql = strings.TrimSpace(sql) | |||
| sql += ", " | |||
| } | |||
| @@ -865,7 +861,7 @@ func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, e | |||
| `\/(?P<dbname>.*?)` + // /dbname | |||
| `(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1¶mN=valueN] | |||
| matches := dsnPattern.FindStringSubmatch(dataSourceName) | |||
| //tlsConfigRegister := make(map[string]*tls.Config) | |||
| // tlsConfigRegister := make(map[string]*tls.Config) | |||
| names := dsnPattern.SubexpNames() | |||
| for i, match := range matches { | |||
| @@ -883,8 +879,8 @@ func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, e | |||
| type oci8Driver struct { | |||
| } | |||
| //dataSourceName=user/password@ipv4:port/dbname | |||
| //dataSourceName=user/password@[ipv6]:port/dbname | |||
| // dataSourceName=user/password@ipv4:port/dbname | |||
| // dataSourceName=user/password@[ipv6]:port/dbname | |||
| func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) { | |||
| db := &core.Uri{DbType: core.ORACLE} | |||
| dsnPattern := regexp.MustCompile( | |||
| @@ -202,10 +202,6 @@ func (db *sqlite3) Quote(name string) string { | |||
| return "`" + name + "`" | |||
| } | |||
| func (db *sqlite3) QuoteStr() string { | |||
| return "`" | |||
| } | |||
| func (db *sqlite3) AutoIncrStr() string { | |||
| return "AUTOINCREMENT" | |||
| } | |||
| @@ -175,12 +175,6 @@ func (engine *Engine) SupportInsertMany() bool { | |||
| return engine.dialect.SupportInsertMany() | |||
| } | |||
| // QuoteStr Engine's database use which character as quote. | |||
| // mysql, sqlite use ` and postgres use " | |||
| func (engine *Engine) QuoteStr() string { | |||
| return engine.dialect.QuoteStr() | |||
| } | |||
| func (engine *Engine) quoteColumns(columnStr string) string { | |||
| columns := strings.Split(columnStr, ",") | |||
| for i := 0; i < len(columns); i++ { | |||
| @@ -196,13 +190,10 @@ func (engine *Engine) Quote(value string) string { | |||
| return value | |||
| } | |||
| if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' { | |||
| return value | |||
| } | |||
| value = strings.Replace(value, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1) | |||
| buf := builder.StringBuilder{} | |||
| engine.QuoteTo(&buf, value) | |||
| return engine.dialect.QuoteStr() + value + engine.dialect.QuoteStr() | |||
| return buf.String() | |||
| } | |||
| // QuoteTo quotes string and writes into the buffer | |||
| @@ -216,20 +207,30 @@ func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) { | |||
| return | |||
| } | |||
| if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' { | |||
| buf.WriteString(value) | |||
| quotePair := engine.dialect.Quote("") | |||
| if value[0] == '`' || len(quotePair) < 2 || value[0] == quotePair[0] { // no quote | |||
| _, _ = buf.WriteString(value) | |||
| return | |||
| } else { | |||
| prefix, suffix := quotePair[0], quotePair[1] | |||
| _ = buf.WriteByte(prefix) | |||
| for i := 0; i < len(value); i++ { | |||
| if value[i] == '.' { | |||
| _ = buf.WriteByte(suffix) | |||
| _ = buf.WriteByte('.') | |||
| _ = buf.WriteByte(prefix) | |||
| } else { | |||
| _ = buf.WriteByte(value[i]) | |||
| } | |||
| } | |||
| _ = buf.WriteByte(suffix) | |||
| } | |||
| value = strings.Replace(value, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1) | |||
| buf.WriteString(engine.dialect.QuoteStr()) | |||
| buf.WriteString(value) | |||
| buf.WriteString(engine.dialect.QuoteStr()) | |||
| } | |||
| func (engine *Engine) quote(sql string) string { | |||
| return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr() | |||
| return engine.dialect.Quote(sql) | |||
| } | |||
| // SqlType will be deprecated, please use SQLType instead | |||
| @@ -1581,7 +1582,7 @@ func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{ | |||
| func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}) { | |||
| switch sqlTypeName { | |||
| case core.Time: | |||
| s := t.Format("2006-01-02 15:04:05") //time.RFC3339 | |||
| s := t.Format("2006-01-02 15:04:05") // time.RFC3339 | |||
| v = s[11:19] | |||
| case core.Date: | |||
| v = t.Format("2006-01-02") | |||
| @@ -15,5 +15,5 @@ require ( | |||
| github.com/stretchr/testify v1.3.0 | |||
| github.com/ziutek/mymysql v1.5.4 | |||
| xorm.io/builder v0.3.5 | |||
| xorm.io/core v0.6.3 | |||
| xorm.io/core v0.7.0 | |||
| ) | |||
| @@ -1,5 +1,4 @@ | |||
| cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | |||
| cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= | |||
| cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | |||
| cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= | |||
| cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= | |||
| @@ -13,7 +12,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 | |||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | |||
| github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= | |||
| github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= | |||
| github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | |||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
| @@ -36,6 +34,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU | |||
| github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |||
| github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
| github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
| github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | |||
| github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | |||
| github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= | |||
| @@ -100,8 +99,9 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK | |||
| go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= | |||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | |||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
| golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= | |||
| golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= | |||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
| golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | |||
| golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | |||
| golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= | |||
| @@ -114,29 +114,38 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r | |||
| golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
| golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | |||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
| golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
| 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= | |||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
| golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
| golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= | |||
| golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
| golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
| google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= | |||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | |||
| google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= | |||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw= | |||
| google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | |||
| google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | |||
| google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | |||
| @@ -155,5 +164,5 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh | |||
| 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/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M= | |||
| xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo= | |||
| xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= | |||
| xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= | |||
| @@ -281,7 +281,7 @@ func rValue(bean interface{}) reflect.Value { | |||
| func rType(bean interface{}) reflect.Type { | |||
| sliceValue := reflect.Indirect(reflect.ValueOf(bean)) | |||
| //return reflect.TypeOf(sliceValue.Interface()) | |||
| // return reflect.TypeOf(sliceValue.Interface()) | |||
| return sliceValue.Type() | |||
| } | |||
| @@ -309,3 +309,24 @@ func sliceEq(left, right []string) bool { | |||
| func indexName(tableName, idxName string) string { | |||
| return fmt.Sprintf("IDX_%v_%v", tableName, idxName) | |||
| } | |||
| func eraseAny(value string, strToErase ...string) string { | |||
| if len(strToErase) == 0 { | |||
| return value | |||
| } | |||
| var replaceSeq []string | |||
| for _, s := range strToErase { | |||
| replaceSeq = append(replaceSeq, s, "") | |||
| } | |||
| replacer := strings.NewReplacer(replaceSeq...) | |||
| return replacer.Replace(value) | |||
| } | |||
| func quoteColumns(cols []string, quoteFunc func(string) string, sep string) string { | |||
| for i := range cols { | |||
| cols[i] = quoteFunc(cols[i]) | |||
| } | |||
| return strings.Join(cols, sep+" ") | |||
| } | |||
| @@ -63,6 +63,8 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte | |||
| } | |||
| func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error { | |||
| defer session.resetStatement() | |||
| if session.statement.lastError != nil { | |||
| return session.statement.lastError | |||
| } | |||
| @@ -24,6 +24,8 @@ func (session *Session) Get(bean interface{}) (bool, error) { | |||
| } | |||
| func (session *Session) get(bean interface{}) (bool, error) { | |||
| defer session.resetStatement() | |||
| if session.statement.lastError != nil { | |||
| return false, session.statement.lastError | |||
| } | |||
| @@ -75,6 +77,8 @@ func (session *Session) get(bean interface{}) (bool, error) { | |||
| if context != nil { | |||
| res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args)) | |||
| if res != nil { | |||
| session.engine.logger.Debug("hit context cache", sqlStr) | |||
| structValue := reflect.Indirect(reflect.ValueOf(bean)) | |||
| structValue.Set(reflect.Indirect(reflect.ValueOf(res))) | |||
| session.lastSQL = "" | |||
| @@ -114,6 +118,114 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bea | |||
| return true, rows.Scan(&bean) | |||
| case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString: | |||
| return true, rows.Scan(bean) | |||
| case *string: | |||
| var res sql.NullString | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*string)) = res.String | |||
| } | |||
| return true, nil | |||
| case *int: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*int)) = int(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *int8: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*int8)) = int8(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *int16: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*int16)) = int16(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *int32: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*int32)) = int32(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *int64: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*int64)) = int64(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *uint: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*uint)) = uint(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *uint8: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*uint8)) = uint8(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *uint16: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*uint16)) = uint16(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *uint32: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*uint32)) = uint32(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *uint64: | |||
| var res sql.NullInt64 | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*uint64)) = uint64(res.Int64) | |||
| } | |||
| return true, nil | |||
| case *bool: | |||
| var res sql.NullBool | |||
| if err := rows.Scan(&res); err != nil { | |||
| return true, err | |||
| } | |||
| if res.Valid { | |||
| *(bean.(*bool)) = res.Bool | |||
| } | |||
| return true, nil | |||
| } | |||
| switch beanKind { | |||
| @@ -142,6 +254,9 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bea | |||
| err = rows.ScanSlice(bean) | |||
| case reflect.Map: | |||
| err = rows.ScanMap(bean) | |||
| case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | |||
| reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |||
| err = rows.Scan(bean) | |||
| default: | |||
| err = rows.Scan(bean) | |||
| } | |||
| @@ -12,6 +12,7 @@ import ( | |||
| "strconv" | |||
| "strings" | |||
| "xorm.io/builder" | |||
| "xorm.io/core" | |||
| ) | |||
| @@ -242,23 +243,17 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error | |||
| var sql string | |||
| if session.engine.dialect.DBType() == core.ORACLE { | |||
| temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (", | |||
| temp := fmt.Sprintf(") INTO %s (%v) VALUES (", | |||
| session.engine.Quote(tableName), | |||
| session.engine.QuoteStr(), | |||
| strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | |||
| session.engine.QuoteStr()) | |||
| sql = fmt.Sprintf("INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL", | |||
| quoteColumns(colNames, session.engine.Quote, ",")) | |||
| sql = fmt.Sprintf("INSERT ALL INTO %s (%v) VALUES (%v) SELECT 1 FROM DUAL", | |||
| session.engine.Quote(tableName), | |||
| session.engine.QuoteStr(), | |||
| strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | |||
| session.engine.QuoteStr(), | |||
| quoteColumns(colNames, session.engine.Quote, ","), | |||
| strings.Join(colMultiPlaces, temp)) | |||
| } else { | |||
| sql = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", | |||
| sql = fmt.Sprintf("INSERT INTO %s (%v) VALUES (%v)", | |||
| session.engine.Quote(tableName), | |||
| session.engine.QuoteStr(), | |||
| strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | |||
| session.engine.QuoteStr(), | |||
| quoteColumns(colNames, session.engine.Quote, ","), | |||
| strings.Join(colMultiPlaces, "),(")) | |||
| } | |||
| res, err := session.exec(sql, args...) | |||
| @@ -351,7 +346,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||
| for _, v := range exprColumns { | |||
| // remove the expr columns | |||
| for i, colName := range colNames { | |||
| if colName == v.colName { | |||
| if colName == strings.Trim(v.colName, "`") { | |||
| colNames = append(colNames[:i], colNames[i+1:]...) | |||
| args = append(args[:i], args[i+1:]...) | |||
| } | |||
| @@ -377,14 +372,30 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||
| if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 { | |||
| output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement) | |||
| } | |||
| if len(colPlaces) > 0 { | |||
| sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v)%s VALUES (%v)", | |||
| session.engine.Quote(tableName), | |||
| session.engine.QuoteStr(), | |||
| strings.Join(colNames, session.engine.Quote(", ")), | |||
| session.engine.QuoteStr(), | |||
| output, | |||
| colPlaces) | |||
| if session.statement.cond.IsValid() { | |||
| condSQL, condArgs, err := builder.ToSQL(session.statement.cond) | |||
| if 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...) | |||
| } else { | |||
| sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s VALUES (%v)", | |||
| session.engine.Quote(tableName), | |||
| quoteColumns(colNames, session.engine.Quote, ","), | |||
| output, | |||
| colPlaces) | |||
| } | |||
| } else { | |||
| if session.engine.dialect.DBType() == core.MYSQL { | |||
| sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName)) | |||
| @@ -671,6 +682,11 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err | |||
| return 0, ErrParamsType | |||
| } | |||
| tableName := session.statement.TableName() | |||
| if len(tableName) <= 0 { | |||
| return 0, ErrTableNotFound | |||
| } | |||
| var columns = make([]string, 0, len(m)) | |||
| for k := range m { | |||
| columns = append(columns, k) | |||
| @@ -678,19 +694,40 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err | |||
| sort.Strings(columns) | |||
| qm := strings.Repeat("?,", len(columns)) | |||
| qm = "(" + qm[:len(qm)-1] + ")" | |||
| tableName := session.statement.TableName() | |||
| if len(tableName) <= 0 { | |||
| return 0, ErrTableNotFound | |||
| } | |||
| var sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES %s", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm) | |||
| 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 | |||
| if session.statement.cond.IsValid() { | |||
| condSQL, condArgs, err := builder.ToSQL(session.statement.cond) | |||
| if 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) | |||
| } | |||
| if err := session.cacheInsert(tableName); err != nil { | |||
| return 0, err | |||
| } | |||
| @@ -711,24 +748,51 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) { | |||
| return 0, ErrParamsType | |||
| } | |||
| tableName := session.statement.TableName() | |||
| if len(tableName) <= 0 { | |||
| return 0, ErrTableNotFound | |||
| } | |||
| var columns = make([]string, 0, len(m)) | |||
| for k := range m { | |||
| columns = append(columns, k) | |||
| } | |||
| sort.Strings(columns) | |||
| var args = make([]interface{}, 0, len(m)) | |||
| for _, colName := range columns { | |||
| args = append(args, m[colName]) | |||
| } | |||
| qm := strings.Repeat("?,", len(columns)) | |||
| qm = "(" + qm[:len(qm)-1] + ")" | |||
| tableName := session.statement.TableName() | |||
| if len(tableName) <= 0 { | |||
| return 0, ErrTableNotFound | |||
| // 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 + "," | |||
| } | |||
| var sql = fmt.Sprintf("INSERT INTO %s (`%s`) VALUES %s", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm) | |||
| var args = make([]interface{}, 0, len(m)) | |||
| for _, colName := range columns { | |||
| args = append(args, m[colName]) | |||
| qm = qm[:len(qm)-1] | |||
| var sql string | |||
| if session.statement.cond.IsValid() { | |||
| qm = "(" + qm[:len(qm)-1] + ")" | |||
| condSQL, condArgs, err := builder.ToSQL(session.statement.cond) | |||
| if 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) | |||
| } | |||
| if err := session.cacheInsert(tableName); err != nil { | |||
| @@ -96,14 +96,15 @@ func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string, | |||
| return ErrCacheFailed | |||
| } | |||
| kvs := strings.Split(strings.TrimSpace(sqls[1]), ",") | |||
| for idx, kv := range kvs { | |||
| sps := strings.SplitN(kv, "=", 2) | |||
| sps2 := strings.Split(sps[0], ".") | |||
| colName := sps2[len(sps2)-1] | |||
| if strings.Contains(colName, "`") { | |||
| colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1)) | |||
| } else if strings.Contains(colName, session.engine.QuoteStr()) { | |||
| colName = strings.TrimSpace(strings.Replace(colName, session.engine.QuoteStr(), "", -1)) | |||
| // treat quote prefix, suffix and '`' as quotes | |||
| quotes := append(strings.Split(session.engine.Quote(""), ""), "`") | |||
| if strings.ContainsAny(colName, strings.Join(quotes, "")) { | |||
| colName = strings.TrimSpace(eraseAny(colName, quotes...)) | |||
| } else { | |||
| session.engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName) | |||
| return ErrCacheFailed | |||
| @@ -221,19 +222,19 @@ 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() | |||
| for _, v := range incColumns { | |||
| colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?") | |||
| args = append(args, v.arg) | |||
| } | |||
| //for update action to like "column = column - ?" | |||
| // 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) | |||
| } | |||
| //for update action to like "column = expression" | |||
| // 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) | |||
| @@ -382,7 +383,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||
| } | |||
| if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache { | |||
| //session.cacheUpdate(table, tableName, sqlStr, args...) | |||
| // session.cacheUpdate(table, tableName, sqlStr, args...) | |||
| session.engine.logger.Debug("[cacheUpdate] clear table ", tableName) | |||
| cacher.ClearIds(tableName) | |||
| cacher.ClearBeans(tableName) | |||
| @@ -6,7 +6,6 @@ package xorm | |||
| import ( | |||
| "database/sql/driver" | |||
| "errors" | |||
| "fmt" | |||
| "reflect" | |||
| "strings" | |||
| @@ -398,7 +397,7 @@ func (statement *Statement) buildUpdates(bean interface{}, | |||
| continue | |||
| } | |||
| } else { | |||
| //TODO: how to handler? | |||
| // TODO: how to handler? | |||
| panic("not supported") | |||
| } | |||
| } else { | |||
| @@ -579,21 +578,9 @@ func (statement *Statement) getExpr() map[string]exprParam { | |||
| func (statement *Statement) col2NewColsWithQuote(columns ...string) []string { | |||
| newColumns := make([]string, 0) | |||
| quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") | |||
| for _, col := range columns { | |||
| col = strings.Replace(col, "`", "", -1) | |||
| col = strings.Replace(col, statement.Engine.QuoteStr(), "", -1) | |||
| ccols := strings.Split(col, ",") | |||
| for _, c := range ccols { | |||
| fields := strings.Split(strings.TrimSpace(c), ".") | |||
| if len(fields) == 1 { | |||
| newColumns = append(newColumns, statement.Engine.quote(fields[0])) | |||
| } else if len(fields) == 2 { | |||
| newColumns = append(newColumns, statement.Engine.quote(fields[0])+"."+ | |||
| statement.Engine.quote(fields[1])) | |||
| } else { | |||
| panic(errors.New("unwanted colnames")) | |||
| } | |||
| } | |||
| newColumns = append(newColumns, statement.Engine.Quote(eraseAny(col, quotes...))) | |||
| } | |||
| return newColumns | |||
| } | |||
| @@ -764,7 +751,9 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition | |||
| return statement | |||
| } | |||
| tbs := strings.Split(tp.TableName(), ".") | |||
| var aliasName = strings.Trim(tbs[len(tbs)-1], statement.Engine.QuoteStr()) | |||
| quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") | |||
| var aliasName = strings.Trim(tbs[len(tbs)-1], strings.Join(quotes, "")) | |||
| fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition) | |||
| statement.joinArgs = append(statement.joinArgs, subQueryArgs...) | |||
| case *builder.Builder: | |||
| @@ -774,7 +763,9 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition | |||
| return statement | |||
| } | |||
| tbs := strings.Split(tp.TableName(), ".") | |||
| var aliasName = strings.Trim(tbs[len(tbs)-1], statement.Engine.QuoteStr()) | |||
| quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") | |||
| var aliasName = strings.Trim(tbs[len(tbs)-1], strings.Join(quotes, "")) | |||
| fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition) | |||
| statement.joinArgs = append(statement.joinArgs, subQueryArgs...) | |||
| default: | |||
| @@ -1157,8 +1148,12 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n | |||
| if statement.Start != 0 || statement.LimitN != 0 { | |||
| oldString := buf.String() | |||
| buf.Reset() | |||
| rawColStr := columnStr | |||
| if rawColStr == "*" { | |||
| rawColStr = "at.*" | |||
| } | |||
| fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", | |||
| columnStr, columnStr, oldString, statement.Start+statement.LimitN, statement.Start) | |||
| columnStr, rawColStr, oldString, statement.Start+statement.LimitN, statement.Start) | |||
| } | |||
| } | |||
| } | |||
| @@ -1242,7 +1237,7 @@ func (statement *Statement) convertUpdateSQL(sqlStr string) (string, string) { | |||
| var whereStr = sqls[1] | |||
| //TODO: for postgres only, if any other database? | |||
| // TODO: for postgres only, if any other database? | |||
| var paraStr string | |||
| if statement.Engine.dialect.DBType() == core.POSTGRES { | |||
| paraStr = "$" | |||
| @@ -148,7 +148,7 @@ github.com/go-redis/redis/internal/proto | |||
| github.com/go-redis/redis/internal/util | |||
| # github.com/go-sql-driver/mysql v1.4.1 | |||
| github.com/go-sql-driver/mysql | |||
| # github.com/go-xorm/xorm v0.7.4 | |||
| # github.com/go-xorm/xorm v0.7.7-0.20190822154023-17592d96b35b | |||
| github.com/go-xorm/xorm | |||
| # github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 | |||
| github.com/gogits/chardet | |||
| @@ -482,5 +482,5 @@ mvdan.cc/xurls/v2 | |||
| strk.kbt.io/projects/go/libravatar | |||
| # xorm.io/builder v0.3.5 | |||
| xorm.io/builder | |||
| # xorm.io/core v0.6.3 | |||
| # xorm.io/core v0.7.0 | |||
| xorm.io/core | |||
| @@ -0,0 +1,42 @@ | |||
| workspace: | |||
| base: /go | |||
| path: src/xorm.io/core | |||
| clone: | |||
| git: | |||
| image: plugins/git:next | |||
| depth: 50 | |||
| tags: true | |||
| matrix: | |||
| GO_VERSION: | |||
| - 1.9 | |||
| - 1.10 | |||
| - 1.11 | |||
| - 1.12 | |||
| pipeline: | |||
| test: | |||
| image: golang:${GO_VERSION} | |||
| environment: | |||
| GOPROXY: https://goproxy.cn | |||
| 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 | |||
| - go get -u github.com/go-sql-driver/mysql | |||
| - go get -u github.com/mattn/go-sqlite3 | |||
| - go vet | |||
| - go test -v -race -coverprofile=coverage.txt -covermode=atomic -dbConn="root:@tcp(mysql:3306)/core_test?charset=utf8mb4" | |||
| when: | |||
| event: [ push, tag, pull_request ] | |||
| services: | |||
| mysql: | |||
| image: mysql:5.7 | |||
| environment: | |||
| - MYSQL_DATABASE=core_test | |||
| - MYSQL_ALLOW_EMPTY_PASSWORD=yes | |||
| when: | |||
| event: [ push, tag, pull_request ] | |||
| @@ -1,6 +1,8 @@ | |||
| Core is a lightweight wrapper of sql.DB. | |||
| [](https://circleci.com/gh/go-xorm/core/tree/master) | |||
| [](https://drone.gitea.com/xorm/core) | |||
| [](http://gocover.io/xorm.io/core) | |||
| [](https://goreportcard.com/report/xorm.io/core) | |||
| # Open | |||
| ```Go | |||
| @@ -14,19 +14,20 @@ import ( | |||
| ) | |||
| const ( | |||
| // default cache expired time | |||
| // CacheExpired is default cache expired time | |||
| CacheExpired = 60 * time.Minute | |||
| // not use now | |||
| // CacheMaxMemory is not use now | |||
| CacheMaxMemory = 256 | |||
| // evey ten minutes to clear all expired nodes | |||
| // CacheGcInterval represents interval time to clear all expired nodes | |||
| CacheGcInterval = 10 * time.Minute | |||
| // each time when gc to removed max nodes | |||
| // CacheGcMaxRemoved represents max nodes removed when gc | |||
| CacheGcMaxRemoved = 20 | |||
| ) | |||
| // list all the errors | |||
| var ( | |||
| ErrCacheMiss = errors.New("xorm/cache: key not found.") | |||
| ErrNotStored = errors.New("xorm/cache: not stored.") | |||
| ErrCacheMiss = errors.New("xorm/cache: key not found") | |||
| ErrNotStored = errors.New("xorm/cache: not stored") | |||
| ) | |||
| // CacheStore is a interface to store cache | |||
| @@ -69,6 +70,7 @@ func decodeIds(s string) ([]PK, error) { | |||
| return pks, err | |||
| } | |||
| // GetCacheSql returns cacher PKs via SQL | |||
| func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error) { | |||
| bytes := m.GetIds(tableName, GenSqlKey(sql, args)) | |||
| if bytes == nil { | |||
| @@ -77,6 +79,7 @@ func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error | |||
| return decodeIds(bytes.(string)) | |||
| } | |||
| // PutCacheSql puts cacher SQL and PKs | |||
| func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) error { | |||
| bytes, err := encodeIds(ids) | |||
| if err != nil { | |||
| @@ -86,6 +89,7 @@ func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) er | |||
| return nil | |||
| } | |||
| // GenSqlKey generates cache key | |||
| func GenSqlKey(sql string, args interface{}) string { | |||
| return fmt.Sprintf("%v-%v", sql, args) | |||
| } | |||
| @@ -73,7 +73,7 @@ func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable | |||
| // String generate column description string according dialect | |||
| func (col *Column) String(d Dialect) string { | |||
| sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " | |||
| sql := d.Quote(col.Name) + " " | |||
| sql += d.SqlType(col) + " " | |||
| @@ -101,7 +101,7 @@ func (col *Column) String(d Dialect) string { | |||
| // StringNoPk generate column description string according dialect without primary keys | |||
| func (col *Column) StringNoPk(d Dialect) string { | |||
| sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " | |||
| sql := d.Quote(col.Name) + " " | |||
| sql += d.SqlType(col) + " " | |||
| @@ -15,6 +15,7 @@ import ( | |||
| ) | |||
| var ( | |||
| // DefaultCacheSize sets the default cache size | |||
| DefaultCacheSize = 200 | |||
| ) | |||
| @@ -132,6 +133,7 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { | |||
| return db.QueryContext(context.Background(), query, args...) | |||
| } | |||
| // QueryMapContext executes query with parameters via map and context | |||
| func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) { | |||
| query, args, err := MapToSlice(query, mp) | |||
| if err != nil { | |||
| @@ -140,6 +142,7 @@ func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{}) | |||
| return db.QueryContext(ctx, query, args...) | |||
| } | |||
| // QueryMap executes query with parameters via map | |||
| func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) { | |||
| return db.QueryMapContext(context.Background(), query, mp) | |||
| } | |||
| @@ -196,6 +199,7 @@ var ( | |||
| re = regexp.MustCompile(`[?](\w+)`) | |||
| ) | |||
| // ExecMapContext exec map with context.Context | |||
| // insert into (name) values (?) | |||
| // insert into (name) values (?name) | |||
| func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) { | |||
| @@ -40,9 +40,9 @@ type Dialect interface { | |||
| DriverName() string | |||
| DataSourceName() string | |||
| QuoteStr() string | |||
| IsReserved(string) bool | |||
| Quote(string) string | |||
| AndStr() string | |||
| OrStr() string | |||
| EqStr() string | |||
| @@ -70,8 +70,8 @@ type Dialect interface { | |||
| ForUpdateSql(query string) string | |||
| //CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error | |||
| //MustDropTable(tableName string) error | |||
| // CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error | |||
| // MustDropTable(tableName string) error | |||
| GetColumns(tableName string) ([]string, map[string]*Column, error) | |||
| GetTables() ([]*Table, error) | |||
| @@ -85,6 +85,7 @@ func OpenDialect(dialect Dialect) (*DB, error) { | |||
| return Open(dialect.DriverName(), dialect.DataSourceName()) | |||
| } | |||
| // Base represents a basic dialect and all real dialects could embed this struct | |||
| type Base struct { | |||
| db *DB | |||
| dialect Dialect | |||
| @@ -172,8 +173,15 @@ func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) { | |||
| } | |||
| func (db *Base) IsColumnExist(tableName, colName string) (bool, error) { | |||
| query := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?" | |||
| query = strings.Replace(query, "`", db.dialect.QuoteStr(), -1) | |||
| query := fmt.Sprintf( | |||
| "SELECT %v FROM %v.%v WHERE %v = ? AND %v = ? AND %v = ?", | |||
| db.dialect.Quote("COLUMN_NAME"), | |||
| db.dialect.Quote("INFORMATION_SCHEMA"), | |||
| db.dialect.Quote("COLUMNS"), | |||
| db.dialect.Quote("TABLE_SCHEMA"), | |||
| db.dialect.Quote("TABLE_NAME"), | |||
| db.dialect.Quote("COLUMN_NAME"), | |||
| ) | |||
| return db.HasRecords(query, db.DbName, tableName, colName) | |||
| } | |||
| @@ -310,7 +318,7 @@ func RegisterDialect(dbName DbType, dialectFunc func() Dialect) { | |||
| dialects[strings.ToLower(string(dbName))] = dialectFunc // !nashtsai! allow override dialect | |||
| } | |||
| // QueryDialect query if registed database dialect | |||
| // QueryDialect query if registered database dialect | |||
| func QueryDialect(dbName DbType) Dialect { | |||
| if d, ok := dialects[strings.ToLower(string(dbName))]; ok { | |||
| return d() | |||
| @@ -7,6 +7,8 @@ package core | |||
| import "errors" | |||
| var ( | |||
| ErrNoMapPointer = errors.New("mp should be a map's pointer") | |||
| // ErrNoMapPointer represents error when no map pointer | |||
| ErrNoMapPointer = errors.New("mp should be a map's pointer") | |||
| // ErrNoStructPointer represents error when no struct pointer | |||
| ErrNoStructPointer = errors.New("mp should be a struct's pointer") | |||
| ) | |||
| @@ -19,7 +19,23 @@ type QuoteFilter struct { | |||
| } | |||
| func (s *QuoteFilter) Do(sql string, dialect Dialect, table *Table) string { | |||
| return strings.Replace(sql, "`", dialect.QuoteStr(), -1) | |||
| dummy := dialect.Quote("") | |||
| if len(dummy) != 2 { | |||
| return sql | |||
| } | |||
| prefix, suffix := dummy[0], dummy[1] | |||
| raw := []byte(sql) | |||
| for i, cnt := 0, 0; i < len(raw); i = i + 1 { | |||
| if raw[i] == '`' { | |||
| if cnt%2 == 0 { | |||
| raw[i] = prefix | |||
| } else { | |||
| raw[i] = suffix | |||
| } | |||
| cnt++ | |||
| } | |||
| } | |||
| return string(raw) | |||
| } | |||
| // IdFilter filter SQL replace (id) to primary key column name | |||
| @@ -35,7 +51,7 @@ func NewQuoter(dialect Dialect) *Quoter { | |||
| } | |||
| func (q *Quoter) Quote(content string) string { | |||
| return q.dialect.QuoteStr() + content + q.dialect.QuoteStr() | |||
| return q.dialect.Quote(content) | |||
| } | |||
| func (i *IdFilter) Do(sql string, dialect Dialect, table *Table) string { | |||
| @@ -2,6 +2,12 @@ module xorm.io/core | |||
| require ( | |||
| github.com/go-sql-driver/mysql v1.4.1 | |||
| github.com/golang/protobuf v1.3.1 // indirect | |||
| github.com/mattn/go-sqlite3 v1.10.0 | |||
| google.golang.org/appengine v1.4.0 // indirect | |||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 // indirect | |||
| golang.org/x/net v0.0.0-20190603091049-60506f45cf65 // indirect | |||
| golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed // indirect | |||
| golang.org/x/text v0.3.2 // indirect | |||
| golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 // indirect | |||
| google.golang.org/appengine v1.6.0 // indirect | |||
| ) | |||
| @@ -1,9 +1,23 @@ | |||
| github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= | |||
| github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | |||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
| github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
| github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= | |||
| github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | |||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
| golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
| golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | |||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/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.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
| golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
| google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= | |||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
| @@ -4,8 +4,10 @@ | |||
| package core | |||
| // LogLevel defines a log level | |||
| type LogLevel int | |||
| // enumerate all LogLevels | |||
| const ( | |||
| // !nashtsai! following level also match syslog.Priority value | |||
| LOG_DEBUG LogLevel = iota | |||
| @@ -16,7 +18,7 @@ const ( | |||
| LOG_UNKNOWN | |||
| ) | |||
| // logger interface | |||
| // ILogger is a logger interface | |||
| type ILogger interface { | |||
| Debug(v ...interface{}) | |||
| Debugf(format string, v ...interface{}) | |||
| @@ -9,12 +9,13 @@ import ( | |||
| "strings" | |||
| ) | |||
| // enumerate all index types | |||
| const ( | |||
| IndexType = iota + 1 | |||
| UniqueType | |||
| ) | |||
| // database index | |||
| // Index represents a database index | |||
| type Index struct { | |||
| IsRegular bool | |||
| Name string | |||
| @@ -35,7 +36,7 @@ func (index *Index) XName(tableName string) string { | |||
| return index.Name | |||
| } | |||
| // add columns which will be composite index | |||
| // AddColumn add columns which will be composite index | |||
| func (index *Index) AddColumn(cols ...string) { | |||
| for _, col := range cols { | |||
| index.Cols = append(index.Cols, col) | |||
| @@ -65,7 +66,7 @@ func (index *Index) Equal(dst *Index) bool { | |||
| return true | |||
| } | |||
| // new an index | |||
| // NewIndex new an index object | |||
| func NewIndex(name string, indexType int) *Index { | |||
| return &Index{true, name, indexType, make([]string, 0)} | |||
| } | |||
| @@ -9,7 +9,7 @@ import ( | |||
| "sync" | |||
| ) | |||
| // name translation between struct, fields names and table, column names | |||
| // IMapper represents a name convertation between struct's fields name and table's column name | |||
| type IMapper interface { | |||
| Obj2Table(string) string | |||
| Table2Obj(string) string | |||
| @@ -184,7 +184,7 @@ func (mapper GonicMapper) Table2Obj(name string) string { | |||
| return string(newstr) | |||
| } | |||
| // A GonicMapper that contains a list of common initialisms taken from golang/lint | |||
| // LintGonicMapper is A GonicMapper that contains a list of common initialisms taken from golang/lint | |||
| var LintGonicMapper = GonicMapper{ | |||
| "API": true, | |||
| "ASCII": true, | |||
| @@ -221,7 +221,7 @@ var LintGonicMapper = GonicMapper{ | |||
| "XSS": true, | |||
| } | |||
| // provide prefix table name support | |||
| // PrefixMapper provides prefix table name support | |||
| type PrefixMapper struct { | |||
| Mapper IMapper | |||
| Prefix string | |||
| @@ -239,7 +239,7 @@ func NewPrefixMapper(mapper IMapper, prefix string) PrefixMapper { | |||
| return PrefixMapper{mapper, prefix} | |||
| } | |||
| // provide suffix table name support | |||
| // SuffixMapper provides suffix table name support | |||
| type SuffixMapper struct { | |||
| Mapper IMapper | |||
| Suffix string | |||
| @@ -170,7 +170,7 @@ func (rs *Rows) ScanMap(dest interface{}) error { | |||
| newDest := make([]interface{}, len(cols)) | |||
| vvv := vv.Elem() | |||
| for i, _ := range cols { | |||
| for i := range cols { | |||
| newDest[i] = rs.db.reflectNew(vvv.Type().Elem()).Interface() | |||
| } | |||
| @@ -11,6 +11,7 @@ import ( | |||
| "reflect" | |||
| ) | |||
| // Stmt reprents a stmt objects | |||
| type Stmt struct { | |||
| *sql.Stmt | |||
| db *DB | |||
| @@ -9,7 +9,7 @@ import ( | |||
| "strings" | |||
| ) | |||
| // database table | |||
| // Table represents a database table | |||
| type Table struct { | |||
| Name string | |||
| Type reflect.Type | |||
| @@ -41,6 +41,7 @@ func NewEmptyTable() *Table { | |||
| return NewTable("", nil) | |||
| } | |||
| // NewTable creates a new Table object | |||
| func NewTable(name string, t reflect.Type) *Table { | |||
| return &Table{Name: name, Type: t, | |||
| columnsSeq: make([]string, 0), | |||
| @@ -87,7 +88,7 @@ func (table *Table) GetColumnIdx(name string, idx int) *Column { | |||
| return nil | |||
| } | |||
| // if has primary key, return column | |||
| // PKColumns reprents all primary key columns | |||
| func (table *Table) PKColumns() []*Column { | |||
| columns := make([]*Column, len(table.PrimaryKeys)) | |||
| for i, name := range table.PrimaryKeys { | |||
| @@ -117,7 +118,7 @@ func (table *Table) DeletedColumn() *Column { | |||
| return table.GetColumn(table.Deleted) | |||
| } | |||
| // add a column to table | |||
| // AddColumn adds a column to table | |||
| func (table *Table) AddColumn(col *Column) { | |||
| table.columnsSeq = append(table.columnsSeq, col.Name) | |||
| table.columns = append(table.columns, col) | |||
| @@ -148,7 +149,7 @@ func (table *Table) AddColumn(col *Column) { | |||
| } | |||
| } | |||
| // add an index or an unique to table | |||
| // AddIndex adds an index or an unique to table | |||
| func (table *Table) AddIndex(index *Index) { | |||
| table.Indexes[index.Name] = index | |||
| } | |||
| @@ -87,16 +87,16 @@ var ( | |||
| UniqueIdentifier = "UNIQUEIDENTIFIER" | |||
| SysName = "SYSNAME" | |||
| Date = "DATE" | |||
| DateTime = "DATETIME" | |||
| SmallDateTime = "SMALLDATETIME" | |||
| Time = "TIME" | |||
| TimeStamp = "TIMESTAMP" | |||
| TimeStampz = "TIMESTAMPZ" | |||
| Decimal = "DECIMAL" | |||
| Numeric = "NUMERIC" | |||
| Money = "MONEY" | |||
| Date = "DATE" | |||
| DateTime = "DATETIME" | |||
| SmallDateTime = "SMALLDATETIME" | |||
| Time = "TIME" | |||
| TimeStamp = "TIMESTAMP" | |||
| TimeStampz = "TIMESTAMPZ" | |||
| Decimal = "DECIMAL" | |||
| Numeric = "NUMERIC" | |||
| Money = "MONEY" | |||
| SmallMoney = "SMALLMONEY" | |||
| Real = "REAL" | |||
| @@ -147,19 +147,19 @@ var ( | |||
| Clob: TEXT_TYPE, | |||
| SysName: TEXT_TYPE, | |||
| Date: TIME_TYPE, | |||
| DateTime: TIME_TYPE, | |||
| Time: TIME_TYPE, | |||
| TimeStamp: TIME_TYPE, | |||
| TimeStampz: TIME_TYPE, | |||
| SmallDateTime: TIME_TYPE, | |||
| Decimal: NUMERIC_TYPE, | |||
| Numeric: NUMERIC_TYPE, | |||
| Real: NUMERIC_TYPE, | |||
| Float: NUMERIC_TYPE, | |||
| Double: NUMERIC_TYPE, | |||
| Money: NUMERIC_TYPE, | |||
| Date: TIME_TYPE, | |||
| DateTime: TIME_TYPE, | |||
| Time: TIME_TYPE, | |||
| TimeStamp: TIME_TYPE, | |||
| TimeStampz: TIME_TYPE, | |||
| SmallDateTime: TIME_TYPE, | |||
| Decimal: NUMERIC_TYPE, | |||
| Numeric: NUMERIC_TYPE, | |||
| Real: NUMERIC_TYPE, | |||
| Float: NUMERIC_TYPE, | |||
| Double: NUMERIC_TYPE, | |||
| Money: NUMERIC_TYPE, | |||
| SmallMoney: NUMERIC_TYPE, | |||
| Binary: BLOB_TYPE, | |||