Merge branch 'master' into lunny/local_log

This commit is contained in:
Lunny Xiao 2019-09-29 12:53:38 +08:00 committed by GitHub
commit b4d3a78b10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1947 additions and 433 deletions

View File

@ -1,125 +1,747 @@
---
kind: pipeline
name: matrix-1
platform:
os: linux
arch: amd64
clone:
disable: true
workspace:
base: /go
path: src/github.com/go-xorm/xorm
clone:
git:
image: plugins/git:next
steps:
- name: git
pull: default
image: plugins/git:next
settings:
depth: 50
tags: true
- name: init_postgres
pull: default
image: postgres:9.5
commands:
- "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n"
- "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n"
- name: build
pull: default
image: golang:1.10
commands:
- go get -t -d -v ./...
- go get -u xorm.io/core
- go get -u xorm.io/builder
- go build -v
when:
event:
- push
- pull_request
- name: test-sqlite
pull: default
image: golang:1.10
commands:
- go get -u github.com/wadey/gocovmerge
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic"
- "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mysql
pull: default
image: golang:1.10
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mysql-utf8mb4
pull: default
image: golang:1.10
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mymysql
pull: default
image: golang:1.10
commands:
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres
pull: default
image: golang:1.10
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres-schema
pull: default
image: golang:1.10
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mssql
pull: default
image: golang:1.10
commands:
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt
when:
event:
- push
- pull_request
services:
mysql:
image: mysql:5.7
environment:
- MYSQL_DATABASE=xorm_test
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
when:
event: [ push, tag, pull_request ]
- name: mysql
pull: default
image: mysql:5.7
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: xorm_test
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 ]
- name: pgsql
pull: default
image: postgres:9.5
environment:
POSTGRES_DB: xorm_test
POSTGRES_USER: postgres
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"
- name: mssql
pull: default
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: yourStrong(!)Password
MSSQL_PID: Developer
when:
event:
- push
- tag
- pull_request
matrix:
GO_VERSION:
- 1.8
- 1.9
- 1.10
- 1.11
---
kind: pipeline
name: matrix-2
pipeline:
init_postgres:
image: postgres:9.5
commands:
# wait for postgres service to become available
- |
until psql -U postgres -d xorm_test -h pgsql \
-c "SELECT 1;" >/dev/null 2>&1; do sleep 1; done
# query the database
- |
psql -U postgres -d xorm_test -h pgsql \
-c "create schema xorm;"
platform:
os: linux
arch: amd64
build:
image: golang:${GO_VERSION}
commands:
- go get -t -d -v ./...
- go get -u xorm.io/core
- go get -u xorm.io/builder
- go build -v
when:
event: [ push, pull_request ]
clone:
disable: true
test-sqlite:
image: golang:${GO_VERSION}
commands:
- go get -u github.com/wadey/gocovmerge
- go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic
- go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic
when:
event: [ push, pull_request ]
workspace:
base: /go
path: src/github.com/go-xorm/xorm
test-mysql:
image: golang:${GO_VERSION}
commands:
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic
when:
event: [ push, pull_request ]
steps:
- name: git
pull: default
image: plugins/git:next
settings:
depth: 50
tags: true
test-mysql-utf8mb4:
image: golang:${GO_VERSION}
commands:
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -coverprofile=coverage2.1-1.txt -covermode=atomic
- go test -v -race -db="mysql" -conn_str="root:@tcp(mysql)/xorm_test?charset=utf8mb4" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic
when:
event: [ push, pull_request ]
- 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"
test-mymysql:
image: golang:${GO_VERSION}
commands:
- go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic
- go test -v -race -db="mymysql" -conn_str="tcp:mysql:3306*xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic
when:
event: [ push, pull_request ]
- name: build
pull: default
image: golang:1.11
environment:
GO111MODULE: "off"
commands:
- go get -t -d -v ./...
- go get -u xorm.io/core
- go get -u xorm.io/builder
- go build -v
when:
event:
- push
- pull_request
test-postgres:
image: golang:${GO_VERSION}
commands:
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic
when:
event: [ push, pull_request ]
test-postgres-schema:
image: golang:${GO_VERSION}
commands:
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic
- go test -v -race -db="postgres" -conn_str="postgres://postgres:@pgsql/xorm_test?sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt > coverage.txt
when:
event: [ push, pull_request ]
- name: build-gomod
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- go build -v
when:
event:
- push
- pull_request
#coverage:
# image: robertstettner/drone-codecov
# secrets: [ codecov_token ]
# files:
# - coverage.txt
# when:
# event: [ push, pull_request ]
# branch: [ master ]
- name: test-sqlite
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "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
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mysql-utf8mb4
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mymysql
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres-schema
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mssql
pull: default
image: golang:1.11
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
- go get github.com/wadey/gocovmerge
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt
when:
event:
- push
- 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
- name: mssql
pull: default
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: yourStrong(!)Password
MSSQL_PID: Developer
when:
event:
- push
- tag
- pull_request
---
kind: pipeline
name: matrix-3
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
environment:
GO111MODULE: "off"
commands:
- go get -t -d -v ./...
- go get -u xorm.io/core
- go get -u xorm.io/builder
- go build -v
when:
event:
- push
- pull_request
- name: build-gomod
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- go build -v
when:
event:
- push
- pull_request
- name: test-sqlite
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "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
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mysql-utf8mb4
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mymysql
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres-schema
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mssql
pull: default
image: golang:1.12
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
- go get -u github.com/wadey/gocovmerge
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt
when:
event:
- push
- 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
- name: mssql
pull: default
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: yourStrong(!)Password
MSSQL_PID: Developer
when:
event:
- push
- tag
- pull_request
---
kind: pipeline
name: go1.13
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.13
environment:
GO111MODULE: "off"
commands:
- go get -t -d -v ./...
- go get -u xorm.io/core
- go get -u xorm.io/builder
- go build -v
when:
event:
- push
- pull_request
- name: build-gomod
pull: default
image: golang:1.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- go build -v
when:
event:
- push
- pull_request
- name: test-sqlite
pull: default
image: golang:1.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "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.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mysql-utf8mb4
pull: default
image: golang:1.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic"
- "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mymysql
pull: default
image: golang:1.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic"
- "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres
pull: default
image: golang:1.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-postgres-schema
pull: default
image: golang:1.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic"
- "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic"
when:
event:
- push
- pull_request
- name: test-mssql
pull: default
image: golang:1.13
environment:
GO111MODULE: "on"
GOPROXY: "https://goproxy.cn"
commands:
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic"
- "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic"
- go get -u github.com/wadey/gocovmerge
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt
when:
event:
- push
- 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
- name: mssql
pull: default
image: microsoft/mssql-server-linux:latest
environment:
ACCEPT_EULA: Y
SA_PASSWORD: yourStrong(!)Password
MSSQL_PID: Developer
when:
event:
- push
- tag
- pull_request

