Retry create issue to cope with duplicate keys (#7898)

* Retry create issue to cope with duplicate keys

* Use  .SetExpr().Where().Insert()
This commit is contained in:
guillep2k 2019-08-26 23:17:23 -03:00 committed by techknowlogick
parent 541fab196f
commit 5fe2ec264f
39 changed files with 1991 additions and 1404 deletions

4
go.mod
View file

@ -45,7 +45,7 @@ require (
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
github.com/go-redis/redis v6.15.2+incompatible github.com/go-redis/redis v6.15.2+incompatible
github.com/go-sql-driver/mysql v1.4.1 github.com/go-sql-driver/mysql v1.4.1
github.com/go-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/gogits/chardet v0.0.0-20150115103509-2404f7772561
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
github.com/google/go-github/v24 v24.0.1 github.com/google/go-github/v24 v24.0.1
@ -117,5 +117,5 @@ require (
mvdan.cc/xurls/v2 v2.0.0 mvdan.cc/xurls/v2 v2.0.0
strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a
xorm.io/builder v0.3.5 xorm.io/builder v0.3.5
xorm.io/core v0.6.3 xorm.io/core v0.7.0
) )

7
go.sum
View file

@ -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/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 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.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 h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA=
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -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-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-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-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-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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190730183949-1393eb018365/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-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-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-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-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-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190731214159-1e85ed8060aa h1:kwa/4M1dbmhZqOIqYiTtbA6JrvPwo1+jqlub2qDXX90= 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.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.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.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 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 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= 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/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M= xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M=
xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo= 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=

View file

@ -5,7 +5,6 @@
package models package models
import ( import (
"errors"
"fmt" "fmt"
"path" "path"
"regexp" "regexp"
@ -74,6 +73,7 @@ var (
const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)` const issueTasksRegexpStr = `(^\s*[-*]\s\[[\sx]\]\s.)|(\n\s*[-*]\s\[[\sx]\]\s.)`
const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)` const issueTasksDoneRegexpStr = `(^\s*[-*]\s\[[x]\]\s.)|(\n\s*[-*]\s\[[x]\]\s.)`
const issueMaxDupIndexAttempts = 3
func init() { func init() {
issueTasksPat = regexp.MustCompile(issueTasksRegexpStr) issueTasksPat = regexp.MustCompile(issueTasksRegexpStr)
@ -1031,36 +1031,9 @@ type NewIssueOptions struct {
IsPull bool 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) { func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
opts.Issue.Title = strings.TrimSpace(opts.Issue.Title) 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 { if opts.Issue.MilestoneID > 0 {
milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID) milestone, err := getMilestoneByRepoID(e, opts.Issue.RepoID, opts.Issue.MilestoneID)
if err != nil && !IsErrMilestoneNotExist(err) { if err != nil && !IsErrMilestoneNotExist(err) {
@ -1109,9 +1082,30 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
} }
// Milestone and assignee validation should happen before insert actual object. // 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 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 opts.Issue.MilestoneID > 0 {
if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil { if err = changeMilestoneAssign(e, doer, opts.Issue, -1); err != nil {

View file

@ -252,15 +252,8 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix()) deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
} }
maxIndex, err := models.GetMaxIndexOfIssue(repo.ID)
if err != nil {
ctx.ServerError("GetPatch", err)
return
}
prIssue := &models.Issue{ prIssue := &models.Issue{
RepoID: repo.ID, RepoID: repo.ID,
Index: maxIndex + 1,
Title: form.Title, Title: form.Title,
PosterID: ctx.User.ID, PosterID: ctx.User.ID,
Poster: ctx.User, Poster: ctx.User,

View file

@ -710,15 +710,8 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
return return
} }
maxIndex, err := models.GetMaxIndexOfIssue(repo.ID)
if err != nil {
ctx.ServerError("GetPatch", err)
return
}
pullIssue := &models.Issue{ pullIssue := &models.Issue{
RepoID: repo.ID, RepoID: repo.ID,
Index: maxIndex + 1,
Title: form.Title, Title: form.Title,
PosterID: ctx.User.ID, PosterID: ctx.User.ID,
Poster: ctx.User, Poster: ctx.User,

View file

@ -1,125 +1,431 @@
---
kind: pipeline
name: matrix-1
platform:
os: linux
arch: amd64
clone:
disable: true
workspace: workspace:
base: /go base: /go
path: src/github.com/go-xorm/xorm path: src/github.com/go-xorm/xorm
clone: steps:
git: - name: git
pull: default
image: plugins/git:next image: plugins/git:next
settings:
depth: 50 depth: 50
tags: true tags: true
services: - name: init_postgres
mysql: pull: default
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 image: postgres:9.5
commands: commands:
# wait for postgres service to become available - "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"
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: - name: build
image: golang:${GO_VERSION} pull: default
image: golang:1.10
commands: commands:
- go get -t -d -v ./... - go get -t -d -v ./...
- go get -u xorm.io/core - go get -u xorm.io/core
- go get -u xorm.io/builder - go get -u xorm.io/builder
- go build -v - go build -v
when: when:
event: [ push, pull_request ] event:
- push
- pull_request
test-sqlite: - name: test-sqlite
image: golang:${GO_VERSION} pull: default
image: golang:1.10
commands: commands:
- go get -u github.com/wadey/gocovmerge - go get -u github.com/wadey/gocovmerge
- go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic"
- go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
when: when:
event: [ push, pull_request ] event:
- push
- pull_request
test-mysql: - name: test-mysql
image: golang:${GO_VERSION} pull: default
image: golang:1.10
commands: commands:
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
when: when:
event: [ push, pull_request ] event:
- push
- pull_request
test-mysql-utf8mb4: - name: test-mysql-utf8mb4
image: golang:${GO_VERSION} pull: default
image: golang:1.10
commands: commands:
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -coverprofile=coverage2.1-1.txt -covermode=atomic - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
when: when:
event: [ push, pull_request ] event:
- push
- pull_request
test-mymysql: - name: test-mymysql
image: golang:${GO_VERSION} pull: default
image: golang:1.10
commands: commands:
- go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
- go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
when: when:
event: [ push, pull_request ] event:
- push
- pull_request
test-postgres: - name: test-postgres
image: golang:${GO_VERSION} pull: default
image: golang:1.10
commands: commands:
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
when: when:
event: [ push, pull_request ] event:
- push
- pull_request
test-postgres-schema: - name: test-postgres-schema
image: golang:${GO_VERSION} pull: default
image: golang:1.10
commands: commands:
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt - 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: when:
event: [ push, pull_request ] event:
- push
- pull_request
#coverage: services:
# image: robertstettner/drone-codecov - name: mysql
# secrets: [ codecov_token ] pull: default
# files: image: mysql:5.7
# - coverage.txt environment:
# when: MYSQL_ALLOW_EMPTY_PASSWORD: yes
# event: [ push, pull_request ] MYSQL_DATABASE: xorm_test
# branch: [ master ] 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:
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:
- 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

View file

@ -284,6 +284,13 @@ counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM 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 * `Sum` sum functions
```Go ```Go

View file

@ -286,10 +286,6 @@ func (db *mssql) Quote(name string) string {
return "\"" + name + "\"" return "\"" + name + "\""
} }
func (db *mssql) QuoteStr() string {
return "\""
}
func (db *mssql) SupportEngine() bool { func (db *mssql) SupportEngine() bool {
return false 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 = "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 pkList := table.PrimaryKeys

View file

@ -220,7 +220,7 @@ func (db *mysql) SqlType(c *core.Column) string {
case core.TimeStampz: case core.TimeStampz:
res = core.Char res = core.Char
c.Length = 64 c.Length = 64
case core.Enum: //mysql enum case core.Enum: // mysql enum
res = core.Enum res = core.Enum
res += "(" res += "("
opts := "" opts := ""
@ -229,7 +229,7 @@ func (db *mysql) SqlType(c *core.Column) string {
} }
res += strings.TrimLeft(opts, ",") res += strings.TrimLeft(opts, ",")
res += ")" res += ")"
case core.Set: //mysql set case core.Set: // mysql set
res = core.Set res = core.Set
res += "(" res += "("
opts := "" opts := ""
@ -278,10 +278,6 @@ func (db *mysql) Quote(name string) string {
return "`" + name + "`" return "`" + name + "`"
} }
func (db *mysql) QuoteStr() string {
return "`"
}
func (db *mysql) SupportEngine() bool { func (db *mysql) SupportEngine() bool {
return true return true
} }
@ -360,7 +356,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
var len1, len2 int var len1, len2 int
if len(cts) == 2 { if len(cts) == 2 {
idx := strings.Index(cts[1], ")") 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], ",") options := strings.Split(cts[1][0:idx], ",")
col.EnumOptions = make(map[string]int) col.EnumOptions = make(map[string]int)
for k, v := range options { for k, v := range options {
@ -408,7 +404,7 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
col.IsPrimaryKey = true col.IsPrimaryKey = true
} }
if colKey == "UNI" { if colKey == "UNI" {
//col.is // col.is
} }
if extra == "auto_increment" { if extra == "auto_increment" {
@ -559,8 +555,6 @@ func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, chars
sql += " DEFAULT CHARSET " + charset sql += " DEFAULT CHARSET " + charset
} }
if db.rowFormat != "" { if db.rowFormat != "" {
sql += " ROW_FORMAT=" + 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<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN] `(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName) matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config) // tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames() names := dsnPattern.SubexpNames()
uri := &core.Uri{DbType: core.MYSQL} uri := &core.Uri{DbType: core.MYSQL}

View file

@ -552,11 +552,7 @@ func (db *oracle) IsReserved(name string) bool {
} }
func (db *oracle) Quote(name string) string { func (db *oracle) Quote(name string) string {
return "\"" + name + "\"" return "[" + name + "]"
}
func (db *oracle) QuoteStr() string {
return "\""
} }
func (db *oracle) SupportEngine() bool { func (db *oracle) SupportEngine() bool {
@ -596,7 +592,7 @@ func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, char
sql += col.String(b.dialect) sql += col.String(b.dialect)
} else {*/ } else {*/
sql += col.StringNoPk(db) sql += col.StringNoPk(db)
//} // }
sql = strings.TrimSpace(sql) sql = strings.TrimSpace(sql)
sql += ", " sql += ", "
} }
@ -865,7 +861,7 @@ func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, e
`\/(?P<dbname>.*?)` + // /dbname `\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN] `(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName) matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config) // tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames() names := dsnPattern.SubexpNames()
for i, match := range matches { for i, match := range matches {
@ -883,8 +879,8 @@ func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, e
type oci8Driver struct { type oci8Driver struct {
} }
//dataSourceName=user/password@ipv4:port/dbname // dataSourceName=user/password@ipv4:port/dbname
//dataSourceName=user/password@[ipv6]:port/dbname // dataSourceName=user/password@[ipv6]:port/dbname
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) { func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.ORACLE} db := &core.Uri{DbType: core.ORACLE}
dsnPattern := regexp.MustCompile( dsnPattern := regexp.MustCompile(

View file

@ -863,10 +863,6 @@ func (db *postgres) Quote(name string) string {
return "\"" + name + "\"" return "\"" + name + "\""
} }
func (db *postgres) QuoteStr() string {
return "\""
}
func (db *postgres) AutoIncrStr() string { func (db *postgres) AutoIncrStr() string {
return "" return ""
} }
@ -998,7 +994,7 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
return nil, nil, err return nil, nil, err
} }
//fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, numPrecision, numRadix, isPK, isUnique) // fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, numPrecision, numRadix, isPK, isUnique)
var maxLen int var maxLen int
if maxLenStr != nil { if maxLenStr != nil {
maxLen, err = strconv.Atoi(*maxLenStr) maxLen, err = strconv.Atoi(*maxLenStr)
@ -1093,7 +1089,6 @@ func (db *postgres) GetTables() ([]*core.Table, error) {
return tables, nil return tables, nil
} }
func getIndexColName(indexdef string) []string { func getIndexColName(indexdef string) []string {
var colNames []string var colNames []string
@ -1105,7 +1100,6 @@ func getIndexColName(indexdef string) []string {
return colNames return colNames
} }
func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) { func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) {
args := []interface{}{tableName} args := []interface{}{tableName}
s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1") s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")

View file

@ -202,10 +202,6 @@ func (db *sqlite3) Quote(name string) string {
return "`" + name + "`" return "`" + name + "`"
} }
func (db *sqlite3) QuoteStr() string {
return "`"
}
func (db *sqlite3) AutoIncrStr() string { func (db *sqlite3) AutoIncrStr() string {
return "AUTOINCREMENT" return "AUTOINCREMENT"
} }

View file

@ -175,12 +175,6 @@ func (engine *Engine) SupportInsertMany() bool {
return engine.dialect.SupportInsertMany() 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 { func (engine *Engine) quoteColumns(columnStr string) string {
columns := strings.Split(columnStr, ",") columns := strings.Split(columnStr, ",")
for i := 0; i < len(columns); i++ { for i := 0; i < len(columns); i++ {
@ -196,13 +190,10 @@ func (engine *Engine) Quote(value string) string {
return value return value
} }
if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' { buf := builder.StringBuilder{}
return value engine.QuoteTo(&buf, value)
}
value = strings.Replace(value, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1) return buf.String()
return engine.dialect.QuoteStr() + value + engine.dialect.QuoteStr()
} }
// QuoteTo quotes string and writes into the buffer // QuoteTo quotes string and writes into the buffer
@ -216,20 +207,30 @@ func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) {
return return
} }
if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' { quotePair := engine.dialect.Quote("")
buf.WriteString(value)
if value[0] == '`' || len(quotePair) < 2 || value[0] == quotePair[0] { // no quote
_, _ = buf.WriteString(value)
return 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 { 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 // 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{}) { func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}) {
switch sqlTypeName { switch sqlTypeName {
case core.Time: 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] v = s[11:19]
case core.Date: case core.Date:
v = t.Format("2006-01-02") v = t.Format("2006-01-02")

View file

@ -15,5 +15,5 @@ require (
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0
github.com/ziutek/mymysql v1.5.4 github.com/ziutek/mymysql v1.5.4
xorm.io/builder v0.3.5 xorm.io/builder v0.3.5
xorm.io/core v0.6.3 xorm.io/core v0.7.0
) )

View file

@ -1,5 +1,4 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 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.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 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= 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/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 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/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.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/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/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= 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= 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-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-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-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/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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 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-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-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-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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 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-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-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-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-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-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-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-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-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-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-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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-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-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-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/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.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.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-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-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/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= 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 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8= xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M= xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo= xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=

View file

@ -281,7 +281,7 @@ func rValue(bean interface{}) reflect.Value {
func rType(bean interface{}) reflect.Type { func rType(bean interface{}) reflect.Type {
sliceValue := reflect.Indirect(reflect.ValueOf(bean)) sliceValue := reflect.Indirect(reflect.ValueOf(bean))
//return reflect.TypeOf(sliceValue.Interface()) // return reflect.TypeOf(sliceValue.Interface())
return sliceValue.Type() return sliceValue.Type()
} }
@ -309,3 +309,24 @@ func sliceEq(left, right []string) bool {
func indexName(tableName, idxName string) string { func indexName(tableName, idxName string) string {
return fmt.Sprintf("IDX_%v_%v", tableName, idxName) 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+" ")
}

View file

@ -63,6 +63,8 @@ func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...inte
} }
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error { func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
defer session.resetStatement()
if session.statement.lastError != nil { if session.statement.lastError != nil {
return session.statement.lastError return session.statement.lastError
} }

View file

@ -24,6 +24,8 @@ func (session *Session) Get(bean interface{}) (bool, error) {
} }
func (session *Session) get(bean interface{}) (bool, error) { func (session *Session) get(bean interface{}) (bool, error) {
defer session.resetStatement()
if session.statement.lastError != nil { if session.statement.lastError != nil {
return false, session.statement.lastError return false, session.statement.lastError
} }
@ -75,6 +77,8 @@ func (session *Session) get(bean interface{}) (bool, error) {
if context != nil { if context != nil {
res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args)) res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
if res != nil { if res != nil {
session.engine.logger.Debug("hit context cache", sqlStr)
structValue := reflect.Indirect(reflect.ValueOf(bean)) structValue := reflect.Indirect(reflect.ValueOf(bean))
structValue.Set(reflect.Indirect(reflect.ValueOf(res))) structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
session.lastSQL = "" session.lastSQL = ""
@ -114,6 +118,114 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bea
return true, rows.Scan(&bean) return true, rows.Scan(&bean)
case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString: case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString:
return true, rows.Scan(bean) 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 { switch beanKind {
@ -142,6 +254,9 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bea
err = rows.ScanSlice(bean) err = rows.ScanSlice(bean)
case reflect.Map: case reflect.Map:
err = rows.ScanMap(bean) 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: default:
err = rows.Scan(bean) err = rows.Scan(bean)
} }

View file

@ -12,6 +12,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"xorm.io/builder"
"xorm.io/core" "xorm.io/core"
) )
@ -242,23 +243,17 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
var sql string var sql string
if session.engine.dialect.DBType() == core.ORACLE { 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.Quote(tableName),
session.engine.QuoteStr(), quoteColumns(colNames, session.engine.Quote, ","))
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), sql = fmt.Sprintf("INSERT ALL INTO %s (%v) VALUES (%v) SELECT 1 FROM DUAL",
session.engine.QuoteStr())
sql = fmt.Sprintf("INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL",
session.engine.Quote(tableName), session.engine.Quote(tableName),
session.engine.QuoteStr(), quoteColumns(colNames, session.engine.Quote, ","),
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.engine.QuoteStr(),
strings.Join(colMultiPlaces, temp)) strings.Join(colMultiPlaces, temp))
} else { } 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.Quote(tableName),
session.engine.QuoteStr(), quoteColumns(colNames, session.engine.Quote, ","),
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.engine.QuoteStr(),
strings.Join(colMultiPlaces, "),(")) strings.Join(colMultiPlaces, "),("))
} }
res, err := session.exec(sql, args...) res, err := session.exec(sql, args...)
@ -351,7 +346,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
for _, v := range exprColumns { for _, v := range exprColumns {
// remove the expr columns // remove the expr columns
for i, colName := range colNames { for i, colName := range colNames {
if colName == v.colName { if colName == strings.Trim(v.colName, "`") {
colNames = append(colNames[:i], colNames[i+1:]...) colNames = append(colNames[:i], colNames[i+1:]...)
args = append(args[:i], args[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 { if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 {
output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement) output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement)
} }
if len(colPlaces) > 0 { if len(colPlaces) > 0 {
sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v)%s VALUES (%v)", 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), session.engine.Quote(tableName),
session.engine.QuoteStr(), quoteColumns(colNames, session.engine.Quote, ","),
strings.Join(colNames, session.engine.Quote(", ")), output,
session.engine.QuoteStr(), 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, output,
colPlaces) colPlaces)
}
} else { } else {
if session.engine.dialect.DBType() == core.MYSQL { if session.engine.dialect.DBType() == core.MYSQL {
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName)) 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 return 0, ErrParamsType
} }
tableName := session.statement.TableName()
if len(tableName) <= 0 {
return 0, ErrTableNotFound
}
var columns = make([]string, 0, len(m)) var columns = make([]string, 0, len(m))
for k := range m { for k := range m {
columns = append(columns, k) columns = append(columns, k)
@ -678,19 +694,40 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err
sort.Strings(columns) sort.Strings(columns)
qm := strings.Repeat("?,", len(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)) var args = make([]interface{}, 0, len(m))
for _, colName := range columns { for _, colName := range columns {
args = append(args, m[colName]) args = append(args, m[colName])
} }
// insert expr columns, override if exists
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 { if err := session.cacheInsert(tableName); err != nil {
return 0, err return 0, err
} }
@ -711,26 +748,53 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
return 0, ErrParamsType return 0, ErrParamsType
} }
tableName := session.statement.TableName()
if len(tableName) <= 0 {
return 0, ErrTableNotFound
}
var columns = make([]string, 0, len(m)) var columns = make([]string, 0, len(m))
for k := range m { for k := range m {
columns = append(columns, k) columns = append(columns, k)
} }
sort.Strings(columns) 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)) var args = make([]interface{}, 0, len(m))
for _, colName := range columns { for _, colName := range columns {
args = append(args, m[colName]) args = append(args, m[colName])
} }
qm := strings.Repeat("?,", len(columns))
// insert expr columns, override if exists
exprColumns := session.statement.getExpr()
for _, col := range exprColumns {
columns = append(columns, strings.Trim(col.colName, "`"))
qm = qm + col.expr + ","
}
qm = qm[:len(qm)-1]
var sql string
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 { if err := session.cacheInsert(tableName); err != nil {
return 0, err return 0, err
} }

View file

@ -96,14 +96,15 @@ func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string,
return ErrCacheFailed return ErrCacheFailed
} }
kvs := strings.Split(strings.TrimSpace(sqls[1]), ",") kvs := strings.Split(strings.TrimSpace(sqls[1]), ",")
for idx, kv := range kvs { for idx, kv := range kvs {
sps := strings.SplitN(kv, "=", 2) sps := strings.SplitN(kv, "=", 2)
sps2 := strings.Split(sps[0], ".") sps2 := strings.Split(sps[0], ".")
colName := sps2[len(sps2)-1] colName := sps2[len(sps2)-1]
if strings.Contains(colName, "`") { // treat quote prefix, suffix and '`' as quotes
colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1)) quotes := append(strings.Split(session.engine.Quote(""), ""), "`")
} else if strings.Contains(colName, session.engine.QuoteStr()) { if strings.ContainsAny(colName, strings.Join(quotes, "")) {
colName = strings.TrimSpace(strings.Replace(colName, session.engine.QuoteStr(), "", -1)) colName = strings.TrimSpace(eraseAny(colName, quotes...))
} else { } else {
session.engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName) session.engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName)
return ErrCacheFailed 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() incColumns := session.statement.getInc()
for _, v := range incColumns { for _, v := range incColumns {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?") colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?")
args = append(args, v.arg) args = append(args, v.arg)
} }
//for update action to like "column = column - ?" // for update action to like "column = column - ?"
decColumns := session.statement.getDec() decColumns := session.statement.getDec()
for _, v := range decColumns { for _, v := range decColumns {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" - ?") colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" - ?")
args = append(args, v.arg) args = append(args, v.arg)
} }
//for update action to like "column = expression" // for update action to like "column = expression"
exprColumns := session.statement.getExpr() exprColumns := session.statement.getExpr()
for _, v := range exprColumns { for _, v := range exprColumns {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+v.expr) 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 { 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) session.engine.logger.Debug("[cacheUpdate] clear table ", tableName)
cacher.ClearIds(tableName) cacher.ClearIds(tableName)
cacher.ClearBeans(tableName) cacher.ClearBeans(tableName)

View file

@ -6,7 +6,6 @@ package xorm
import ( import (
"database/sql/driver" "database/sql/driver"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@ -398,7 +397,7 @@ func (statement *Statement) buildUpdates(bean interface{},
continue continue
} }
} else { } else {
//TODO: how to handler? // TODO: how to handler?
panic("not supported") panic("not supported")
} }
} else { } else {
@ -579,21 +578,9 @@ func (statement *Statement) getExpr() map[string]exprParam {
func (statement *Statement) col2NewColsWithQuote(columns ...string) []string { func (statement *Statement) col2NewColsWithQuote(columns ...string) []string {
newColumns := make([]string, 0) newColumns := make([]string, 0)
quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`")
for _, col := range columns { for _, col := range columns {
col = strings.Replace(col, "`", "", -1) newColumns = append(newColumns, statement.Engine.Quote(eraseAny(col, quotes...)))
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"))
}
}
} }
return newColumns return newColumns
} }
@ -764,7 +751,9 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition
return statement return statement
} }
tbs := strings.Split(tp.TableName(), ".") 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) fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition)
statement.joinArgs = append(statement.joinArgs, subQueryArgs...) statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
case *builder.Builder: case *builder.Builder:
@ -774,7 +763,9 @@ func (statement *Statement) Join(joinOP string, tablename interface{}, condition
return statement return statement
} }
tbs := strings.Split(tp.TableName(), ".") 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) fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition)
statement.joinArgs = append(statement.joinArgs, subQueryArgs...) statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
default: default:
@ -1157,8 +1148,12 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n
if statement.Start != 0 || statement.LimitN != 0 { if statement.Start != 0 || statement.LimitN != 0 {
oldString := buf.String() oldString := buf.String()
buf.Reset() 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", 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] var whereStr = sqls[1]
//TODO: for postgres only, if any other database? // TODO: for postgres only, if any other database?
var paraStr string var paraStr string
if statement.Engine.dialect.DBType() == core.POSTGRES { if statement.Engine.dialect.DBType() == core.POSTGRES {
paraStr = "$" paraStr = "$"

4
vendor/modules.txt vendored
View file

@ -148,7 +148,7 @@ github.com/go-redis/redis/internal/proto
github.com/go-redis/redis/internal/util github.com/go-redis/redis/internal/util
# github.com/go-sql-driver/mysql v1.4.1 # github.com/go-sql-driver/mysql v1.4.1
github.com/go-sql-driver/mysql 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/go-xorm/xorm
# github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 # github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
github.com/gogits/chardet github.com/gogits/chardet
@ -482,5 +482,5 @@ mvdan.cc/xurls/v2
strk.kbt.io/projects/go/libravatar strk.kbt.io/projects/go/libravatar
# xorm.io/builder v0.3.5 # xorm.io/builder v0.3.5
xorm.io/builder xorm.io/builder
# xorm.io/core v0.6.3 # xorm.io/core v0.7.0
xorm.io/core xorm.io/core

42
vendor/xorm.io/core/.drone.yml generated vendored Normal file
View file

@ -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 ]

4
vendor/xorm.io/core/README.md generated vendored
View file

@ -1,6 +1,8 @@
Core is a lightweight wrapper of sql.DB. Core is a lightweight wrapper of sql.DB.
[![CircleCI](https://circleci.com/gh/go-xorm/core/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/core/tree/master) [![Build Status](https://drone.gitea.com/api/badges/xorm/core/status.svg)](https://drone.gitea.com/xorm/core)
[![](http://gocover.io/_badge/xorm.io/core)](http://gocover.io/xorm.io/core)
[![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/xorm.io/core)
# Open # Open
```Go ```Go

16
vendor/xorm.io/core/cache.go generated vendored
View file

@ -14,19 +14,20 @@ import (
) )
const ( const (
// default cache expired time // CacheExpired is default cache expired time
CacheExpired = 60 * time.Minute CacheExpired = 60 * time.Minute
// not use now // CacheMaxMemory is not use now
CacheMaxMemory = 256 CacheMaxMemory = 256
// evey ten minutes to clear all expired nodes // CacheGcInterval represents interval time to clear all expired nodes
CacheGcInterval = 10 * time.Minute CacheGcInterval = 10 * time.Minute
// each time when gc to removed max nodes // CacheGcMaxRemoved represents max nodes removed when gc
CacheGcMaxRemoved = 20 CacheGcMaxRemoved = 20
) )
// list all the errors
var ( var (
ErrCacheMiss = errors.New("xorm/cache: key not found.") ErrCacheMiss = errors.New("xorm/cache: key not found")
ErrNotStored = errors.New("xorm/cache: not stored.") ErrNotStored = errors.New("xorm/cache: not stored")
) )
// CacheStore is a interface to store cache // CacheStore is a interface to store cache
@ -69,6 +70,7 @@ func decodeIds(s string) ([]PK, error) {
return pks, err return pks, err
} }
// GetCacheSql returns cacher PKs via SQL
func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error) { func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error) {
bytes := m.GetIds(tableName, GenSqlKey(sql, args)) bytes := m.GetIds(tableName, GenSqlKey(sql, args))
if bytes == nil { if bytes == nil {
@ -77,6 +79,7 @@ func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error
return decodeIds(bytes.(string)) return decodeIds(bytes.(string))
} }
// PutCacheSql puts cacher SQL and PKs
func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) error { func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) error {
bytes, err := encodeIds(ids) bytes, err := encodeIds(ids)
if err != nil { if err != nil {
@ -86,6 +89,7 @@ func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) er
return nil return nil
} }
// GenSqlKey generates cache key
func GenSqlKey(sql string, args interface{}) string { func GenSqlKey(sql string, args interface{}) string {
return fmt.Sprintf("%v-%v", sql, args) return fmt.Sprintf("%v-%v", sql, args)
} }

4
vendor/xorm.io/core/column.go generated vendored
View file

@ -73,7 +73,7 @@ func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable
// String generate column description string according dialect // String generate column description string according dialect
func (col *Column) String(d Dialect) string { func (col *Column) String(d Dialect) string {
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " sql := d.Quote(col.Name) + " "
sql += d.SqlType(col) + " " 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 // StringNoPk generate column description string according dialect without primary keys
func (col *Column) StringNoPk(d Dialect) string { func (col *Column) StringNoPk(d Dialect) string {
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " " sql := d.Quote(col.Name) + " "
sql += d.SqlType(col) + " " sql += d.SqlType(col) + " "

4
vendor/xorm.io/core/db.go generated vendored
View file

@ -15,6 +15,7 @@ import (
) )
var ( var (
// DefaultCacheSize sets the default cache size
DefaultCacheSize = 200 DefaultCacheSize = 200
) )
@ -132,6 +133,7 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
return db.QueryContext(context.Background(), query, args...) 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) { func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{}) (*Rows, error) {
query, args, err := MapToSlice(query, mp) query, args, err := MapToSlice(query, mp)
if err != nil { if err != nil {
@ -140,6 +142,7 @@ func (db *DB) QueryMapContext(ctx context.Context, query string, mp interface{})
return db.QueryContext(ctx, query, args...) return db.QueryContext(ctx, query, args...)
} }
// QueryMap executes query with parameters via map
func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) { func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
return db.QueryMapContext(context.Background(), query, mp) return db.QueryMapContext(context.Background(), query, mp)
} }
@ -196,6 +199,7 @@ var (
re = regexp.MustCompile(`[?](\w+)`) re = regexp.MustCompile(`[?](\w+)`)
) )
// ExecMapContext exec map with context.Context
// insert into (name) values (?) // insert into (name) values (?)
// insert into (name) values (?name) // insert into (name) values (?name)
func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) { func (db *DB) ExecMapContext(ctx context.Context, query string, mp interface{}) (sql.Result, error) {

20
vendor/xorm.io/core/dialect.go generated vendored
View file

@ -40,9 +40,9 @@ type Dialect interface {
DriverName() string DriverName() string
DataSourceName() string DataSourceName() string
QuoteStr() string
IsReserved(string) bool IsReserved(string) bool
Quote(string) string Quote(string) string
AndStr() string AndStr() string
OrStr() string OrStr() string
EqStr() string EqStr() string
@ -70,8 +70,8 @@ type Dialect interface {
ForUpdateSql(query string) string ForUpdateSql(query string) string
//CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error // CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error
//MustDropTable(tableName string) error // MustDropTable(tableName string) error
GetColumns(tableName string) ([]string, map[string]*Column, error) GetColumns(tableName string) ([]string, map[string]*Column, error)
GetTables() ([]*Table, error) GetTables() ([]*Table, error)
@ -85,6 +85,7 @@ func OpenDialect(dialect Dialect) (*DB, error) {
return Open(dialect.DriverName(), dialect.DataSourceName()) return Open(dialect.DriverName(), dialect.DataSourceName())
} }
// Base represents a basic dialect and all real dialects could embed this struct
type Base struct { type Base struct {
db *DB db *DB
dialect Dialect 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) { 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 := fmt.Sprintf(
query = strings.Replace(query, "`", db.dialect.QuoteStr(), -1) "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) 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 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 { func QueryDialect(dbName DbType) Dialect {
if d, ok := dialects[strings.ToLower(string(dbName))]; ok { if d, ok := dialects[strings.ToLower(string(dbName))]; ok {
return d() return d()

2
vendor/xorm.io/core/error.go generated vendored
View file

@ -7,6 +7,8 @@ package core
import "errors" import "errors"
var ( var (
// ErrNoMapPointer represents error when no map pointer
ErrNoMapPointer = errors.New("mp should be a map's 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") ErrNoStructPointer = errors.New("mp should be a struct's pointer")
) )

20
vendor/xorm.io/core/filter.go generated vendored
View file

@ -19,7 +19,23 @@ type QuoteFilter struct {
} }
func (s *QuoteFilter) Do(sql string, dialect Dialect, table *Table) string { 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 // 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 { 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 { func (i *IdFilter) Do(sql string, dialect Dialect, table *Table) string {

8
vendor/xorm.io/core/go.mod generated vendored
View file

@ -2,6 +2,12 @@ module xorm.io/core
require ( require (
github.com/go-sql-driver/mysql v1.4.1 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 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
) )

14
vendor/xorm.io/core/go.sum generated vendored
View file

@ -1,9 +1,23 @@
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 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/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.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 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 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-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.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 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.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=

4
vendor/xorm.io/core/ilogger.go generated vendored
View file

@ -4,8 +4,10 @@
package core package core
// LogLevel defines a log level
type LogLevel int type LogLevel int
// enumerate all LogLevels
const ( const (
// !nashtsai! following level also match syslog.Priority value // !nashtsai! following level also match syslog.Priority value
LOG_DEBUG LogLevel = iota LOG_DEBUG LogLevel = iota
@ -16,7 +18,7 @@ const (
LOG_UNKNOWN LOG_UNKNOWN
) )
// logger interface // ILogger is a logger interface
type ILogger interface { type ILogger interface {
Debug(v ...interface{}) Debug(v ...interface{})
Debugf(format string, v ...interface{}) Debugf(format string, v ...interface{})

7
vendor/xorm.io/core/index.go generated vendored
View file

@ -9,12 +9,13 @@ import (
"strings" "strings"
) )
// enumerate all index types
const ( const (
IndexType = iota + 1 IndexType = iota + 1
UniqueType UniqueType
) )
// database index // Index represents a database index
type Index struct { type Index struct {
IsRegular bool IsRegular bool
Name string Name string
@ -35,7 +36,7 @@ func (index *Index) XName(tableName string) string {
return index.Name return index.Name
} }
// add columns which will be composite index // AddColumn add columns which will be composite index
func (index *Index) AddColumn(cols ...string) { func (index *Index) AddColumn(cols ...string) {
for _, col := range cols { for _, col := range cols {
index.Cols = append(index.Cols, col) index.Cols = append(index.Cols, col)
@ -65,7 +66,7 @@ func (index *Index) Equal(dst *Index) bool {
return true return true
} }
// new an index // NewIndex new an index object
func NewIndex(name string, indexType int) *Index { func NewIndex(name string, indexType int) *Index {
return &Index{true, name, indexType, make([]string, 0)} return &Index{true, name, indexType, make([]string, 0)}
} }

8
vendor/xorm.io/core/mapper.go generated vendored
View file

@ -9,7 +9,7 @@ import (
"sync" "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 { type IMapper interface {
Obj2Table(string) string Obj2Table(string) string
Table2Obj(string) string Table2Obj(string) string
@ -184,7 +184,7 @@ func (mapper GonicMapper) Table2Obj(name string) string {
return string(newstr) 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{ var LintGonicMapper = GonicMapper{
"API": true, "API": true,
"ASCII": true, "ASCII": true,
@ -221,7 +221,7 @@ var LintGonicMapper = GonicMapper{
"XSS": true, "XSS": true,
} }
// provide prefix table name support // PrefixMapper provides prefix table name support
type PrefixMapper struct { type PrefixMapper struct {
Mapper IMapper Mapper IMapper
Prefix string Prefix string
@ -239,7 +239,7 @@ func NewPrefixMapper(mapper IMapper, prefix string) PrefixMapper {
return PrefixMapper{mapper, prefix} return PrefixMapper{mapper, prefix}
} }
// provide suffix table name support // SuffixMapper provides suffix table name support
type SuffixMapper struct { type SuffixMapper struct {
Mapper IMapper Mapper IMapper
Suffix string Suffix string

2
vendor/xorm.io/core/rows.go generated vendored
View file

@ -170,7 +170,7 @@ func (rs *Rows) ScanMap(dest interface{}) error {
newDest := make([]interface{}, len(cols)) newDest := make([]interface{}, len(cols))
vvv := vv.Elem() vvv := vv.Elem()
for i, _ := range cols { for i := range cols {
newDest[i] = rs.db.reflectNew(vvv.Type().Elem()).Interface() newDest[i] = rs.db.reflectNew(vvv.Type().Elem()).Interface()
} }

1
vendor/xorm.io/core/stmt.go generated vendored
View file

@ -11,6 +11,7 @@ import (
"reflect" "reflect"
) )
// Stmt reprents a stmt objects
type Stmt struct { type Stmt struct {
*sql.Stmt *sql.Stmt
db *DB db *DB

9
vendor/xorm.io/core/table.go generated vendored
View file

@ -9,7 +9,7 @@ import (
"strings" "strings"
) )
// database table // Table represents a database table
type Table struct { type Table struct {
Name string Name string
Type reflect.Type Type reflect.Type
@ -41,6 +41,7 @@ func NewEmptyTable() *Table {
return NewTable("", nil) return NewTable("", nil)
} }
// NewTable creates a new Table object
func NewTable(name string, t reflect.Type) *Table { func NewTable(name string, t reflect.Type) *Table {
return &Table{Name: name, Type: t, return &Table{Name: name, Type: t,
columnsSeq: make([]string, 0), columnsSeq: make([]string, 0),
@ -87,7 +88,7 @@ func (table *Table) GetColumnIdx(name string, idx int) *Column {
return nil return nil
} }
// if has primary key, return column // PKColumns reprents all primary key columns
func (table *Table) PKColumns() []*Column { func (table *Table) PKColumns() []*Column {
columns := make([]*Column, len(table.PrimaryKeys)) columns := make([]*Column, len(table.PrimaryKeys))
for i, name := range table.PrimaryKeys { for i, name := range table.PrimaryKeys {
@ -117,7 +118,7 @@ func (table *Table) DeletedColumn() *Column {
return table.GetColumn(table.Deleted) return table.GetColumn(table.Deleted)
} }
// add a column to table // AddColumn adds a column to table
func (table *Table) AddColumn(col *Column) { func (table *Table) AddColumn(col *Column) {
table.columnsSeq = append(table.columnsSeq, col.Name) table.columnsSeq = append(table.columnsSeq, col.Name)
table.columns = append(table.columns, col) 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) { func (table *Table) AddIndex(index *Index) {
table.Indexes[index.Name] = index table.Indexes[index.Name] = index
} }