View File

@ -254,6 +254,9 @@ func (db *mssql) SqlType(c *core.Column) string {
case core.TinyInt:
res = core.TinyInt
c.Length = 0
case core.BigInt:
res = core.BigInt
c.Length = 0
default:
res = t
}
@ -335,6 +338,7 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{}
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
"default_is_null" = (CASE WHEN c.text is null THEN 1 ELSE 0 END),
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault,
ISNULL(i.is_primary_key, 0)
from sys.columns a
@ -358,8 +362,8 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
for rows.Next() {
var name, ctype, vdefault string
var maxLen, precision, scale int
var nullable, isPK bool
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK)
var nullable, isPK, defaultIsNull bool
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &defaultIsNull, &vdefault, &isPK)
if err != nil {
return nil, nil, err
}
@ -368,7 +372,10 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
col.Indexes = make(map[string]int)
col.Name = strings.Trim(name, "` ")
col.Nullable = nullable
col.Default = vdefault
col.DefaultIsEmpty = defaultIsNull
if !defaultIsNull {
col.Default = vdefault
}
col.IsPrimaryKey = isPK
ct := strings.ToUpper(ctype)
if ct == "DECIMAL" {
@ -392,15 +399,6 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
}
}
if col.SQLType.IsText() || col.SQLType.IsTime() {
if col.Default != "" {
col.Default = "'" + col.Default + "'"
} else {
if col.DefaultIsEmpty {
col.Default = "''"
}
}
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}

View File

@ -345,9 +345,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
if colDefault != nil {
col.Default = *colDefault
if col.Default == "" {
col.DefaultIsEmpty = true
}
col.DefaultIsEmpty = false
} else {
col.DefaultIsEmpty = true
}
cts := strings.Split(colType, "(")
@ -411,13 +411,11 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
col.IsAutoIncrement = true
}
if col.SQLType.IsText() || col.SQLType.IsTime() {
if col.Default != "" {
if !col.DefaultIsEmpty {
if col.SQLType.IsText() {
col.Default = "'" + col.Default + "'"
} else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" {
col.Default = "'" + col.Default + "'"
} else {
if col.DefaultIsEmpty {
col.Default = "''"
}
}
}
cols[col.Name] = col

View File

@ -952,7 +952,7 @@ func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{tableName}
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_precision_radix ,
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length,
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
FROM pg_attribute f
@ -987,14 +987,14 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
col.Indexes = make(map[string]int)
var colName, isNullable, dataType string
var maxLenStr, colDefault, numPrecision, numRadix *string
var maxLenStr, colDefault *string
var isPK, isUnique bool
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &numPrecision, &numRadix, &isPK, &isUnique)
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &isPK, &isUnique)
if err != nil {
return nil, nil, err
}
// fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, numPrecision, numRadix, isPK, isUnique)
// fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, isPK, isUnique)
var maxLen int
if maxLenStr != nil {
maxLen, err = strconv.Atoi(*maxLenStr)
@ -1005,16 +1005,18 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
col.Name = strings.Trim(colName, `" `)
if colDefault != nil || isPK {
if isPK {
col.IsPrimaryKey = true
} else {
col.Default = *colDefault
if colDefault != nil {
col.Default = *colDefault
col.DefaultIsEmpty = false
if strings.HasPrefix(col.Default, "nextval(") {
col.IsAutoIncrement = true
}
} else {
col.DefaultIsEmpty = true
}
if colDefault != nil && strings.HasPrefix(*colDefault, "nextval(") {
col.IsAutoIncrement = true
if isPK {
col.IsPrimaryKey = true
}
col.Nullable = (isNullable == "YES")
@ -1043,12 +1045,16 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
col.Length = maxLen
if col.SQLType.IsText() || col.SQLType.IsTime() {
if col.Default != "" {
col.Default = "'" + col.Default + "'"
} else {
if col.DefaultIsEmpty {
col.Default = "''"
if !col.DefaultIsEmpty {
if col.SQLType.IsText() {
if strings.HasSuffix(col.Default, "::character varying") {
col.Default = strings.TrimRight(col.Default, "::character varying")
} else if !strings.HasPrefix(col.Default, "'") {
col.Default = "'" + col.Default + "'"
}
} else if col.SQLType.IsTime() {
if strings.HasSuffix(col.Default, "::timestamp without time zone") {
col.Default = strings.TrimRight(col.Default, "::timestamp without time zone")
}
}
}

View File

@ -4,9 +4,8 @@ import (
"reflect"
"testing"
"xorm.io/core"
"github.com/jackc/pgx/stdlib"
"github.com/stretchr/testify/assert"
"xorm.io/core"
)
func TestParsePostgres(t *testing.T) {
@ -72,10 +71,7 @@ func TestParsePgx(t *testing.T) {
}
// Register DriverConfig
drvierConfig := stdlib.DriverConfig{}
stdlib.RegisterDriverConfig(&drvierConfig)
uri, err = driver.Parse("pgx",
drvierConfig.ConnectionString(test.in))
uri, err = driver.Parse("pgx", test.in)
if err != nil && test.valid {
t.Errorf("%q got unexpected error: %s", test.in, err)
} else if err == nil && !reflect.DeepEqual(test.expected, uri.DbName) {

View File

@ -270,6 +270,34 @@ func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
return false, nil
}
// splitColStr splits a sqlite col strings as fields
func splitColStr(colStr string) []string {
colStr = strings.TrimSpace(colStr)
var results = make([]string, 0, 10)
var lastIdx int
var hasC, hasQuote bool
for i, c := range colStr {
if c == ' ' && !hasQuote {
if hasC {
results = append(results, colStr[lastIdx:i])
hasC = false
}
} else {
if c == '\'' {
hasQuote = !hasQuote
}
if !hasC {
lastIdx = i
}
hasC = true
if i == len(colStr)-1 {
results = append(results, colStr[lastIdx:i+1])
}
}
}
return results
}
func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{tableName}
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
@ -315,7 +343,7 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
continue
}
fields := strings.Fields(strings.TrimSpace(colStr))
fields := splitColStr(colStr)
col := new(core.Column)
col.Indexes = make(map[string]int)
col.Nullable = true
@ -344,9 +372,6 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
col.DefaultIsEmpty = false
}
}
if !col.SQLType.IsNumeric() && !col.DefaultIsEmpty {
col.Default = "'" + col.Default + "'"
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}

35
dialect_sqlite3_test.go Normal file
View File

@ -0,0 +1,35 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSplitColStr(t *testing.T) {
var kases = []struct {
colStr string
fields []string
}{
{
colStr: "`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
fields: []string{
"`id`", "INTEGER", "PRIMARY", "KEY", "AUTOINCREMENT", "NOT", "NULL",
},
},
{
colStr: "`created` DATETIME DEFAULT '2006-01-02 15:04:05' NULL",
fields: []string{
"`created`", "DATETIME", "DEFAULT", "'2006-01-02 15:04:05'", "NULL",
},
},
}
for _, kase := range kases {
assert.EqualValues(t, kase.fields, splitColStr(kase.colStr))
}
}

View File

@ -190,14 +190,14 @@ func (engine *Engine) Quote(value string) string {
return value
}
buf := builder.StringBuilder{}
buf := strings.Builder{}
engine.QuoteTo(&buf, value)
return buf.String()
}
// QuoteTo quotes string and writes into the buffer
func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) {
func (engine *Engine) QuoteTo(buf *strings.Builder, value string) {
if buf == nil {
return
}
@ -729,7 +729,7 @@ func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
}
// SetExpr provides a update string like "column = {expression}"
func (engine *Engine) SetExpr(column string, expression string) *Session {
func (engine *Engine) SetExpr(column string, expression interface{}) *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.SetExpr(column, expression)
@ -907,8 +907,15 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
fieldType := fieldValue.Type()
if ormTagStr != "" {
col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]int)}
col = &core.Column{
FieldName: t.Field(i).Name,
Nullable: true,
IsPrimaryKey: false,
IsAutoIncrement: false,
MapType: core.TWOSIDES,
Indexes: make(map[string]int),
DefaultIsEmpty: true,
}
tags := splitTag(ormTagStr)
if len(tags) > 0 {

13
go.mod
View File

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

45
go.sum
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.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
@ -13,7 +12,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -30,12 +28,15 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
@ -49,18 +50,13 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90=
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx v3.6.0+incompatible h1:bJeo4JdVbDAW8KB2m8XkFeo8CPipREoG37BwEoKGz+Q=
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
@ -85,8 +81,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@ -95,6 +89,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@ -102,6 +98,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -114,29 +112,39 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw=
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -149,11 +157,16 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
xorm.io/builder v0.3.5 h1:EilU39fvWDxjb1cDaELpYhsF+zziRBhew8xk4pngO+A=
xorm.io/builder v0.3.5/go.mod h1:ZFbByS/KxZI1FKRjL05PyJ4YrK2bcxlUaAxdum5aTR8=
xorm.io/core v0.6.3 h1:n1NhVZt1s2oLw1BZfX2ocIJsHyso259uPgg63BGr37M=
xorm.io/core v0.6.3/go.mod h1:8kz/C6arVW/O9vk3PgCiMJO2hIAm1UcuOL3dSPyZ2qo=
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM=
xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI=
xorm.io/core v0.7.1 h1:I6x6Q6dYb67aDEoYFWr2t8UcKIYjJPyCHS+aXuj5V0Y=
xorm.io/core v0.7.1/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo=
xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=

View File

@ -10,25 +10,6 @@ import (
"github.com/stretchr/testify/assert"
)
func TestSplitTag(t *testing.T) {
var cases = []struct {
tag string
tags []string
}{
{"not null default '2000-01-01 00:00:00' TIMESTAMP", []string{"not", "null", "default", "'2000-01-01 00:00:00'", "TIMESTAMP"}},
{"TEXT", []string{"TEXT"}},
{"default('2000-01-01 00:00:00')", []string{"default('2000-01-01 00:00:00')"}},
{"json binary", []string{"json", "binary"}},
}
for _, kase := range cases {
tags := splitTag(kase.tag)
if !sliceEq(tags, kase.tags) {
t.Fatalf("[%d]%v is not equal [%d]%v", len(tags), tags, len(kase.tags), kase.tags)
}
}
}
func TestEraseAny(t *testing.T) {
raw := "SELECT * FROM `table`.[table_name]"
assert.EqualValues(t, raw, eraseAny(raw))

View File

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

View File

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

View File

@ -7,21 +7,38 @@ package xorm
import (
"testing"
"xorm.io/core"
"github.com/stretchr/testify/assert"
"xorm.io/builder"
"xorm.io/core"
)
func TestSetExpr(t *testing.T) {
assert.NoError(t, prepareEngine())
type UserExprIssue struct {
Id int64
Title string
}
assert.NoError(t, testEngine.Sync2(new(UserExprIssue)))
var issue = UserExprIssue{
Title: "my issue",
}
cnt, err := testEngine.Insert(&issue)
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
assert.EqualValues(t, 1, issue.Id)
type UserExpr struct {
Id int64
Show bool
Id int64
IssueId int64 `xorm:"index"`
Show bool
}
assert.NoError(t, testEngine.Sync2(new(UserExpr)))
cnt, err := testEngine.Insert(&UserExpr{
cnt, err = testEngine.Insert(&UserExpr{
Show: true,
})
assert.NoError(t, err)
@ -34,6 +51,16 @@ func TestSetExpr(t *testing.T) {
cnt, err = testEngine.SetExpr("show", not+" `show`").ID(1).Update(new(UserExpr))
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
tableName := testEngine.TableName(new(UserExprIssue), true)
cnt, err = testEngine.SetExpr("issue_id",
builder.Select("id").
From(tableName).
Where(builder.Eq{"id": issue.Id})).
ID(1).
Update(new(UserExpr))
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
}
func TestCols(t *testing.T) {

View File

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

View File

@ -24,6 +24,8 @@ func (session *Session) Get(bean interface{}) (bool, error) {
}
func (session *Session) get(bean interface{}) (bool, error) {
defer session.resetStatement()
if session.statement.lastError != nil {
return false, session.statement.lastError
}
@ -75,6 +77,8 @@ func (session *Session) get(bean interface{}) (bool, error) {
if context != nil {
res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
if res != nil {
session.engine.logger.Debug("hit context cache", sqlStr)
structValue := reflect.Indirect(reflect.ValueOf(bean))
structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
session.lastSQL = ""
@ -252,7 +256,7 @@ func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bea
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)
err = rows.Scan(bean)
default:
err = rows.Scan(bean)
}

View File

@ -584,3 +584,37 @@ func TestGetNullVar(t *testing.T) {
assert.True(t, has)
assert.EqualValues(t, 0, age10)
}
func TestCustomTypes(t *testing.T) {
type MyInt int
type MyString string
type TestCustomizeStruct struct {
Id int64
Name MyString
Age MyInt
}
assert.NoError(t, prepareEngine())
assertSync(t, new(TestCustomizeStruct))
var s = TestCustomizeStruct{
Name: "test",
Age: 32,
}
_, err := testEngine.Insert(&s)
assert.NoError(t, err)
assert.EqualValues(t, 1, s.Id)
var name MyString
has, err := testEngine.Table(new(TestCustomizeStruct)).ID(s.Id).Cols("name").Get(&name)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "test", name)
var age MyInt
has, err = testEngine.Table(new(TestCustomizeStruct)).ID(s.Id).Select("age").Get(&age)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 32, age)
}

View File

@ -12,6 +12,7 @@ import (
"strconv"
"strings"
"xorm.io/builder"
"xorm.io/core"
)
@ -24,6 +25,12 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) {
defer session.Close()
}
session.autoResetStatement = false
defer func() {
session.autoResetStatement = true
session.resetStatement()
}()
for _, bean := range beans {
switch bean.(type) {
case map[string]interface{}:
@ -34,7 +41,6 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) {
affected += cnt
case []map[string]interface{}:
s := bean.([]map[string]interface{})
session.autoResetStatement = false
for i := 0; i < len(s); i++ {
cnt, err := session.insertMapInterface(s[i])
if err != nil {
@ -50,7 +56,6 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) {
affected += cnt
case []map[string]string:
s := bean.([]map[string]string)
session.autoResetStatement = false
for i := 0; i < len(s); i++ {
cnt, err := session.insertMapString(s[i])
if err != nil {
@ -339,56 +344,96 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
if err != nil {
return 0, err
}
// insert expr columns, override if exists
exprColumns := session.statement.getExpr()
exprColVals := make([]string, 0, len(exprColumns))
for _, v := range exprColumns {
// remove the expr columns
for i, colName := range colNames {
if colName == v.colName {
colNames = append(colNames[:i], colNames[i+1:]...)
args = append(args[:i], args[i+1:]...)
}
}
// append expr column to the end
colNames = append(colNames, v.colName)
exprColVals = append(exprColVals, v.expr)
exprs := session.statement.exprColumns
colPlaces := strings.Repeat("?, ", len(colNames))
if exprs.Len() <= 0 && len(colPlaces) > 0 {
colPlaces = colPlaces[0 : len(colPlaces)-2]
}
colPlaces := strings.Repeat("?, ", len(colNames)-len(exprColumns))
if len(exprColVals) > 0 {
colPlaces = colPlaces + strings.Join(exprColVals, ", ")
} else {
if len(colPlaces) > 0 {
colPlaces = colPlaces[0 : len(colPlaces)-2]
}
}
var sqlStr string
var tableName = session.statement.TableName()
var output string
if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 {
output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement)
}
if len(colPlaces) > 0 {
sqlStr = fmt.Sprintf("INSERT INTO %s (%v)%s VALUES (%v)",
session.engine.Quote(tableName),
quoteColumns(colNames, session.engine.Quote, ","),
output,
colPlaces)
} else {
var buf = builder.NewWriter()
if _, err := buf.WriteString(fmt.Sprintf("INSERT INTO %s", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if len(colPlaces) <= 0 {
if session.engine.dialect.DBType() == core.MYSQL {
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName))
if _, err := buf.WriteString(" VALUES ()"); err != nil {
return 0, err
}
} else {
sqlStr = fmt.Sprintf("INSERT INTO %s%s DEFAULT VALUES", session.engine.Quote(tableName), output)
if _, err := buf.WriteString(fmt.Sprintf("%s DEFAULT VALUES", output)); err != nil {
return 0, err
}
}
} else {
if _, err := buf.WriteString(" ("); err != nil {
return 0, err
}
if err := writeStrings(buf, append(colNames, exprs.colNames...), "`", "`"); err != nil {
return 0, err
}
if session.statement.cond.IsValid() {
if _, err := buf.WriteString(fmt.Sprintf(")%s SELECT ", output)); err != nil {
return 0, err
}
if err := session.statement.writeArgs(buf, args); err != nil {
return 0, err
}
if len(exprs.args) > 0 {
if _, err := buf.WriteString(","); err != nil {
return 0, err
}
}
if err := exprs.writeArgs(buf); err != nil {
return 0, err
}
if _, err := buf.WriteString(fmt.Sprintf(" FROM %v WHERE ", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := session.statement.cond.WriteTo(buf); err != nil {
return 0, err
}
} else {
buf.Append(args...)
if _, err := buf.WriteString(fmt.Sprintf(")%s VALUES (%v",
output,
colPlaces)); err != nil {
return 0, err
}
if err := exprs.writeArgs(buf); err != nil {
return 0, err
}
if _, err := buf.WriteString(")"); err != nil {
return 0, err
}
}
}
if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES {
sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement)
if _, err := buf.WriteString(" RETURNING " + session.engine.Quote(table.AutoIncrement)); err != nil {
return 0, err
}
}
sqlStr := buf.String()
args = buf.Args()
handleAfterInsertProcessorFunc := func(bean interface{}) {
if session.isAutoCommit {
for _, closure := range session.afterClosures {
@ -592,9 +637,11 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
continue
}
if _, ok := session.statement.incrColumns[col.Name]; ok {
if session.statement.incrColumns.isColExist(col.Name) {
continue
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
} else if session.statement.decrColumns.isColExist(col.Name) {
continue
} else if session.statement.exprColumns.isColExist(col.Name) {
continue
}
@ -663,26 +710,72 @@ func (session *Session) insertMapInterface(m map[string]interface{}) (int64, err
return 0, ErrParamsType
}
var columns = make([]string, 0, len(m))
for k := range m {
columns = append(columns, k)
}
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 columns = make([]string, 0, len(m))
exprs := session.statement.exprColumns
for k := range m {
if !exprs.isColExist(k) {
columns = append(columns, k)
}
}
sort.Strings(columns)
var args = make([]interface{}, 0, len(m))
for _, colName := range columns {
args = append(args, m[colName])
}
w := builder.NewWriter()
if session.statement.cond.IsValid() {
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
return 0, err
}
if _, err := w.WriteString(") SELECT "); err != nil {
return 0, err
}
if err := session.statement.writeArgs(w, args); err != nil {
return 0, err
}
if len(exprs.args) > 0 {
if _, err := w.WriteString(","); err != nil {
return 0, err
}
if err := exprs.writeArgs(w); err != nil {
return 0, err
}
}
if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := session.statement.cond.WriteTo(w); err != nil {
return 0, err
}
} else {
qm := strings.Repeat("?,", len(columns))
qm = qm[:len(qm)-1]
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil {
return 0, err
}
w.Append(args...)
}
sql := w.String()
args = w.Args()
if err := session.cacheInsert(tableName); err != nil {
return 0, err
}
@ -703,26 +796,72 @@ func (session *Session) insertMapString(m map[string]string) (int64, error) {
return 0, ErrParamsType
}
var columns = make([]string, 0, len(m))
for k := range m {
columns = append(columns, k)
}
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 columns = make([]string, 0, len(m))
exprs := session.statement.exprColumns
for k := range m {
if !exprs.isColExist(k) {
columns = append(columns, k)
}
}
sort.Strings(columns)
var args = make([]interface{}, 0, len(m))
for _, colName := range columns {
args = append(args, m[colName])
}
w := builder.NewWriter()
if session.statement.cond.IsValid() {
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil {
return 0, err
}
if _, err := w.WriteString(") SELECT "); err != nil {
return 0, err
}
if err := session.statement.writeArgs(w, args); err != nil {
return 0, err
}
if len(exprs.args) > 0 {
if _, err := w.WriteString(","); err != nil {
return 0, err
}
if err := exprs.writeArgs(w); err != nil {
return 0, err
}
}
if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil {
return 0, err
}
if err := session.statement.cond.WriteTo(w); err != nil {
return 0, err
}
} else {
qm := strings.Repeat("?,", len(columns))
qm = qm[:len(qm)-1]
if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil {
return 0, err
}
w.Append(args...)
}
sql := w.String()
args = w.Args()
if err := session.cacheInsert(tableName); err != nil {
return 0, err
}

View File

@ -834,3 +834,193 @@ func TestInsertMap(t *testing.T) {
assert.EqualValues(t, 10, ims[3].Height)
assert.EqualValues(t, "lunny", ims[3].Name)
}
/*INSERT INTO `issue` (`repo_id`, `poster_id`, ... ,`name`, `content`, ... ,`index`)
SELECT $1, $2, ..., $14, $15, ..., MAX(`index`) + 1 FROM `issue` WHERE `repo_id` = $1;
*/
func TestInsertWhere(t *testing.T) {
type InsertWhere struct {
Id int64
Index int `xorm:"unique(s) notnull"`
RepoId int64 `xorm:"unique(s)"`
Width uint32
Height uint32
Name string
IsTrue bool
}
assert.NoError(t, prepareEngine())
assertSync(t, new(InsertWhere))
var i = InsertWhere{
RepoId: 1,
Width: 10,
Height: 20,
Name: "trest",
}
inserted, err := testEngine.SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Where("repo_id=?", 1).
Insert(&i)
assert.NoError(t, err)
assert.EqualValues(t, 1, inserted)
assert.EqualValues(t, 1, i.Id)
var j InsertWhere
has, err := testEngine.ID(i.Id).Get(&j)
assert.NoError(t, err)
assert.True(t, has)
i.Index = 1
assert.EqualValues(t, i, j)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{
"repo_id": 1,
"width": 20,
"height": 40,
"name": "trest2",
})
assert.NoError(t, err)
assert.EqualValues(t, 1, inserted)
var j2 InsertWhere
has, err = testEngine.ID(2).Get(&j2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, j2.RepoId)
assert.EqualValues(t, 20, j2.Width)
assert.EqualValues(t, 40, j2.Height)
assert.EqualValues(t, "trest2", j2.Name)
assert.EqualValues(t, 2, j2.Index)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
SetExpr("repo_id", "1").
Insert(map[string]string{
"name": "trest3",
})
assert.NoError(t, err)
assert.EqualValues(t, 1, inserted)
var j3 InsertWhere
has, err = testEngine.ID(3).Get(&j3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "trest3", j3.Name)
assert.EqualValues(t, 3, j3.Index)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{
"repo_id": 1,
"name": "10';delete * from insert_where; --",
})
assert.NoError(t, err)
assert.EqualValues(t, 1, inserted)
var j4 InsertWhere
has, err = testEngine.ID(4).Get(&j4)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "10';delete * from insert_where; --", j4.Name)
assert.EqualValues(t, 4, j4.Index)
inserted, err = testEngine.Table(new(InsertWhere)).Where("repo_id=?", 1).
SetExpr("`index`", "coalesce(MAX(`index`),0)+1").
Insert(map[string]interface{}{
"repo_id": 1,
"name": "10\\';delete * from insert_where; --",
})
assert.NoError(t, err)
assert.EqualValues(t, 1, inserted)
var j5 InsertWhere
has, err = testEngine.ID(5).Get(&j5)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, "10\\';delete * from insert_where; --", j5.Name)
assert.EqualValues(t, 5, j5.Index)
}
type NightlyRate struct {
ID int64 `xorm:"'id' not null pk BIGINT(20)" json:"id"`
}
func (NightlyRate) TableName() string {
return "prd_nightly_rate"
}
func TestMultipleInsertTableName(t *testing.T) {
assert.NoError(t, prepareEngine())
tableName := `prd_nightly_rate_16`
assert.NoError(t, testEngine.Table(tableName).Sync2(new(NightlyRate)))
trans := testEngine.NewSession()
defer trans.Close()
err := trans.Begin()
assert.NoError(t, err)
rtArr := []interface{}{
[]*NightlyRate{
{ID: 1},
{ID: 2},
},
[]*NightlyRate{
{ID: 3},
{ID: 4},
},
[]*NightlyRate{
{ID: 5},
},
}
_, err = trans.Table(tableName).Insert(rtArr...)
assert.NoError(t, err)
assert.NoError(t, trans.Commit())
}
func TestInsertMultiWithOmit(t *testing.T) {
assert.NoError(t, prepareEngine())
type TestMultiOmit struct {
Id int64 `xorm:"int(11) pk"`
Name string `xorm:"varchar(255)"`
Omitted string `xorm:"varchar(255) 'omitted'"`
}
assert.NoError(t, testEngine.Sync2(new(TestMultiOmit)))
l := []interface{}{
TestMultiOmit{Id: 1, Name: "1", Omitted: "1"},
TestMultiOmit{Id: 2, Name: "1", Omitted: "2"},
TestMultiOmit{Id: 3, Name: "1", Omitted: "3"},
}
check := func() {
var ls []TestMultiOmit
err := testEngine.Find(&ls)
assert.NoError(t, err)
assert.EqualValues(t, 3, len(ls))
for e := range ls {
assert.EqualValues(t, "", ls[e].Omitted)
}
}
num, err := testEngine.Omit("omitted").Insert(l...)
assert.NoError(t, err)
assert.EqualValues(t, 3, num)
check()
num, err = testEngine.Delete(TestMultiOmit{Name: "1"})
assert.NoError(t, err)
assert.EqualValues(t, 3, num)
num, err = testEngine.Omit("omitted").Insert(l)
assert.NoError(t, err)
assert.EqualValues(t, 3, num)
check()
}

View File

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

View File

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

170
statement_args.go Normal file
View File

@ -0,0 +1,170 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
"fmt"
"reflect"
"strings"
"time"
"xorm.io/builder"
"xorm.io/core"
)
func quoteNeeded(a interface{}) bool {
switch a.(type) {
case int, int8, int16, int32, int64:
return false
case uint, uint8, uint16, uint32, uint64:
return false
case float32, float64:
return false
case bool:
return false
case string:
return true
case time.Time, *time.Time:
return true
case builder.Builder, *builder.Builder:
return false
}
t := reflect.TypeOf(a)
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return false
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return false
case reflect.Float32, reflect.Float64:
return false
case reflect.Bool:
return false
case reflect.String:
return true
}
return true
}
func convertStringSingleQuote(arg string) string {
return "'" + strings.Replace(arg, "'", "''", -1) + "'"
}
func convertString(arg string) string {
var buf strings.Builder
buf.WriteRune('\'')
for _, c := range arg {
if c == '\\' || c == '\'' {
buf.WriteRune('\\')
}
buf.WriteRune(c)
}
buf.WriteRune('\'')
return buf.String()
}
func convertArg(arg interface{}, convertFunc func(string) string) string {
if quoteNeeded(arg) {
argv := fmt.Sprintf("%v", arg)
return convertFunc(argv)
}
return fmt.Sprintf("%v", arg)
}
const insertSelectPlaceHolder = true
func (statement *Statement) writeArg(w *builder.BytesWriter, arg interface{}) error {
switch argv := arg.(type) {
case bool:
if statement.Engine.dialect.DBType() == core.MSSQL {
if argv {
if _, err := w.WriteString("1"); err != nil {
return err
}
} else {
if _, err := w.WriteString("0"); err != nil {
return err
}
}
} else {
if argv {
if _, err := w.WriteString("true"); err != nil {
return err
}
} else {
if _, err := w.WriteString("false"); err != nil {
return err
}
}
}
case *builder.Builder:
if _, err := w.WriteString("("); err != nil {
return err
}
if err := argv.WriteTo(w); err != nil {
return err
}
if _, err := w.WriteString(")"); err != nil {
return err
}
default:
if insertSelectPlaceHolder {
if err := w.WriteByte('?'); err != nil {
return err
}
w.Append(arg)
} else {
var convertFunc = convertStringSingleQuote
if statement.Engine.dialect.DBType() == core.MYSQL {
convertFunc = convertString
}
if _, err := w.WriteString(convertArg(arg, convertFunc)); err != nil {
return err
}
}
}
return nil
}
func (statement *Statement) writeArgs(w *builder.BytesWriter, args []interface{}) error {
for i, arg := range args {
if err := statement.writeArg(w, arg); err != nil {
return err
}
if i+1 != len(args) {
if _, err := w.WriteString(","); err != nil {
return err
}
}
}
return nil
}
func writeStrings(w *builder.BytesWriter, cols []string, leftQuote, rightQuote string) error {
for i, colName := range cols {
if len(leftQuote) > 0 && colName[0] != '`' {
if _, err := w.WriteString(leftQuote); err != nil {
return err
}
}
if _, err := w.WriteString(colName); err != nil {
return err
}
if len(rightQuote) > 0 && colName[len(colName)-1] != '`' {
if _, err := w.WriteString(rightQuote); err != nil {
return err
}
}
if i+1 != len(cols) {
if _, err := w.WriteString(","); err != nil {
return err
}
}
}
return nil
}

35
statement_columnmap.go Normal file
View File

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

117
statement_exprparam.go Normal file
View File

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

19
statement_quote.go Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
func trimQuote(s string) string {
if len(s) == 0 {
return s
}
if s[0] == '`' {
s = s[1:]
}
if len(s) > 0 && s[len(s)-1] == '`' {
return s[:len(s)-1]
}
return s
}

1
tag.go
View File

@ -125,6 +125,7 @@ func DefaultTagHandler(ctx *tagContext) error {
ctx.col.Default = ctx.nextTag
ctx.ignoreNext = true
}
ctx.col.DefaultIsEmpty = false
return nil
}

View File

@ -5,7 +5,6 @@
package xorm
import (
"errors"
"fmt"
"strings"
"testing"
@ -27,58 +26,27 @@ func TestCreatedAndUpdated(t *testing.T) {
u := new(UserCU)
err := testEngine.DropTables(u)
if err != nil {
t.Error(err)
panic(err)
}
assert.NoError(t, err)
err = testEngine.CreateTables(u)
if err != nil {
t.Error(err)
panic(err)
}
assert.NoError(t, err)
u.Name = "sss"
cnt, err := testEngine.Insert(u)
if err != nil {
t.Error(err)
panic(err)
}
if cnt != 1 {
err = errors.New("insert not returned 1")
t.Error(err)
panic(err)
return
}
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
u.Name = "xxx"
cnt, err = testEngine.ID(u.Id).Update(u)
if err != nil {
t.Error(err)
panic(err)
}
if cnt != 1 {
err = errors.New("update not returned 1")
t.Error(err)
panic(err)
return
}
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
u.Id = 0
u.Created = time.Now().Add(-time.Hour * 24 * 365)
u.Updated = u.Created
fmt.Println(u)
cnt, err = testEngine.NoAutoTime().Insert(u)
if err != nil {
t.Error(err)
panic(err)
}
if cnt != 1 {
err = errors.New("insert not returned 1")
t.Error(err)
panic(err)
return
}
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
}
type StrangeName struct {
@ -90,25 +58,17 @@ func TestStrangeName(t *testing.T) {
assert.NoError(t, prepareEngine())
err := testEngine.DropTables(new(StrangeName))
if err != nil {
t.Error(err)
}
assert.NoError(t, err)
err = testEngine.CreateTables(new(StrangeName))
if err != nil {
t.Error(err)
}
assert.NoError(t, err)
_, err = testEngine.Insert(&StrangeName{Name: "sfsfdsfds"})
if err != nil {
t.Error(err)
}
assert.NoError(t, err)
beans := make([]StrangeName, 0)
err = testEngine.Find(&beans)
if err != nil {
t.Error(err)
}
assert.NoError(t, err)
}
func TestCreatedUpdated(t *testing.T) {
@ -179,29 +139,17 @@ func TestLowerCase(t *testing.T) {
assert.NoError(t, prepareEngine())
err := testEngine.Sync2(&Lowercase{})
_, err = testEngine.Where("(id) > 0").Delete(&Lowercase{})
if err != nil {
t.Error(err)
panic(err)
}
assert.NoError(t, err)
_, err = testEngine.Where("id > 0").Delete(&Lowercase{})
assert.NoError(t, err)
_, err = testEngine.Insert(&Lowercase{ended: 1})
if err != nil {
t.Error(err)
panic(err)
}
assert.NoError(t, err)
ls := make([]Lowercase, 0)
err = testEngine.Find(&ls)
if err != nil {
t.Error(err)
panic(err)
}
if len(ls) != 1 {
err = errors.New("should be 1")
t.Error(err)
panic(err)
}
assert.NoError(t, err)
assert.EqualValues(t, 1, len(ls))
}
func TestAutoIncrTag(t *testing.T) {
@ -297,6 +245,24 @@ func TestTagDefault(t *testing.T) {
assertSync(t, new(DefaultStruct))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
var defaultVal string
var isDefaultExist bool
tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct")
for _, table := range tables {
if table.Name == tableName {
col := table.GetColumn("age")
assert.NotNil(t, col)
defaultVal = col.Default
isDefaultExist = !col.DefaultIsEmpty
break
}
}
assert.True(t, isDefaultExist)
assert.EqualValues(t, "10", defaultVal)
cnt, err := testEngine.Omit("age").Insert(&DefaultStruct{
Name: "test",
Age: 20,
@ -312,6 +278,163 @@ func TestTagDefault(t *testing.T) {
assert.EqualValues(t, "test", s.Name)
}
func TestTagDefault2(t *testing.T) {
assert.NoError(t, prepareEngine())
type DefaultStruct2 struct {
Id int64
Name string
}
assertSync(t, new(DefaultStruct2))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
var defaultVal string
var isDefaultExist bool
tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct2")
for _, table := range tables {
if table.Name == tableName {
col := table.GetColumn("name")
assert.NotNil(t, col)
defaultVal = col.Default
isDefaultExist = !col.DefaultIsEmpty
break
}
}
assert.False(t, isDefaultExist, fmt.Sprintf("default value is --%v--", defaultVal))
assert.EqualValues(t, "", defaultVal)
}
func TestTagDefault3(t *testing.T) {
assert.NoError(t, prepareEngine())
type DefaultStruct3 struct {
Id int64
Name string `xorm:"default('myname')"`
}
assertSync(t, new(DefaultStruct3))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
var defaultVal string
var isDefaultExist bool
tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct3")
for _, table := range tables {
if table.Name == tableName {
col := table.GetColumn("name")
assert.NotNil(t, col)
defaultVal = col.Default
isDefaultExist = !col.DefaultIsEmpty
break
}
}
assert.True(t, isDefaultExist)
assert.EqualValues(t, "'myname'", defaultVal)
}
func TestTagDefault4(t *testing.T) {
assert.NoError(t, prepareEngine())
type DefaultStruct4 struct {
Id int64
Created time.Time `xorm:"default(CURRENT_TIMESTAMP)"`
}
assertSync(t, new(DefaultStruct4))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
var defaultVal string
var isDefaultExist bool
tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct4")
for _, table := range tables {
if table.Name == tableName {
col := table.GetColumn("created")
assert.NotNil(t, col)
defaultVal = col.Default
isDefaultExist = !col.DefaultIsEmpty
break
}
}
assert.True(t, isDefaultExist)
assert.True(t, "CURRENT_TIMESTAMP" == defaultVal ||
"now()" == defaultVal ||
"getdate" == defaultVal, defaultVal)
}
func TestTagDefault5(t *testing.T) {
assert.NoError(t, prepareEngine())
type DefaultStruct5 struct {
Id int64
Created time.Time `xorm:"default('2006-01-02 15:04:05')"`
}
assertSync(t, new(DefaultStruct5))
table := testEngine.TableInfo(new(DefaultStruct5))
createdCol := table.GetColumn("created")
assert.NotNil(t, createdCol)
assert.EqualValues(t, "'2006-01-02 15:04:05'", createdCol.Default)
assert.False(t, createdCol.DefaultIsEmpty)
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
var defaultVal string
var isDefaultExist bool
tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct5")
for _, table := range tables {
if table.Name == tableName {
col := table.GetColumn("created")
assert.NotNil(t, col)
defaultVal = col.Default
isDefaultExist = !col.DefaultIsEmpty
break
}
}
assert.True(t, isDefaultExist)
assert.EqualValues(t, "'2006-01-02 15:04:05'", defaultVal)
}
func TestTagDefault6(t *testing.T) {
assert.NoError(t, prepareEngine())
type DefaultStruct6 struct {
Id int64
IsMan bool `xorm:"default(true)"`
}
assertSync(t, new(DefaultStruct6))
tables, err := testEngine.DBMetas()
assert.NoError(t, err)
var defaultVal string
var isDefaultExist bool
tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct6")
for _, table := range tables {
if table.Name == tableName {
col := table.GetColumn("is_man")
assert.NotNil(t, col)
defaultVal = col.Default
isDefaultExist = !col.DefaultIsEmpty
break
}
}
assert.True(t, isDefaultExist)
if defaultVal == "1" {
defaultVal = "true"
} else if defaultVal == "0" {
defaultVal = "false"
}
assert.EqualValues(t, "true", defaultVal)
}
func TestTagsDirection(t *testing.T) {
assert.NoError(t, prepareEngine())
@ -407,3 +530,22 @@ func TestTagTime(t *testing.T) {
assert.EqualValues(t, s.Created.UTC().Format("2006-01-02 15:04:05"),
strings.Replace(strings.Replace(tm, "T", " ", -1), "Z", "", -1))
}
func TestSplitTag(t *testing.T) {
var cases = []struct {
tag string
tags []string
}{
{"not null default '2000-01-01 00:00:00' TIMESTAMP", []string{"not", "null", "default", "'2000-01-01 00:00:00'", "TIMESTAMP"}},
{"TEXT", []string{"TEXT"}},
{"default('2000-01-01 00:00:00')", []string{"default('2000-01-01 00:00:00')"}},
{"json binary", []string{"json", "binary"}},
}
for _, kase := range cases {
tags := splitTag(kase.tag)
if !sliceEq(tags, kase.tags) {
t.Fatalf("[%d]%v is not equal [%d]%v", len(tags), tags, len(kase.tags), kase.tags)
}
}
}