mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 00:20:25 +08:00 
			
		
		
		
	Upgrade xorm to v0.8.0 (#8536)
This commit is contained in:
		
				
					committed by
					
						
						Antoine GIRARD
					
				
			
			
				
	
			
			
			
						parent
						
							ae132632a9
						
					
				
				
					commit
					d151503d34
				
			
							
								
								
									
										771
									
								
								vendor/xorm.io/xorm/.drone.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										771
									
								
								vendor/xorm.io/xorm/.drone.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,771 @@
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
name: matrix-1
 | 
			
		||||
 | 
			
		||||
platform:
 | 
			
		||||
  os: linux
 | 
			
		||||
  arch: amd64
 | 
			
		||||
 | 
			
		||||
workspace:
 | 
			
		||||
  base: /go
 | 
			
		||||
  path: src/gitea.com/xorm/xorm
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
- 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"
 | 
			
		||||
  when:
 | 
			
		||||
    event:
 | 
			
		||||
    - push
 | 
			
		||||
    - pull_request
 | 
			
		||||
 | 
			
		||||
- name: test-tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: golang:1.10
 | 
			
		||||
  commands:
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic"
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-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 coverage7-1.txt coverage7-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: tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: pingcap/tidb:v3.0.3
 | 
			
		||||
  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-2
 | 
			
		||||
 | 
			
		||||
platform:
 | 
			
		||||
  os: linux
 | 
			
		||||
  arch: amd64
 | 
			
		||||
 | 
			
		||||
workspace:
 | 
			
		||||
  base: /go
 | 
			
		||||
  path: src/gitea.com/xorm/xorm
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
- name: build
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: golang:1.11
 | 
			
		||||
  environment:
 | 
			
		||||
    GO111MODULE: "off"
 | 
			
		||||
  commands:
 | 
			
		||||
    - go get -t -d -v ./...	
 | 
			
		||||
    - go get -u xorm.io/core	
 | 
			
		||||
    - go get -u xorm.io/builder
 | 
			
		||||
    - go build -v
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
- 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"
 | 
			
		||||
 | 
			
		||||
  when:
 | 
			
		||||
    event:
 | 
			
		||||
    - push
 | 
			
		||||
    - pull_request
 | 
			
		||||
 | 
			
		||||
- name: test-tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: golang:1.11
 | 
			
		||||
  environment:
 | 
			
		||||
    GO111MODULE: "on"
 | 
			
		||||
    GOPROXY: "https://goproxy.cn"
 | 
			
		||||
  commands:
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic"
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-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 coverage7-1.txt coverage7-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: tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: pingcap/tidb:v3.0.3
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
workspace:
 | 
			
		||||
  base: /go
 | 
			
		||||
  path: src/gitea.com/xorm/xorm
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
 | 
			
		||||
- name: build
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: golang:1.12
 | 
			
		||||
  environment:
 | 
			
		||||
    GO111MODULE: "off"
 | 
			
		||||
  commands:
 | 
			
		||||
    - go get -t -d -v ./...	
 | 
			
		||||
    - go get -u xorm.io/core	
 | 
			
		||||
    - go get -u xorm.io/builder
 | 
			
		||||
    - 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"
 | 
			
		||||
  when:
 | 
			
		||||
    event:
 | 
			
		||||
    - push
 | 
			
		||||
    - pull_request
 | 
			
		||||
 | 
			
		||||
- name: test-tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: golang:1.12
 | 
			
		||||
  environment:
 | 
			
		||||
    GO111MODULE: "on"
 | 
			
		||||
    GOPROXY: "https://goproxy.cn"
 | 
			
		||||
  commands:
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic"
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-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 coverage7-1.txt coverage7-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: tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: pingcap/tidb:v3.0.3
 | 
			
		||||
  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
 | 
			
		||||
 | 
			
		||||
workspace:
 | 
			
		||||
  base: /go
 | 
			
		||||
  path: src/gitea.com/xorm/xorm
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
 | 
			
		||||
- 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"
 | 
			
		||||
  when:
 | 
			
		||||
    event:
 | 
			
		||||
    - push
 | 
			
		||||
    - pull_request
 | 
			
		||||
 | 
			
		||||
- name: test-tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: golang:1.13
 | 
			
		||||
  environment:
 | 
			
		||||
    GO111MODULE: "on"
 | 
			
		||||
    GOPROXY: "https://goproxy.cn"
 | 
			
		||||
  commands:
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic"
 | 
			
		||||
  - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-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 coverage7-1.txt coverage7-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: tidb
 | 
			
		||||
  pull: default
 | 
			
		||||
  image: pingcap/tidb:v3.0.3
 | 
			
		||||
  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
 | 
			
		||||
							
								
								
									
										33
									
								
								vendor/xorm.io/xorm/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/xorm.io/xorm/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
 | 
			
		||||
*.o
 | 
			
		||||
*.a
 | 
			
		||||
*.so
 | 
			
		||||
*.db
 | 
			
		||||
 | 
			
		||||
# Folders
 | 
			
		||||
_obj
 | 
			
		||||
_test
 | 
			
		||||
 | 
			
		||||
# Architecture specific extensions/prefixes
 | 
			
		||||
*.[568vq]
 | 
			
		||||
[568vq].out
 | 
			
		||||
 | 
			
		||||
*.cgo1.go
 | 
			
		||||
*.cgo2.c
 | 
			
		||||
_cgo_defun.c
 | 
			
		||||
_cgo_gotypes.go
 | 
			
		||||
_cgo_export.*
 | 
			
		||||
 | 
			
		||||
_testmain.go
 | 
			
		||||
 | 
			
		||||
*.exe
 | 
			
		||||
 | 
			
		||||
*.log
 | 
			
		||||
.vendor
 | 
			
		||||
temp_test.go
 | 
			
		||||
.vscode
 | 
			
		||||
xorm.test
 | 
			
		||||
*.sqlite3
 | 
			
		||||
test.db.sql
 | 
			
		||||
 | 
			
		||||
.idea/
 | 
			
		||||
							
								
								
									
										46
									
								
								vendor/xorm.io/xorm/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								vendor/xorm.io/xorm/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
## Contributing to xorm
 | 
			
		||||
 | 
			
		||||
`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very
 | 
			
		||||
much welcome. You can help with patch review, submitting bug reports,
 | 
			
		||||
or adding new functionality. There is no formal style guide, but
 | 
			
		||||
please conform to the style of existing code and general Go formatting
 | 
			
		||||
conventions when submitting patches.
 | 
			
		||||
 | 
			
		||||
* [fork a repo](https://help.github.com/articles/fork-a-repo)
 | 
			
		||||
* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request)
 | 
			
		||||
 | 
			
		||||
### Language
 | 
			
		||||
 | 
			
		||||
Since `xorm` is a world-wide open source project, please describe your issues or code changes in English as soon as possible.
 | 
			
		||||
 | 
			
		||||
### Sign your codes with comments
 | 
			
		||||
```
 | 
			
		||||
// !<you github id>! your comments
 | 
			
		||||
 | 
			
		||||
e.g.,
 | 
			
		||||
 | 
			
		||||
// !lunny! this is comments made by lunny
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Patch review
 | 
			
		||||
 | 
			
		||||
Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or
 | 
			
		||||
proposed functionality.
 | 
			
		||||
 | 
			
		||||
### Bug reports
 | 
			
		||||
 | 
			
		||||
We appreciate any bug reports, but especially ones with self-contained
 | 
			
		||||
(doesn't depend on code outside of xorm), minimal (can't be simplified
 | 
			
		||||
further) test cases. It's especially helpful if you can submit a pull
 | 
			
		||||
request with just the failing test case(you can find some example test file like [session_get_test.go](https://gitea.com/xorm/xorm/src/branch/master/session_get_test.go)).
 | 
			
		||||
 | 
			
		||||
If you implements a new database interface, you maybe need to add a test_<databasename>.sh file.
 | 
			
		||||
For example, [mysql_test.go](https://gitea.com/xorm/xorm/src/branch/master/test_mysql.sh)
 | 
			
		||||
 | 
			
		||||
### New functionality
 | 
			
		||||
 | 
			
		||||
There are a number of pending patches for new functionality, so
 | 
			
		||||
additional feature patches will take a while to merge. Still, patches
 | 
			
		||||
are generally reviewed based on usefulness and complexity in addition
 | 
			
		||||
to time-in-queue, so if you have a knockout idea, take a shot. Feel
 | 
			
		||||
free to open an issue discussion your proposed patch beforehand.
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/xorm.io/xorm/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/xorm.io/xorm/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
Copyright (c) 2013 - 2015 The Xorm Authors
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
* Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
  list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
* Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
  this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
  and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
* Neither the name of the {organization} nor the names of its
 | 
			
		||||
  contributors may be used to endorse or promote products derived from
 | 
			
		||||
  this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
			
		||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
			
		||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										503
									
								
								vendor/xorm.io/xorm/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								vendor/xorm.io/xorm/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,503 @@
 | 
			
		||||
# xorm
 | 
			
		||||
 | 
			
		||||
[中文](https://gitea.com/xorm/xorm/src/branch/master/README_CN.md)
 | 
			
		||||
 | 
			
		||||
Xorm is a simple and powerful ORM for Go.
 | 
			
		||||
 | 
			
		||||
[](https://drone.gitea.com/xorm/xorm) [](https://gocover.io/xorm.io/xorm)
 | 
			
		||||
[](https://goreportcard.com/report/xorm.io/xorm)
 | 
			
		||||
[](https://discord.gg/HuR2CF3)
 | 
			
		||||
 | 
			
		||||
## Features
 | 
			
		||||
 | 
			
		||||
* Struct <-> Table Mapping Support
 | 
			
		||||
 | 
			
		||||
* Chainable APIs
 | 
			
		||||
 | 
			
		||||
* Transaction Support
 | 
			
		||||
 | 
			
		||||
* Both ORM and raw SQL operation Support
 | 
			
		||||
 | 
			
		||||
* Sync database schema Support
 | 
			
		||||
 | 
			
		||||
* Query Cache speed up
 | 
			
		||||
 | 
			
		||||
* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/cmd/blob/master/README.md)
 | 
			
		||||
 | 
			
		||||
* Simple cascade loading support
 | 
			
		||||
 | 
			
		||||
* Optimistic Locking support
 | 
			
		||||
 | 
			
		||||
* SQL Builder support via [xorm.io/builder](https://xorm.io/builder)
 | 
			
		||||
 | 
			
		||||
* Automatical Read/Write seperatelly
 | 
			
		||||
 | 
			
		||||
* Postgres schema support
 | 
			
		||||
 | 
			
		||||
* Context Cache support
 | 
			
		||||
 | 
			
		||||
## Drivers Support
 | 
			
		||||
 | 
			
		||||
Drivers for Go's sql package which currently support database/sql includes:
 | 
			
		||||
 | 
			
		||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
 | 
			
		||||
 | 
			
		||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/tree/master/godrv)
 | 
			
		||||
 | 
			
		||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
 | 
			
		||||
 | 
			
		||||
* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
 | 
			
		||||
 | 
			
		||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
 | 
			
		||||
 | 
			
		||||
* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 | 
			
		||||
 | 
			
		||||
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
	go get xorm.io/xorm
 | 
			
		||||
 | 
			
		||||
## Documents
 | 
			
		||||
 | 
			
		||||
* [Manual](http://xorm.io/docs)
 | 
			
		||||
 | 
			
		||||
* [GoDoc](http://godoc.org/xorm.io/xorm)
 | 
			
		||||
 | 
			
		||||
## Quick Start
 | 
			
		||||
 | 
			
		||||
* Create Engine
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
engine, err := xorm.NewEngine(driverName, dataSourceName)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Define a struct and Sync2 table struct to database
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
type User struct {
 | 
			
		||||
    Id int64
 | 
			
		||||
    Name string
 | 
			
		||||
    Salt string
 | 
			
		||||
    Age int
 | 
			
		||||
    Passwd string `xorm:"varchar(200)"`
 | 
			
		||||
    Created time.Time `xorm:"created"`
 | 
			
		||||
    Updated time.Time `xorm:"updated"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
err := engine.Sync2(new(User))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Create Engine Group
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
 | 
			
		||||
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
 | 
			
		||||
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
 | 
			
		||||
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
 | 
			
		||||
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then all place where `engine` you can just use `engineGroup`.
 | 
			
		||||
 | 
			
		||||
* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`, `QueryInterface` returns `[]map[string]interface{}`.
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
results, err := engine.Query("select * from user")
 | 
			
		||||
results, err := engine.Where("a = 1").Query()
 | 
			
		||||
 | 
			
		||||
results, err := engine.QueryString("select * from user")
 | 
			
		||||
results, err := engine.Where("a = 1").QueryString()
 | 
			
		||||
 | 
			
		||||
results, err := engine.QueryInterface("select * from user")
 | 
			
		||||
results, err := engine.Where("a = 1").QueryInterface()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Exec` runs a SQL string, it returns `affected` and `error`
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Insert` one or multiple records to database
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.Insert(&user)
 | 
			
		||||
// INSERT INTO struct () values ()
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Insert(&user1, &user2)
 | 
			
		||||
// INSERT INTO struct1 () values ()
 | 
			
		||||
// INSERT INTO struct2 () values ()
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Insert(&users)
 | 
			
		||||
// INSERT INTO struct () values (),(),()
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Insert(&user1, &users)
 | 
			
		||||
// INSERT INTO struct1 () values ()
 | 
			
		||||
// INSERT INTO struct2 () values (),(),()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Get` query one record from database
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
has, err := engine.Get(&user)
 | 
			
		||||
// SELECT * FROM user LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
 | 
			
		||||
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
 | 
			
		||||
 | 
			
		||||
var name string
 | 
			
		||||
has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name)
 | 
			
		||||
// SELECT name FROM user WHERE id = ?
 | 
			
		||||
 | 
			
		||||
var id int64
 | 
			
		||||
has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id)
 | 
			
		||||
has, err := engine.SQL("select id from user").Get(&id)
 | 
			
		||||
// SELECT id FROM user WHERE name = ?
 | 
			
		||||
 | 
			
		||||
var valuesMap = make(map[string]string)
 | 
			
		||||
has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
 | 
			
		||||
// SELECT * FROM user WHERE id = ?
 | 
			
		||||
 | 
			
		||||
var valuesSlice = make([]interface{}, len(cols))
 | 
			
		||||
has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
 | 
			
		||||
// SELECT col1, col2, col3 FROM user WHERE id = ?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Exist` check if one record exist on table
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
has, err := testEngine.Exist(new(RecordExist))
 | 
			
		||||
// SELECT * FROM record_exist LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Exist(&RecordExist{
 | 
			
		||||
		Name: "test1",
 | 
			
		||||
	})
 | 
			
		||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
 | 
			
		||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
 | 
			
		||||
// select * from record_exist where name = ?
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Table("record_exist").Exist()
 | 
			
		||||
// SELECT * FROM record_exist LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
 | 
			
		||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Find` query multiple records from database, also you can use join and extends
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
var users []User
 | 
			
		||||
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
 | 
			
		||||
// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
 | 
			
		||||
 | 
			
		||||
type Detail struct {
 | 
			
		||||
    Id int64
 | 
			
		||||
    UserId int64 `xorm:"index"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserDetail struct {
 | 
			
		||||
    User `xorm:"extends"`
 | 
			
		||||
    Detail `xorm:"extends"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var users []UserDetail
 | 
			
		||||
err := engine.Table("user").Select("user.*, detail.*").
 | 
			
		||||
    Join("INNER", "detail", "detail.user_id = user.id").
 | 
			
		||||
    Where("user.name = ?", name).Limit(10, 0).
 | 
			
		||||
    Find(&users)
 | 
			
		||||
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Iterate` and `Rows` query multiple records and record by record handle, there are two methods Iterate and Rows
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
 | 
			
		||||
    user := bean.(*User)
 | 
			
		||||
    return nil
 | 
			
		||||
})
 | 
			
		||||
// SELECT * FROM user
 | 
			
		||||
 | 
			
		||||
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
 | 
			
		||||
    user := bean.(*User)
 | 
			
		||||
    return nil
 | 
			
		||||
})
 | 
			
		||||
// SELECT * FROM user Limit 0, 100
 | 
			
		||||
// SELECT * FROM user Limit 101, 100
 | 
			
		||||
 | 
			
		||||
rows, err := engine.Rows(&User{Name:name})
 | 
			
		||||
// SELECT * FROM user
 | 
			
		||||
defer rows.Close()
 | 
			
		||||
bean := new(Struct)
 | 
			
		||||
for rows.Next() {
 | 
			
		||||
    err = rows.Scan(bean)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Update` update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.ID(1).Update(&user)
 | 
			
		||||
// UPDATE user SET ... Where id = ?
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Update(&user, &User{Name:name})
 | 
			
		||||
// UPDATE user SET ... Where name = ?
 | 
			
		||||
 | 
			
		||||
var ids = []int64{1, 2, 3}
 | 
			
		||||
affected, err := engine.In("id", ids).Update(&user)
 | 
			
		||||
// UPDATE user SET ... Where id IN (?, ?, ?)
 | 
			
		||||
 | 
			
		||||
// force update indicated columns by Cols
 | 
			
		||||
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
 | 
			
		||||
// UPDATE user SET age = ?, updated=? Where id = ?
 | 
			
		||||
 | 
			
		||||
// force NOT update indicated columns by Omit
 | 
			
		||||
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
 | 
			
		||||
// UPDATE user SET age = ?, updated=? Where id = ?
 | 
			
		||||
 | 
			
		||||
affected, err := engine.ID(1).AllCols().Update(&user)
 | 
			
		||||
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Delete` delete one or more records, Delete MUST have condition
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.Where(...).Delete(&user)
 | 
			
		||||
// DELETE FROM user Where ...
 | 
			
		||||
 | 
			
		||||
affected, err := engine.ID(2).Delete(&user)
 | 
			
		||||
// DELETE FROM user Where id = ?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Count` count records
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
counts, err := engine.Count(&user)
 | 
			
		||||
// SELECT count(*) AS total FROM user
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `FindAndCount` combines function `Find` with `Count` which is usually used in query by page
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
var users []User
 | 
			
		||||
counts, err := engine.FindAndCount(&users)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Sum` sum functions
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
agesFloat64, err := engine.Sum(&user, "age")
 | 
			
		||||
// SELECT sum(age) AS total FROM user
 | 
			
		||||
 | 
			
		||||
agesInt64, err := engine.SumInt(&user, "age")
 | 
			
		||||
// SELECT sum(age) AS total FROM user
 | 
			
		||||
 | 
			
		||||
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
 | 
			
		||||
// SELECT sum(age), sum(score) FROM user
 | 
			
		||||
 | 
			
		||||
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
 | 
			
		||||
// SELECT sum(age), sum(score) FROM user
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Query conditions builder
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users)
 | 
			
		||||
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Multiple operations in one go routine, no transation here but resue session memory
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
session := engine.NewSession()
 | 
			
		||||
defer session.Close()
 | 
			
		||||
 | 
			
		||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
 | 
			
		||||
if _, err := session.Insert(&user1); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
user2 := Userinfo{Username: "yyy"}
 | 
			
		||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
return nil
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Transation should be on one go routine. There is transaction and resue session memory
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
session := engine.NewSession()
 | 
			
		||||
defer session.Close()
 | 
			
		||||
 | 
			
		||||
// add Begin() before any action
 | 
			
		||||
if err := session.Begin(); err != nil {
 | 
			
		||||
    // if returned then will rollback automatically
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
 | 
			
		||||
if _, err := session.Insert(&user1); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
user2 := Userinfo{Username: "yyy"}
 | 
			
		||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// add Commit() after all actions
 | 
			
		||||
return session.Commit()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Or you can use `Transaction` to replace above codes.
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) {
 | 
			
		||||
    user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
 | 
			
		||||
    if _, err := session.Insert(&user1); err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    user2 := Userinfo{Username: "yyy"}
 | 
			
		||||
    if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
    return nil, nil
 | 
			
		||||
})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
	sess := engine.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
 | 
			
		||||
	var context = xorm.NewMemoryContextCache()
 | 
			
		||||
 | 
			
		||||
	var c2 ContextGetStruct
 | 
			
		||||
	has, err := sess.ID(1).ContextCache(context).Get(&c2)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, has)
 | 
			
		||||
	assert.EqualValues(t, 1, c2.Id)
 | 
			
		||||
	assert.EqualValues(t, "1", c2.Name)
 | 
			
		||||
	sql, args := sess.LastSQL()
 | 
			
		||||
	assert.True(t, len(sql) > 0)
 | 
			
		||||
	assert.True(t, len(args) > 0)
 | 
			
		||||
 | 
			
		||||
	var c3 ContextGetStruct
 | 
			
		||||
	has, err = sess.ID(1).ContextCache(context).Get(&c3)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, has)
 | 
			
		||||
	assert.EqualValues(t, 1, c3.Id)
 | 
			
		||||
	assert.EqualValues(t, "1", c3.Name)
 | 
			
		||||
	sql, args = sess.LastSQL()
 | 
			
		||||
	assert.True(t, len(sql) == 0)
 | 
			
		||||
	assert.True(t, len(args) == 0)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
If you want to pull request, please see [CONTRIBUTING](https://gitea.com/xorm/xorm/src/branch/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss.
 | 
			
		||||
 | 
			
		||||
## Credits
 | 
			
		||||
 | 
			
		||||
### Contributors
 | 
			
		||||
 | 
			
		||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
 | 
			
		||||
<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
 | 
			
		||||
 | 
			
		||||
### Backers
 | 
			
		||||
 | 
			
		||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/xorm#backer)]
 | 
			
		||||
 | 
			
		||||
<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
 | 
			
		||||
 | 
			
		||||
### Sponsors
 | 
			
		||||
 | 
			
		||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/xorm#sponsor)]
 | 
			
		||||
 | 
			
		||||
## Changelog
 | 
			
		||||
 | 
			
		||||
* **v0.7.0**
 | 
			
		||||
    * Some bugs fixed
 | 
			
		||||
 | 
			
		||||
* **v0.6.6**
 | 
			
		||||
    * Some bugs fixed
 | 
			
		||||
 | 
			
		||||
* **v0.6.5**
 | 
			
		||||
    * Postgres schema support
 | 
			
		||||
    * vgo support
 | 
			
		||||
    * Add FindAndCount
 | 
			
		||||
    * Database special params support via NewEngineWithParams
 | 
			
		||||
    * Some bugs fixed
 | 
			
		||||
 | 
			
		||||
* **v0.6.4**
 | 
			
		||||
    * Automatical Read/Write seperatelly
 | 
			
		||||
    * Query/QueryString/QueryInterface and action with Where/And
 | 
			
		||||
    * Get support non-struct variables
 | 
			
		||||
    * BufferSize on Iterate
 | 
			
		||||
    * fix some other bugs.
 | 
			
		||||
 | 
			
		||||
[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
 | 
			
		||||
 | 
			
		||||
## Cases
 | 
			
		||||
 | 
			
		||||
* [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
 | 
			
		||||
 | 
			
		||||
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
 | 
			
		||||
 | 
			
		||||
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
 | 
			
		||||
 | 
			
		||||
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
 | 
			
		||||
 | 
			
		||||
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
 | 
			
		||||
 | 
			
		||||
* [Wego](http://github.com/go-tango/wego)
 | 
			
		||||
 | 
			
		||||
* [Docker.cn](https://docker.cn/)
 | 
			
		||||
 | 
			
		||||
* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
 | 
			
		||||
 | 
			
		||||
* [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel)
 | 
			
		||||
 | 
			
		||||
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
 | 
			
		||||
 | 
			
		||||
* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
 | 
			
		||||
 | 
			
		||||
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
 | 
			
		||||
 | 
			
		||||
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
 | 
			
		||||
 | 
			
		||||
* [YouGam](http://www.yougam.com/)
 | 
			
		||||
 | 
			
		||||
* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
 | 
			
		||||
 | 
			
		||||
* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/)
 | 
			
		||||
 | 
			
		||||
* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
 | 
			
		||||
 | 
			
		||||
## LICENSE
 | 
			
		||||
 | 
			
		||||
BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
 | 
			
		||||
							
								
								
									
										498
									
								
								vendor/xorm.io/xorm/README_CN.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										498
									
								
								vendor/xorm.io/xorm/README_CN.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,498 @@
 | 
			
		||||
# xorm
 | 
			
		||||
 | 
			
		||||
[English](https://gitea.com/xorm/xorm/src/branch/master/README.md)
 | 
			
		||||
 | 
			
		||||
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
 | 
			
		||||
 | 
			
		||||
[](https://drone.gitea.com/xorm/builder) [](https://gocover.io/xorm.io/xorm)
 | 
			
		||||
[](https://goreportcard.com/report/xorm.io/xorm)
 | 
			
		||||
[](https://discord.gg/HuR2CF3)
 | 
			
		||||
 | 
			
		||||
## 特性
 | 
			
		||||
 | 
			
		||||
* 支持Struct和数据库表之间的灵活映射,并支持自动同步
 | 
			
		||||
 | 
			
		||||
* 事务支持
 | 
			
		||||
 | 
			
		||||
* 同时支持原始SQL语句和ORM操作的混合执行
 | 
			
		||||
 | 
			
		||||
* 使用连写来简化调用
 | 
			
		||||
 | 
			
		||||
* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
 | 
			
		||||
 | 
			
		||||
* 支持级联加载Struct
 | 
			
		||||
 | 
			
		||||
* Schema支持(仅Postgres)
 | 
			
		||||
 | 
			
		||||
* 支持缓存
 | 
			
		||||
 | 
			
		||||
* 支持根据数据库自动生成xorm的结构体
 | 
			
		||||
 | 
			
		||||
* 支持记录版本(即乐观锁)
 | 
			
		||||
 | 
			
		||||
* 内置SQL Builder支持
 | 
			
		||||
 | 
			
		||||
* 上下文缓存支持
 | 
			
		||||
 | 
			
		||||
## 驱动支持
 | 
			
		||||
 | 
			
		||||
目前支持的Go数据库驱动和对应的数据库如下:
 | 
			
		||||
 | 
			
		||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
 | 
			
		||||
 | 
			
		||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
 | 
			
		||||
 | 
			
		||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
 | 
			
		||||
 | 
			
		||||
* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
 | 
			
		||||
 | 
			
		||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
 | 
			
		||||
 | 
			
		||||
* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
 | 
			
		||||
 | 
			
		||||
* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
 | 
			
		||||
 | 
			
		||||
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
 | 
			
		||||
 | 
			
		||||
## 安装
 | 
			
		||||
 | 
			
		||||
	go get xorm.io/xorm
 | 
			
		||||
 | 
			
		||||
## 文档
 | 
			
		||||
 | 
			
		||||
* [操作指南](http://xorm.io/docs)
 | 
			
		||||
 | 
			
		||||
* [Godoc代码文档](http://godoc.org/xorm.io/xorm)
 | 
			
		||||
 | 
			
		||||
# 快速开始
 | 
			
		||||
 | 
			
		||||
* 第一步创建引擎,driverName, dataSourceName和database/sql接口相同
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
engine, err := xorm.NewEngine(driverName, dataSourceName)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* 定义一个和表同步的结构体,并且自动同步结构体到数据库
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
type User struct {
 | 
			
		||||
    Id int64
 | 
			
		||||
    Name string
 | 
			
		||||
    Salt string
 | 
			
		||||
    Age int
 | 
			
		||||
    Passwd string `xorm:"varchar(200)"`
 | 
			
		||||
    Created time.Time `xorm:"created"`
 | 
			
		||||
    Updated time.Time `xorm:"updated"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
err := engine.Sync2(new(User))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* 创建Engine组
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
 | 
			
		||||
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
 | 
			
		||||
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
 | 
			
		||||
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
 | 
			
		||||
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
所有使用 `engine` 都可以简单的用 `engineGroup` 来替换。
 | 
			
		||||
 | 
			
		||||
* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string, `QueryInterface` 返回 `[]map[string]interface{}`.
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
results, err := engine.Query("select * from user")
 | 
			
		||||
results, err := engine.Where("a = 1").Query()
 | 
			
		||||
 | 
			
		||||
results, err := engine.QueryString("select * from user")
 | 
			
		||||
results, err := engine.Where("a = 1").QueryString()
 | 
			
		||||
 | 
			
		||||
results, err := engine.QueryInterface("select * from user")
 | 
			
		||||
results, err := engine.Where("a = 1").QueryInterface()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Exec` 执行一个SQL语句
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Insert` 插入一条或者多条记录
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.Insert(&user)
 | 
			
		||||
// INSERT INTO struct () values ()
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Insert(&user1, &user2)
 | 
			
		||||
// INSERT INTO struct1 () values ()
 | 
			
		||||
// INSERT INTO struct2 () values ()
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Insert(&users)
 | 
			
		||||
// INSERT INTO struct () values (),(),()
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Insert(&user1, &users)
 | 
			
		||||
// INSERT INTO struct1 () values ()
 | 
			
		||||
// INSERT INTO struct2 () values (),(),()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Get` 查询单条记录
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
has, err := engine.Get(&user)
 | 
			
		||||
// SELECT * FROM user LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
 | 
			
		||||
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
 | 
			
		||||
 | 
			
		||||
var name string
 | 
			
		||||
has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name)
 | 
			
		||||
// SELECT name FROM user WHERE id = ?
 | 
			
		||||
 | 
			
		||||
var id int64
 | 
			
		||||
has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id)
 | 
			
		||||
has, err := engine.SQL("select id from user").Get(&id)
 | 
			
		||||
// SELECT id FROM user WHERE name = ?
 | 
			
		||||
 | 
			
		||||
var valuesMap = make(map[string]string)
 | 
			
		||||
has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
 | 
			
		||||
// SELECT * FROM user WHERE id = ?
 | 
			
		||||
 | 
			
		||||
var valuesSlice = make([]interface{}, len(cols))
 | 
			
		||||
has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
 | 
			
		||||
// SELECT col1, col2, col3 FROM user WHERE id = ?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Exist` 检测记录是否存在
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
has, err := testEngine.Exist(new(RecordExist))
 | 
			
		||||
// SELECT * FROM record_exist LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Exist(&RecordExist{
 | 
			
		||||
		Name: "test1",
 | 
			
		||||
	})
 | 
			
		||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
 | 
			
		||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
 | 
			
		||||
// select * from record_exist where name = ?
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Table("record_exist").Exist()
 | 
			
		||||
// SELECT * FROM record_exist LIMIT 1
 | 
			
		||||
 | 
			
		||||
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
 | 
			
		||||
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Find` 查询多条记录,当然可以使用Join和extends来组合使用
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
var users []User
 | 
			
		||||
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
 | 
			
		||||
// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
 | 
			
		||||
 | 
			
		||||
type Detail struct {
 | 
			
		||||
    Id int64
 | 
			
		||||
    UserId int64 `xorm:"index"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserDetail struct {
 | 
			
		||||
    User `xorm:"extends"`
 | 
			
		||||
    Detail `xorm:"extends"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var users []UserDetail
 | 
			
		||||
err := engine.Table("user").Select("user.*, detail.*")
 | 
			
		||||
    Join("INNER", "detail", "detail.user_id = user.id").
 | 
			
		||||
    Where("user.name = ?", name).Limit(10, 0).
 | 
			
		||||
    Find(&users)
 | 
			
		||||
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Iterate` 和 `Rows` 根据条件遍历数据库,可以有两种方式: Iterate and Rows
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
 | 
			
		||||
    user := bean.(*User)
 | 
			
		||||
    return nil
 | 
			
		||||
})
 | 
			
		||||
// SELECT * FROM user
 | 
			
		||||
 | 
			
		||||
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
 | 
			
		||||
    user := bean.(*User)
 | 
			
		||||
    return nil
 | 
			
		||||
})
 | 
			
		||||
// SELECT * FROM user Limit 0, 100
 | 
			
		||||
// SELECT * FROM user Limit 101, 100
 | 
			
		||||
 | 
			
		||||
rows, err := engine.Rows(&User{Name:name})
 | 
			
		||||
// SELECT * FROM user
 | 
			
		||||
defer rows.Close()
 | 
			
		||||
bean := new(Struct)
 | 
			
		||||
for rows.Next() {
 | 
			
		||||
    err = rows.Scan(bean)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Update` 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.ID(1).Update(&user)
 | 
			
		||||
// UPDATE user SET ... Where id = ?
 | 
			
		||||
 | 
			
		||||
affected, err := engine.Update(&user, &User{Name:name})
 | 
			
		||||
// UPDATE user SET ... Where name = ?
 | 
			
		||||
 | 
			
		||||
var ids = []int64{1, 2, 3}
 | 
			
		||||
affected, err := engine.In(ids).Update(&user)
 | 
			
		||||
// UPDATE user SET ... Where id IN (?, ?, ?)
 | 
			
		||||
 | 
			
		||||
// force update indicated columns by Cols
 | 
			
		||||
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
 | 
			
		||||
// UPDATE user SET age = ?, updated=? Where id = ?
 | 
			
		||||
 | 
			
		||||
// force NOT update indicated columns by Omit
 | 
			
		||||
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
 | 
			
		||||
// UPDATE user SET age = ?, updated=? Where id = ?
 | 
			
		||||
 | 
			
		||||
affected, err := engine.ID(1).AllCols().Update(&user)
 | 
			
		||||
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Delete` 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
affected, err := engine.Where(...).Delete(&user)
 | 
			
		||||
// DELETE FROM user Where ...
 | 
			
		||||
 | 
			
		||||
affected, err := engine.ID(2).Delete(&user)
 | 
			
		||||
// DELETE FROM user Where id = ?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Count` 获取记录条数
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
counts, err := engine.Count(&user)
 | 
			
		||||
// SELECT count(*) AS total FROM user
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `Sum` 求和函数
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
agesFloat64, err := engine.Sum(&user, "age")
 | 
			
		||||
// SELECT sum(age) AS total FROM user
 | 
			
		||||
 | 
			
		||||
agesInt64, err := engine.SumInt(&user, "age")
 | 
			
		||||
// SELECT sum(age) AS total FROM user
 | 
			
		||||
 | 
			
		||||
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
 | 
			
		||||
// SELECT sum(age), sum(score) FROM user
 | 
			
		||||
 | 
			
		||||
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
 | 
			
		||||
// SELECT sum(age), sum(score) FROM user
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* 条件编辑器
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users)
 | 
			
		||||
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* 在一个Go程中多次操作数据库,但没有事务
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
session := engine.NewSession()
 | 
			
		||||
defer session.Close()
 | 
			
		||||
 | 
			
		||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
 | 
			
		||||
if _, err := session.Insert(&user1); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
user2 := Userinfo{Username: "yyy"}
 | 
			
		||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
return nil
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* 在一个Go程中有事务
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
session := engine.NewSession()
 | 
			
		||||
defer session.Close()
 | 
			
		||||
 | 
			
		||||
// add Begin() before any action
 | 
			
		||||
if err := session.Begin(); err != nil {
 | 
			
		||||
    // if returned then will rollback automatically
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
 | 
			
		||||
if _, err := session.Insert(&user1); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
user2 := Userinfo{Username: "yyy"}
 | 
			
		||||
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
 | 
			
		||||
    return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// add Commit() after all actions
 | 
			
		||||
return session.Commit()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* 事务的简写方法
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) {
 | 
			
		||||
    user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
 | 
			
		||||
    if _, err := session.Insert(&user1); err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    user2 := Userinfo{Username: "yyy"}
 | 
			
		||||
    if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
    return nil, nil
 | 
			
		||||
})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* 上下文缓存,如果启用,那么针对单个对象的查询将会被缓存到系统中,可以被下一个查询使用。
 | 
			
		||||
 | 
			
		||||
```Go
 | 
			
		||||
	sess := engine.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
 | 
			
		||||
	var context = xorm.NewMemoryContextCache()
 | 
			
		||||
 | 
			
		||||
	var c2 ContextGetStruct
 | 
			
		||||
	has, err := sess.ID(1).ContextCache(context).Get(&c2)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, has)
 | 
			
		||||
	assert.EqualValues(t, 1, c2.Id)
 | 
			
		||||
	assert.EqualValues(t, "1", c2.Name)
 | 
			
		||||
	sql, args := sess.LastSQL()
 | 
			
		||||
	assert.True(t, len(sql) > 0)
 | 
			
		||||
	assert.True(t, len(args) > 0)
 | 
			
		||||
 | 
			
		||||
	var c3 ContextGetStruct
 | 
			
		||||
	has, err = sess.ID(1).ContextCache(context).Get(&c3)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, has)
 | 
			
		||||
	assert.EqualValues(t, 1, c3.Id)
 | 
			
		||||
	assert.EqualValues(t, "1", c3.Name)
 | 
			
		||||
	sql, args = sess.LastSQL()
 | 
			
		||||
	assert.True(t, len(sql) == 0)
 | 
			
		||||
	assert.True(t, len(args) == 0)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 贡献
 | 
			
		||||
 | 
			
		||||
如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://gitea.com/xorm/xorm/src/branch/master/CONTRIBUTING.md)。您也可以加入QQ群  技术帮助和讨论。
 | 
			
		||||
群一:280360085 (已满)
 | 
			
		||||
群二:795010183
 | 
			
		||||
 | 
			
		||||
## Credits
 | 
			
		||||
 | 
			
		||||
### Contributors
 | 
			
		||||
 | 
			
		||||
感谢所有的贡献者. [[Contribute](CONTRIBUTING.md)].
 | 
			
		||||
<a href="graphs/contributors"><img src="https://opencollective.com/xorm/contributors.svg?width=890&button=false" /></a>
 | 
			
		||||
 | 
			
		||||
### Backers
 | 
			
		||||
 | 
			
		||||
感谢我们所有的 backers! 🙏 [[成为 backer](https://opencollective.com/xorm#backer)]
 | 
			
		||||
 | 
			
		||||
<a href="https://opencollective.com/xorm#backers" target="_blank"><img src="https://opencollective.com/xorm/backers.svg?width=890"></a>
 | 
			
		||||
 | 
			
		||||
### Sponsors
 | 
			
		||||
 | 
			
		||||
成为 sponsor 来支持 xorm。您的 logo 将会被显示并被链接到您的网站。 [[成为 sponsor](https://opencollective.com/xorm#sponsor)]
 | 
			
		||||
 | 
			
		||||
# 案例
 | 
			
		||||
 | 
			
		||||
* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
 | 
			
		||||
 | 
			
		||||
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
 | 
			
		||||
 | 
			
		||||
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
 | 
			
		||||
 | 
			
		||||
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
 | 
			
		||||
 | 
			
		||||
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
 | 
			
		||||
 | 
			
		||||
* [Wego](http://github.com/go-tango/wego)
 | 
			
		||||
 | 
			
		||||
* [Docker.cn](https://docker.cn/)
 | 
			
		||||
 | 
			
		||||
* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
 | 
			
		||||
 | 
			
		||||
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
 | 
			
		||||
 | 
			
		||||
* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
 | 
			
		||||
 | 
			
		||||
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
 | 
			
		||||
 | 
			
		||||
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
 | 
			
		||||
 | 
			
		||||
* [YouGam](http://www.yougam.com/)
 | 
			
		||||
 | 
			
		||||
* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
 | 
			
		||||
 | 
			
		||||
* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/)
 | 
			
		||||
 | 
			
		||||
* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 更新日志
 | 
			
		||||
 | 
			
		||||
* **v0.7.0**
 | 
			
		||||
    * 修正部分Bug
 | 
			
		||||
 | 
			
		||||
* **v0.6.6**
 | 
			
		||||
    * 修正部分Bug
 | 
			
		||||
 | 
			
		||||
* **v0.6.5**
 | 
			
		||||
    * 通过 engine.SetSchema 来支持 schema,当前仅支持Postgres
 | 
			
		||||
    * vgo 支持
 | 
			
		||||
    * 新增 `FindAndCount` 函数
 | 
			
		||||
    * 通过 `NewEngineWithParams` 支持数据库特别参数
 | 
			
		||||
    * 修正部分Bug
 | 
			
		||||
 | 
			
		||||
* **v0.6.4**
 | 
			
		||||
    * 自动读写分离支持
 | 
			
		||||
    * Query/QueryString/QueryInterface 支持与 Where/And 合用
 | 
			
		||||
    * `Get` 支持获取非结构体变量
 | 
			
		||||
    * `Iterate` 支持 `BufferSize` 
 | 
			
		||||
    * 修正部分Bug
 | 
			
		||||
 | 
			
		||||
[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
 | 
			
		||||
 | 
			
		||||
## LICENSE
 | 
			
		||||
 | 
			
		||||
BSD License
 | 
			
		||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
 | 
			
		||||
							
								
								
									
										284
									
								
								vendor/xorm.io/xorm/cache_lru.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								vendor/xorm.io/xorm/cache_lru.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,284 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"container/list"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// LRUCacher implments cache object facilities
 | 
			
		||||
type LRUCacher struct {
 | 
			
		||||
	idList         *list.List
 | 
			
		||||
	sqlList        *list.List
 | 
			
		||||
	idIndex        map[string]map[string]*list.Element
 | 
			
		||||
	sqlIndex       map[string]map[string]*list.Element
 | 
			
		||||
	store          core.CacheStore
 | 
			
		||||
	mutex          sync.Mutex
 | 
			
		||||
	MaxElementSize int
 | 
			
		||||
	Expired        time.Duration
 | 
			
		||||
	GcInterval     time.Duration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewLRUCacher creates a cacher
 | 
			
		||||
func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
 | 
			
		||||
	return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewLRUCacher2 creates a cache include different params
 | 
			
		||||
func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
 | 
			
		||||
	cacher := &LRUCacher{store: store, idList: list.New(),
 | 
			
		||||
		sqlList: list.New(), Expired: expired,
 | 
			
		||||
		GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize,
 | 
			
		||||
		sqlIndex: make(map[string]map[string]*list.Element),
 | 
			
		||||
		idIndex:  make(map[string]map[string]*list.Element),
 | 
			
		||||
	}
 | 
			
		||||
	cacher.RunGC()
 | 
			
		||||
	return cacher
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunGC run once every m.GcInterval
 | 
			
		||||
func (m *LRUCacher) RunGC() {
 | 
			
		||||
	time.AfterFunc(m.GcInterval, func() {
 | 
			
		||||
		m.RunGC()
 | 
			
		||||
		m.GC()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GC check ids lit and sql list to remove all element expired
 | 
			
		||||
func (m *LRUCacher) GC() {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	defer m.mutex.Unlock()
 | 
			
		||||
	var removedNum int
 | 
			
		||||
	for e := m.idList.Front(); e != nil; {
 | 
			
		||||
		if removedNum <= core.CacheGcMaxRemoved &&
 | 
			
		||||
			time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
 | 
			
		||||
			removedNum++
 | 
			
		||||
			next := e.Next()
 | 
			
		||||
			node := e.Value.(*idNode)
 | 
			
		||||
			m.delBean(node.tbName, node.id)
 | 
			
		||||
			e = next
 | 
			
		||||
		} else {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	removedNum = 0
 | 
			
		||||
	for e := m.sqlList.Front(); e != nil; {
 | 
			
		||||
		if removedNum <= core.CacheGcMaxRemoved &&
 | 
			
		||||
			time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
 | 
			
		||||
			removedNum++
 | 
			
		||||
			next := e.Next()
 | 
			
		||||
			node := e.Value.(*sqlNode)
 | 
			
		||||
			m.delIds(node.tbName, node.sql)
 | 
			
		||||
			e = next
 | 
			
		||||
		} else {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetIds returns all bean's ids according to sql and parameter from cache
 | 
			
		||||
func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	defer m.mutex.Unlock()
 | 
			
		||||
	if _, ok := m.sqlIndex[tableName]; !ok {
 | 
			
		||||
		m.sqlIndex[tableName] = make(map[string]*list.Element)
 | 
			
		||||
	}
 | 
			
		||||
	if v, err := m.store.Get(sql); err == nil {
 | 
			
		||||
		if el, ok := m.sqlIndex[tableName][sql]; !ok {
 | 
			
		||||
			el = m.sqlList.PushBack(newSQLNode(tableName, sql))
 | 
			
		||||
			m.sqlIndex[tableName][sql] = el
 | 
			
		||||
		} else {
 | 
			
		||||
			lastTime := el.Value.(*sqlNode).lastVisit
 | 
			
		||||
			// if expired, remove the node and return nil
 | 
			
		||||
			if time.Now().Sub(lastTime) > m.Expired {
 | 
			
		||||
				m.delIds(tableName, sql)
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			m.sqlList.MoveToBack(el)
 | 
			
		||||
			el.Value.(*sqlNode).lastVisit = time.Now()
 | 
			
		||||
		}
 | 
			
		||||
		return v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.delIds(tableName, sql)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetBean returns bean according tableName and id from cache
 | 
			
		||||
func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	defer m.mutex.Unlock()
 | 
			
		||||
	if _, ok := m.idIndex[tableName]; !ok {
 | 
			
		||||
		m.idIndex[tableName] = make(map[string]*list.Element)
 | 
			
		||||
	}
 | 
			
		||||
	tid := genID(tableName, id)
 | 
			
		||||
	if v, err := m.store.Get(tid); err == nil {
 | 
			
		||||
		if el, ok := m.idIndex[tableName][id]; ok {
 | 
			
		||||
			lastTime := el.Value.(*idNode).lastVisit
 | 
			
		||||
			// if expired, remove the node and return nil
 | 
			
		||||
			if time.Now().Sub(lastTime) > m.Expired {
 | 
			
		||||
				m.delBean(tableName, id)
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			m.idList.MoveToBack(el)
 | 
			
		||||
			el.Value.(*idNode).lastVisit = time.Now()
 | 
			
		||||
		} else {
 | 
			
		||||
			el = m.idList.PushBack(newIDNode(tableName, id))
 | 
			
		||||
			m.idIndex[tableName][id] = el
 | 
			
		||||
		}
 | 
			
		||||
		return v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// store bean is not exist, then remove memory's index
 | 
			
		||||
	m.delBean(tableName, id)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// clearIds clears all sql-ids mapping on table tableName from cache
 | 
			
		||||
func (m *LRUCacher) clearIds(tableName string) {
 | 
			
		||||
	if tis, ok := m.sqlIndex[tableName]; ok {
 | 
			
		||||
		for sql, v := range tis {
 | 
			
		||||
			m.sqlList.Remove(v)
 | 
			
		||||
			m.store.Del(sql)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m.sqlIndex[tableName] = make(map[string]*list.Element)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ClearIds clears all sql-ids mapping on table tableName from cache
 | 
			
		||||
func (m *LRUCacher) ClearIds(tableName string) {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	m.clearIds(tableName)
 | 
			
		||||
	m.mutex.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *LRUCacher) clearBeans(tableName string) {
 | 
			
		||||
	if tis, ok := m.idIndex[tableName]; ok {
 | 
			
		||||
		for id, v := range tis {
 | 
			
		||||
			m.idList.Remove(v)
 | 
			
		||||
			tid := genID(tableName, id)
 | 
			
		||||
			m.store.Del(tid)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m.idIndex[tableName] = make(map[string]*list.Element)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ClearBeans clears all beans in some table
 | 
			
		||||
func (m *LRUCacher) ClearBeans(tableName string) {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	m.clearBeans(tableName)
 | 
			
		||||
	m.mutex.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PutIds pus ids into table
 | 
			
		||||
func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	if _, ok := m.sqlIndex[tableName]; !ok {
 | 
			
		||||
		m.sqlIndex[tableName] = make(map[string]*list.Element)
 | 
			
		||||
	}
 | 
			
		||||
	if el, ok := m.sqlIndex[tableName][sql]; !ok {
 | 
			
		||||
		el = m.sqlList.PushBack(newSQLNode(tableName, sql))
 | 
			
		||||
		m.sqlIndex[tableName][sql] = el
 | 
			
		||||
	} else {
 | 
			
		||||
		el.Value.(*sqlNode).lastVisit = time.Now()
 | 
			
		||||
	}
 | 
			
		||||
	m.store.Put(sql, ids)
 | 
			
		||||
	if m.sqlList.Len() > m.MaxElementSize {
 | 
			
		||||
		e := m.sqlList.Front()
 | 
			
		||||
		node := e.Value.(*sqlNode)
 | 
			
		||||
		m.delIds(node.tbName, node.sql)
 | 
			
		||||
	}
 | 
			
		||||
	m.mutex.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PutBean puts beans into table
 | 
			
		||||
func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	var el *list.Element
 | 
			
		||||
	var ok bool
 | 
			
		||||
 | 
			
		||||
	if el, ok = m.idIndex[tableName][id]; !ok {
 | 
			
		||||
		el = m.idList.PushBack(newIDNode(tableName, id))
 | 
			
		||||
		m.idIndex[tableName][id] = el
 | 
			
		||||
	} else {
 | 
			
		||||
		el.Value.(*idNode).lastVisit = time.Now()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.store.Put(genID(tableName, id), obj)
 | 
			
		||||
	if m.idList.Len() > m.MaxElementSize {
 | 
			
		||||
		e := m.idList.Front()
 | 
			
		||||
		node := e.Value.(*idNode)
 | 
			
		||||
		m.delBean(node.tbName, node.id)
 | 
			
		||||
	}
 | 
			
		||||
	m.mutex.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *LRUCacher) delIds(tableName, sql string) {
 | 
			
		||||
	if _, ok := m.sqlIndex[tableName]; ok {
 | 
			
		||||
		if el, ok := m.sqlIndex[tableName][sql]; ok {
 | 
			
		||||
			delete(m.sqlIndex[tableName], sql)
 | 
			
		||||
			m.sqlList.Remove(el)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m.store.Del(sql)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DelIds deletes ids
 | 
			
		||||
func (m *LRUCacher) DelIds(tableName, sql string) {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	m.delIds(tableName, sql)
 | 
			
		||||
	m.mutex.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *LRUCacher) delBean(tableName string, id string) {
 | 
			
		||||
	tid := genID(tableName, id)
 | 
			
		||||
	if el, ok := m.idIndex[tableName][id]; ok {
 | 
			
		||||
		delete(m.idIndex[tableName], id)
 | 
			
		||||
		m.idList.Remove(el)
 | 
			
		||||
		m.clearIds(tableName)
 | 
			
		||||
	}
 | 
			
		||||
	m.store.Del(tid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DelBean deletes beans in some table
 | 
			
		||||
func (m *LRUCacher) DelBean(tableName string, id string) {
 | 
			
		||||
	m.mutex.Lock()
 | 
			
		||||
	m.delBean(tableName, id)
 | 
			
		||||
	m.mutex.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type idNode struct {
 | 
			
		||||
	tbName    string
 | 
			
		||||
	id        string
 | 
			
		||||
	lastVisit time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type sqlNode struct {
 | 
			
		||||
	tbName    string
 | 
			
		||||
	sql       string
 | 
			
		||||
	lastVisit time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func genSQLKey(sql string, args interface{}) string {
 | 
			
		||||
	return fmt.Sprintf("%v-%v", sql, args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func genID(prefix string, id string) string {
 | 
			
		||||
	return fmt.Sprintf("%v-%v", prefix, id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newIDNode(tbName string, id string) *idNode {
 | 
			
		||||
	return &idNode{tbName, id, time.Now()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newSQLNode(tbName, sql string) *sqlNode {
 | 
			
		||||
	return &sqlNode{tbName, sql, time.Now()}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								vendor/xorm.io/xorm/cache_memory_store.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/xorm.io/xorm/cache_memory_store.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ core.CacheStore = NewMemoryStore()
 | 
			
		||||
 | 
			
		||||
// MemoryStore represents in-memory store
 | 
			
		||||
type MemoryStore struct {
 | 
			
		||||
	store map[interface{}]interface{}
 | 
			
		||||
	mutex sync.RWMutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewMemoryStore creates a new store in memory
 | 
			
		||||
func NewMemoryStore() *MemoryStore {
 | 
			
		||||
	return &MemoryStore{store: make(map[interface{}]interface{})}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Put puts object into store
 | 
			
		||||
func (s *MemoryStore) Put(key string, value interface{}) error {
 | 
			
		||||
	s.mutex.Lock()
 | 
			
		||||
	defer s.mutex.Unlock()
 | 
			
		||||
	s.store[key] = value
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get gets object from store
 | 
			
		||||
func (s *MemoryStore) Get(key string) (interface{}, error) {
 | 
			
		||||
	s.mutex.RLock()
 | 
			
		||||
	defer s.mutex.RUnlock()
 | 
			
		||||
	if v, ok := s.store[key]; ok {
 | 
			
		||||
		return v, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, ErrNotExist
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Del deletes object
 | 
			
		||||
func (s *MemoryStore) Del(key string) error {
 | 
			
		||||
	s.mutex.Lock()
 | 
			
		||||
	defer s.mutex.Unlock()
 | 
			
		||||
	delete(s.store, key)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								vendor/xorm.io/xorm/context_cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/xorm.io/xorm/context_cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
// Copyright 2018 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
 | 
			
		||||
 | 
			
		||||
// ContextCache is the interface that operates the cache data.
 | 
			
		||||
type ContextCache interface {
 | 
			
		||||
	// Put puts value into cache with key.
 | 
			
		||||
	Put(key string, val interface{})
 | 
			
		||||
	// Get gets cached value by given key.
 | 
			
		||||
	Get(key string) interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type memoryContextCache map[string]interface{}
 | 
			
		||||
 | 
			
		||||
// NewMemoryContextCache return memoryContextCache
 | 
			
		||||
func NewMemoryContextCache() memoryContextCache {
 | 
			
		||||
	return make(map[string]interface{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Put puts value into cache with key.
 | 
			
		||||
func (m memoryContextCache) Put(key string, val interface{}) {
 | 
			
		||||
	m[key] = val
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get gets cached value by given key.
 | 
			
		||||
func (m memoryContextCache) Get(key string) interface{} {
 | 
			
		||||
	return m[key]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										348
									
								
								vendor/xorm.io/xorm/convert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								vendor/xorm.io/xorm/convert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,348 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"database/sql/driver"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
 | 
			
		||||
 | 
			
		||||
func strconvErr(err error) error {
 | 
			
		||||
	if ne, ok := err.(*strconv.NumError); ok {
 | 
			
		||||
		return ne.Err
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cloneBytes(b []byte) []byte {
 | 
			
		||||
	if b == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	} else {
 | 
			
		||||
		c := make([]byte, len(b))
 | 
			
		||||
		copy(c, b)
 | 
			
		||||
		return c
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func asString(src interface{}) string {
 | 
			
		||||
	switch v := src.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		return v
 | 
			
		||||
	case []byte:
 | 
			
		||||
		return string(v)
 | 
			
		||||
	}
 | 
			
		||||
	rv := reflect.ValueOf(src)
 | 
			
		||||
	switch rv.Kind() {
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		return strconv.FormatInt(rv.Int(), 10)
 | 
			
		||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
		return strconv.FormatUint(rv.Uint(), 10)
 | 
			
		||||
	case reflect.Float64:
 | 
			
		||||
		return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
 | 
			
		||||
	case reflect.Float32:
 | 
			
		||||
		return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		return strconv.FormatBool(rv.Bool())
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%v", src)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
 | 
			
		||||
	switch rv.Kind() {
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		return strconv.AppendInt(buf, rv.Int(), 10), true
 | 
			
		||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
		return strconv.AppendUint(buf, rv.Uint(), 10), true
 | 
			
		||||
	case reflect.Float32:
 | 
			
		||||
		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
 | 
			
		||||
	case reflect.Float64:
 | 
			
		||||
		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		return strconv.AppendBool(buf, rv.Bool()), true
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		s := rv.String()
 | 
			
		||||
		return append(buf, s...), true
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// convertAssign copies to dest the value in src, converting it if possible.
 | 
			
		||||
// An error is returned if the copy would result in loss of information.
 | 
			
		||||
// dest should be a pointer type.
 | 
			
		||||
func convertAssign(dest, src interface{}) error {
 | 
			
		||||
	// Common cases, without reflect.
 | 
			
		||||
	switch s := src.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		switch d := dest.(type) {
 | 
			
		||||
		case *string:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = s
 | 
			
		||||
			return nil
 | 
			
		||||
		case *[]byte:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = []byte(s)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	case []byte:
 | 
			
		||||
		switch d := dest.(type) {
 | 
			
		||||
		case *string:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = string(s)
 | 
			
		||||
			return nil
 | 
			
		||||
		case *interface{}:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = cloneBytes(s)
 | 
			
		||||
			return nil
 | 
			
		||||
		case *[]byte:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = cloneBytes(s)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case time.Time:
 | 
			
		||||
		switch d := dest.(type) {
 | 
			
		||||
		case *string:
 | 
			
		||||
			*d = s.Format(time.RFC3339Nano)
 | 
			
		||||
			return nil
 | 
			
		||||
		case *[]byte:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = []byte(s.Format(time.RFC3339Nano))
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	case nil:
 | 
			
		||||
		switch d := dest.(type) {
 | 
			
		||||
		case *interface{}:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = nil
 | 
			
		||||
			return nil
 | 
			
		||||
		case *[]byte:
 | 
			
		||||
			if d == nil {
 | 
			
		||||
				return errNilPtr
 | 
			
		||||
			}
 | 
			
		||||
			*d = nil
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sv reflect.Value
 | 
			
		||||
 | 
			
		||||
	switch d := dest.(type) {
 | 
			
		||||
	case *string:
 | 
			
		||||
		sv = reflect.ValueOf(src)
 | 
			
		||||
		switch sv.Kind() {
 | 
			
		||||
		case reflect.Bool,
 | 
			
		||||
			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 | 
			
		||||
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
 | 
			
		||||
			reflect.Float32, reflect.Float64:
 | 
			
		||||
			*d = asString(src)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	case *[]byte:
 | 
			
		||||
		sv = reflect.ValueOf(src)
 | 
			
		||||
		if b, ok := asBytes(nil, sv); ok {
 | 
			
		||||
			*d = b
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	case *bool:
 | 
			
		||||
		bv, err := driver.Bool.ConvertValue(src)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			*d = bv.(bool)
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	case *interface{}:
 | 
			
		||||
		*d = src
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dpv := reflect.ValueOf(dest)
 | 
			
		||||
	if dpv.Kind() != reflect.Ptr {
 | 
			
		||||
		return errors.New("destination not a pointer")
 | 
			
		||||
	}
 | 
			
		||||
	if dpv.IsNil() {
 | 
			
		||||
		return errNilPtr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !sv.IsValid() {
 | 
			
		||||
		sv = reflect.ValueOf(src)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dv := reflect.Indirect(dpv)
 | 
			
		||||
	if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
 | 
			
		||||
		switch b := src.(type) {
 | 
			
		||||
		case []byte:
 | 
			
		||||
			dv.Set(reflect.ValueOf(cloneBytes(b)))
 | 
			
		||||
		default:
 | 
			
		||||
			dv.Set(sv)
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
 | 
			
		||||
		dv.Set(sv.Convert(dv.Type()))
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch dv.Kind() {
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		if src == nil {
 | 
			
		||||
			dv.Set(reflect.Zero(dv.Type()))
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dv.Set(reflect.New(dv.Type().Elem()))
 | 
			
		||||
		return convertAssign(dv.Interface(), src)
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		s := asString(src)
 | 
			
		||||
		i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			err = strconvErr(err)
 | 
			
		||||
			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
 | 
			
		||||
		}
 | 
			
		||||
		dv.SetInt(i64)
 | 
			
		||||
		return nil
 | 
			
		||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
		s := asString(src)
 | 
			
		||||
		u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			err = strconvErr(err)
 | 
			
		||||
			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
 | 
			
		||||
		}
 | 
			
		||||
		dv.SetUint(u64)
 | 
			
		||||
		return nil
 | 
			
		||||
	case reflect.Float32, reflect.Float64:
 | 
			
		||||
		s := asString(src)
 | 
			
		||||
		f64, err := strconv.ParseFloat(s, dv.Type().Bits())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			err = strconvErr(err)
 | 
			
		||||
			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
 | 
			
		||||
		}
 | 
			
		||||
		dv.SetFloat(f64)
 | 
			
		||||
		return nil
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		dv.SetString(asString(src))
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
 | 
			
		||||
	switch tp.Kind() {
 | 
			
		||||
	case reflect.Int64:
 | 
			
		||||
		return vv.Int(), nil
 | 
			
		||||
	case reflect.Int:
 | 
			
		||||
		return int(vv.Int()), nil
 | 
			
		||||
	case reflect.Int32:
 | 
			
		||||
		return int32(vv.Int()), nil
 | 
			
		||||
	case reflect.Int16:
 | 
			
		||||
		return int16(vv.Int()), nil
 | 
			
		||||
	case reflect.Int8:
 | 
			
		||||
		return int8(vv.Int()), nil
 | 
			
		||||
	case reflect.Uint64:
 | 
			
		||||
		return vv.Uint(), nil
 | 
			
		||||
	case reflect.Uint:
 | 
			
		||||
		return uint(vv.Uint()), nil
 | 
			
		||||
	case reflect.Uint32:
 | 
			
		||||
		return uint32(vv.Uint()), nil
 | 
			
		||||
	case reflect.Uint16:
 | 
			
		||||
		return uint16(vv.Uint()), nil
 | 
			
		||||
	case reflect.Uint8:
 | 
			
		||||
		return uint8(vv.Uint()), nil
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		return vv.String(), nil
 | 
			
		||||
	case reflect.Slice:
 | 
			
		||||
		if tp.Elem().Kind() == reflect.Uint8 {
 | 
			
		||||
			v, err := strconv.ParseInt(string(vv.Interface().([]byte)), 10, 64)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return v, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertFloat(v interface{}) (float64, error) {
 | 
			
		||||
	switch v.(type) {
 | 
			
		||||
	case float32:
 | 
			
		||||
		return float64(v.(float32)), nil
 | 
			
		||||
	case float64:
 | 
			
		||||
		return v.(float64), nil
 | 
			
		||||
	case string:
 | 
			
		||||
		i, err := strconv.ParseFloat(v.(string), 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return i, nil
 | 
			
		||||
	case []byte:
 | 
			
		||||
		i, err := strconv.ParseFloat(string(v.([]byte)), 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return i, nil
 | 
			
		||||
	}
 | 
			
		||||
	return 0, fmt.Errorf("unsupported type: %v", v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertInt(v interface{}) (int64, error) {
 | 
			
		||||
	switch v.(type) {
 | 
			
		||||
	case int:
 | 
			
		||||
		return int64(v.(int)), nil
 | 
			
		||||
	case int8:
 | 
			
		||||
		return int64(v.(int8)), nil
 | 
			
		||||
	case int16:
 | 
			
		||||
		return int64(v.(int16)), nil
 | 
			
		||||
	case int32:
 | 
			
		||||
		return int64(v.(int32)), nil
 | 
			
		||||
	case int64:
 | 
			
		||||
		return v.(int64), nil
 | 
			
		||||
	case []byte:
 | 
			
		||||
		i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return i, nil
 | 
			
		||||
	case string:
 | 
			
		||||
		i, err := strconv.ParseInt(v.(string), 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return i, nil
 | 
			
		||||
	}
 | 
			
		||||
	return 0, fmt.Errorf("unsupported type: %v", v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func asBool(bs []byte) (bool, error) {
 | 
			
		||||
	if len(bs) == 0 {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	if bs[0] == 0x00 {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	} else if bs[0] == 0x01 {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	return strconv.ParseBool(string(bs))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										567
									
								
								vendor/xorm.io/xorm/dialect_mssql.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										567
									
								
								vendor/xorm.io/xorm/dialect_mssql.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,567 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	mssqlReservedWords = map[string]bool{
 | 
			
		||||
		"ADD":                            true,
 | 
			
		||||
		"EXTERNAL":                       true,
 | 
			
		||||
		"PROCEDURE":                      true,
 | 
			
		||||
		"ALL":                            true,
 | 
			
		||||
		"FETCH":                          true,
 | 
			
		||||
		"PUBLIC":                         true,
 | 
			
		||||
		"ALTER":                          true,
 | 
			
		||||
		"FILE":                           true,
 | 
			
		||||
		"RAISERROR":                      true,
 | 
			
		||||
		"AND":                            true,
 | 
			
		||||
		"FILLFACTOR":                     true,
 | 
			
		||||
		"READ":                           true,
 | 
			
		||||
		"ANY":                            true,
 | 
			
		||||
		"FOR":                            true,
 | 
			
		||||
		"READTEXT":                       true,
 | 
			
		||||
		"AS":                             true,
 | 
			
		||||
		"FOREIGN":                        true,
 | 
			
		||||
		"RECONFIGURE":                    true,
 | 
			
		||||
		"ASC":                            true,
 | 
			
		||||
		"FREETEXT":                       true,
 | 
			
		||||
		"REFERENCES":                     true,
 | 
			
		||||
		"AUTHORIZATION":                  true,
 | 
			
		||||
		"FREETEXTTABLE":                  true,
 | 
			
		||||
		"REPLICATION":                    true,
 | 
			
		||||
		"BACKUP":                         true,
 | 
			
		||||
		"FROM":                           true,
 | 
			
		||||
		"RESTORE":                        true,
 | 
			
		||||
		"BEGIN":                          true,
 | 
			
		||||
		"FULL":                           true,
 | 
			
		||||
		"RESTRICT":                       true,
 | 
			
		||||
		"BETWEEN":                        true,
 | 
			
		||||
		"FUNCTION":                       true,
 | 
			
		||||
		"RETURN":                         true,
 | 
			
		||||
		"BREAK":                          true,
 | 
			
		||||
		"GOTO":                           true,
 | 
			
		||||
		"REVERT":                         true,
 | 
			
		||||
		"BROWSE":                         true,
 | 
			
		||||
		"GRANT":                          true,
 | 
			
		||||
		"REVOKE":                         true,
 | 
			
		||||
		"BULK":                           true,
 | 
			
		||||
		"GROUP":                          true,
 | 
			
		||||
		"RIGHT":                          true,
 | 
			
		||||
		"BY":                             true,
 | 
			
		||||
		"HAVING":                         true,
 | 
			
		||||
		"ROLLBACK":                       true,
 | 
			
		||||
		"CASCADE":                        true,
 | 
			
		||||
		"HOLDLOCK":                       true,
 | 
			
		||||
		"ROWCOUNT":                       true,
 | 
			
		||||
		"CASE":                           true,
 | 
			
		||||
		"IDENTITY":                       true,
 | 
			
		||||
		"ROWGUIDCOL":                     true,
 | 
			
		||||
		"CHECK":                          true,
 | 
			
		||||
		"IDENTITY_INSERT":                true,
 | 
			
		||||
		"RULE":                           true,
 | 
			
		||||
		"CHECKPOINT":                     true,
 | 
			
		||||
		"IDENTITYCOL":                    true,
 | 
			
		||||
		"SAVE":                           true,
 | 
			
		||||
		"CLOSE":                          true,
 | 
			
		||||
		"IF":                             true,
 | 
			
		||||
		"SCHEMA":                         true,
 | 
			
		||||
		"CLUSTERED":                      true,
 | 
			
		||||
		"IN":                             true,
 | 
			
		||||
		"SECURITYAUDIT":                  true,
 | 
			
		||||
		"COALESCE":                       true,
 | 
			
		||||
		"INDEX":                          true,
 | 
			
		||||
		"SELECT":                         true,
 | 
			
		||||
		"COLLATE":                        true,
 | 
			
		||||
		"INNER":                          true,
 | 
			
		||||
		"SEMANTICKEYPHRASETABLE":         true,
 | 
			
		||||
		"COLUMN":                         true,
 | 
			
		||||
		"INSERT":                         true,
 | 
			
		||||
		"SEMANTICSIMILARITYDETAILSTABLE": true,
 | 
			
		||||
		"COMMIT":                         true,
 | 
			
		||||
		"INTERSECT":                      true,
 | 
			
		||||
		"SEMANTICSIMILARITYTABLE":        true,
 | 
			
		||||
		"COMPUTE":                        true,
 | 
			
		||||
		"INTO":                           true,
 | 
			
		||||
		"SESSION_USER":                   true,
 | 
			
		||||
		"CONSTRAINT":                     true,
 | 
			
		||||
		"IS":                             true,
 | 
			
		||||
		"SET":                            true,
 | 
			
		||||
		"CONTAINS":                       true,
 | 
			
		||||
		"JOIN":                           true,
 | 
			
		||||
		"SETUSER":                        true,
 | 
			
		||||
		"CONTAINSTABLE":                  true,
 | 
			
		||||
		"KEY":                            true,
 | 
			
		||||
		"SHUTDOWN":                       true,
 | 
			
		||||
		"CONTINUE":                       true,
 | 
			
		||||
		"KILL":                           true,
 | 
			
		||||
		"SOME":                           true,
 | 
			
		||||
		"CONVERT":                        true,
 | 
			
		||||
		"LEFT":                           true,
 | 
			
		||||
		"STATISTICS":                     true,
 | 
			
		||||
		"CREATE":                         true,
 | 
			
		||||
		"LIKE":                           true,
 | 
			
		||||
		"SYSTEM_USER":                    true,
 | 
			
		||||
		"CROSS":                          true,
 | 
			
		||||
		"LINENO":                         true,
 | 
			
		||||
		"TABLE":                          true,
 | 
			
		||||
		"CURRENT":                        true,
 | 
			
		||||
		"LOAD":                           true,
 | 
			
		||||
		"TABLESAMPLE":                    true,
 | 
			
		||||
		"CURRENT_DATE":                   true,
 | 
			
		||||
		"MERGE":                          true,
 | 
			
		||||
		"TEXTSIZE":                       true,
 | 
			
		||||
		"CURRENT_TIME":                   true,
 | 
			
		||||
		"NATIONAL":                       true,
 | 
			
		||||
		"THEN":                           true,
 | 
			
		||||
		"CURRENT_TIMESTAMP":              true,
 | 
			
		||||
		"NOCHECK":                        true,
 | 
			
		||||
		"TO":                             true,
 | 
			
		||||
		"CURRENT_USER":                   true,
 | 
			
		||||
		"NONCLUSTERED":                   true,
 | 
			
		||||
		"TOP":                            true,
 | 
			
		||||
		"CURSOR":                         true,
 | 
			
		||||
		"NOT":                            true,
 | 
			
		||||
		"TRAN":                           true,
 | 
			
		||||
		"DATABASE":                       true,
 | 
			
		||||
		"NULL":                           true,
 | 
			
		||||
		"TRANSACTION":                    true,
 | 
			
		||||
		"DBCC":                           true,
 | 
			
		||||
		"NULLIF":                         true,
 | 
			
		||||
		"TRIGGER":                        true,
 | 
			
		||||
		"DEALLOCATE":                     true,
 | 
			
		||||
		"OF":                             true,
 | 
			
		||||
		"TRUNCATE":                       true,
 | 
			
		||||
		"DECLARE":                        true,
 | 
			
		||||
		"OFF":                            true,
 | 
			
		||||
		"TRY_CONVERT":                    true,
 | 
			
		||||
		"DEFAULT":                        true,
 | 
			
		||||
		"OFFSETS":                        true,
 | 
			
		||||
		"TSEQUAL":                        true,
 | 
			
		||||
		"DELETE":                         true,
 | 
			
		||||
		"ON":                             true,
 | 
			
		||||
		"UNION":                          true,
 | 
			
		||||
		"DENY":                           true,
 | 
			
		||||
		"OPEN":                           true,
 | 
			
		||||
		"UNIQUE":                         true,
 | 
			
		||||
		"DESC":                           true,
 | 
			
		||||
		"OPENDATASOURCE":                 true,
 | 
			
		||||
		"UNPIVOT":                        true,
 | 
			
		||||
		"DISK":                           true,
 | 
			
		||||
		"OPENQUERY":                      true,
 | 
			
		||||
		"UPDATE":                         true,
 | 
			
		||||
		"DISTINCT":                       true,
 | 
			
		||||
		"OPENROWSET":                     true,
 | 
			
		||||
		"UPDATETEXT":                     true,
 | 
			
		||||
		"DISTRIBUTED":                    true,
 | 
			
		||||
		"OPENXML":                        true,
 | 
			
		||||
		"USE":                            true,
 | 
			
		||||
		"DOUBLE":                         true,
 | 
			
		||||
		"OPTION":                         true,
 | 
			
		||||
		"USER":                           true,
 | 
			
		||||
		"DROP":                           true,
 | 
			
		||||
		"OR":                             true,
 | 
			
		||||
		"VALUES":                         true,
 | 
			
		||||
		"DUMP":                           true,
 | 
			
		||||
		"ORDER":                          true,
 | 
			
		||||
		"VARYING":                        true,
 | 
			
		||||
		"ELSE":                           true,
 | 
			
		||||
		"OUTER":                          true,
 | 
			
		||||
		"VIEW":                           true,
 | 
			
		||||
		"END":                            true,
 | 
			
		||||
		"OVER":                           true,
 | 
			
		||||
		"WAITFOR":                        true,
 | 
			
		||||
		"ERRLVL":                         true,
 | 
			
		||||
		"PERCENT":                        true,
 | 
			
		||||
		"WHEN":                           true,
 | 
			
		||||
		"ESCAPE":                         true,
 | 
			
		||||
		"PIVOT":                          true,
 | 
			
		||||
		"WHERE":                          true,
 | 
			
		||||
		"EXCEPT":                         true,
 | 
			
		||||
		"PLAN":                           true,
 | 
			
		||||
		"WHILE":                          true,
 | 
			
		||||
		"EXEC":                           true,
 | 
			
		||||
		"PRECISION":                      true,
 | 
			
		||||
		"WITH":                           true,
 | 
			
		||||
		"EXECUTE":                        true,
 | 
			
		||||
		"PRIMARY":                        true,
 | 
			
		||||
		"WITHIN":                         true,
 | 
			
		||||
		"EXISTS":                         true,
 | 
			
		||||
		"PRINT":                          true,
 | 
			
		||||
		"WRITETEXT":                      true,
 | 
			
		||||
		"EXIT":                           true,
 | 
			
		||||
		"PROC":                           true,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type mssql struct {
 | 
			
		||||
	core.Base
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
 | 
			
		||||
	return db.Base.Init(d, db, uri, drivername, dataSourceName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) SqlType(c *core.Column) string {
 | 
			
		||||
	var res string
 | 
			
		||||
	switch t := c.SQLType.Name; t {
 | 
			
		||||
	case core.Bool:
 | 
			
		||||
		res = core.Bit
 | 
			
		||||
		if strings.EqualFold(c.Default, "true") {
 | 
			
		||||
			c.Default = "1"
 | 
			
		||||
		} else if strings.EqualFold(c.Default, "false") {
 | 
			
		||||
			c.Default = "0"
 | 
			
		||||
		}
 | 
			
		||||
	case core.Serial:
 | 
			
		||||
		c.IsAutoIncrement = true
 | 
			
		||||
		c.IsPrimaryKey = true
 | 
			
		||||
		c.Nullable = false
 | 
			
		||||
		res = core.Int
 | 
			
		||||
	case core.BigSerial:
 | 
			
		||||
		c.IsAutoIncrement = true
 | 
			
		||||
		c.IsPrimaryKey = true
 | 
			
		||||
		c.Nullable = false
 | 
			
		||||
		res = core.BigInt
 | 
			
		||||
	case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob:
 | 
			
		||||
		res = core.VarBinary
 | 
			
		||||
		if c.Length == 0 {
 | 
			
		||||
			c.Length = 50
 | 
			
		||||
		}
 | 
			
		||||
	case core.TimeStamp:
 | 
			
		||||
		res = core.DateTime
 | 
			
		||||
	case core.TimeStampz:
 | 
			
		||||
		res = "DATETIMEOFFSET"
 | 
			
		||||
		c.Length = 7
 | 
			
		||||
	case core.MediumInt:
 | 
			
		||||
		res = core.Int
 | 
			
		||||
	case core.Text, core.MediumText, core.TinyText, core.LongText, core.Json:
 | 
			
		||||
		res = core.Varchar + "(MAX)"
 | 
			
		||||
	case core.Double:
 | 
			
		||||
		res = core.Real
 | 
			
		||||
	case core.Uuid:
 | 
			
		||||
		res = core.Varchar
 | 
			
		||||
		c.Length = 40
 | 
			
		||||
	case core.TinyInt:
 | 
			
		||||
		res = core.TinyInt
 | 
			
		||||
		c.Length = 0
 | 
			
		||||
	case core.BigInt:
 | 
			
		||||
		res = core.BigInt
 | 
			
		||||
		c.Length = 0
 | 
			
		||||
	default:
 | 
			
		||||
		res = t
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if res == core.Int {
 | 
			
		||||
		return core.Int
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hasLen1 := (c.Length > 0)
 | 
			
		||||
	hasLen2 := (c.Length2 > 0)
 | 
			
		||||
 | 
			
		||||
	if hasLen2 {
 | 
			
		||||
		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 | 
			
		||||
	} else if hasLen1 {
 | 
			
		||||
		res += "(" + strconv.Itoa(c.Length) + ")"
 | 
			
		||||
	}
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) SupportInsertMany() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) IsReserved(name string) bool {
 | 
			
		||||
	_, ok := mssqlReservedWords[name]
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) Quote(name string) string {
 | 
			
		||||
	return "\"" + name + "\""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) SupportEngine() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) AutoIncrStr() string {
 | 
			
		||||
	return "IDENTITY"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) DropTableSql(tableName string) string {
 | 
			
		||||
	return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+
 | 
			
		||||
		"object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+
 | 
			
		||||
		"DROP TABLE \"%s\"", tableName, tableName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) SupportCharset() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) IndexOnTable() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{idxName}
 | 
			
		||||
	sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?"
 | 
			
		||||
	return sql, args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{tableName, colName}
 | 
			
		||||
	sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
 | 
			
		||||
	return sql, args
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) {
 | 
			
		||||
	query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
 | 
			
		||||
 | 
			
		||||
	return db.HasRecords(query, tableName, colName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{}
 | 
			
		||||
	sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1"
 | 
			
		||||
	return sql, args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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), a.is_identity as is_identity
 | 
			
		||||
          from sys.columns a 
 | 
			
		||||
		  left join sys.types b on a.user_type_id=b.user_type_id
 | 
			
		||||
          left join sys.syscomments c on a.default_object_id=c.id
 | 
			
		||||
		  LEFT OUTER JOIN 
 | 
			
		||||
    sys.index_columns ic ON ic.object_id = a.object_id AND ic.column_id = a.column_id
 | 
			
		||||
		  LEFT OUTER JOIN 
 | 
			
		||||
    sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
 | 
			
		||||
          where a.object_id=object_id('` + tableName + `')`
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	cols := make(map[string]*core.Column)
 | 
			
		||||
	colSeq := make([]string, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var name, ctype, vdefault string
 | 
			
		||||
		var maxLen, precision, scale int
 | 
			
		||||
		var nullable, isPK, defaultIsNull, isIncrement bool
 | 
			
		||||
		err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &defaultIsNull, &vdefault, &isPK, &isIncrement)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		col := new(core.Column)
 | 
			
		||||
		col.Indexes = make(map[string]int)
 | 
			
		||||
		col.Name = strings.Trim(name, "` ")
 | 
			
		||||
		col.Nullable = nullable
 | 
			
		||||
		col.DefaultIsEmpty = defaultIsNull
 | 
			
		||||
		if !defaultIsNull {
 | 
			
		||||
			col.Default = vdefault
 | 
			
		||||
		}
 | 
			
		||||
		col.IsPrimaryKey = isPK
 | 
			
		||||
		col.IsAutoIncrement = isIncrement
 | 
			
		||||
		ct := strings.ToUpper(ctype)
 | 
			
		||||
		if ct == "DECIMAL" {
 | 
			
		||||
			col.Length = precision
 | 
			
		||||
			col.Length2 = scale
 | 
			
		||||
		} else {
 | 
			
		||||
			col.Length = maxLen
 | 
			
		||||
		}
 | 
			
		||||
		switch ct {
 | 
			
		||||
		case "DATETIMEOFFSET":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
		case "NVARCHAR":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
		case "IMAGE":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
		default:
 | 
			
		||||
			if _, ok := core.SqlTypes[ct]; ok {
 | 
			
		||||
				col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
			} else {
 | 
			
		||||
				return nil, nil, fmt.Errorf("Unknown colType %v for %v - %v", ct, tableName, col.Name)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cols[col.Name] = col
 | 
			
		||||
		colSeq = append(colSeq, col.Name)
 | 
			
		||||
	}
 | 
			
		||||
	return colSeq, cols, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) GetTables() ([]*core.Table, error) {
 | 
			
		||||
	args := []interface{}{}
 | 
			
		||||
	s := `select name from sysobjects where xtype ='U'`
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	tables := make([]*core.Table, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		table := core.NewEmptyTable()
 | 
			
		||||
		var name string
 | 
			
		||||
		err = rows.Scan(&name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		table.Name = strings.Trim(name, "` ")
 | 
			
		||||
		tables = append(tables, table)
 | 
			
		||||
	}
 | 
			
		||||
	return tables, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	s := `SELECT
 | 
			
		||||
IXS.NAME                    AS  [INDEX_NAME],
 | 
			
		||||
C.NAME                      AS  [COLUMN_NAME],
 | 
			
		||||
IXS.is_unique AS [IS_UNIQUE]
 | 
			
		||||
FROM SYS.INDEXES IXS
 | 
			
		||||
INNER JOIN SYS.INDEX_COLUMNS   IXCS
 | 
			
		||||
ON IXS.OBJECT_ID=IXCS.OBJECT_ID  AND IXS.INDEX_ID = IXCS.INDEX_ID
 | 
			
		||||
INNER   JOIN SYS.COLUMNS C  ON IXS.OBJECT_ID=C.OBJECT_ID
 | 
			
		||||
AND IXCS.COLUMN_ID=C.COLUMN_ID
 | 
			
		||||
WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
 | 
			
		||||
`
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	indexes := make(map[string]*core.Index, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var indexType int
 | 
			
		||||
		var indexName, colName, isUnique string
 | 
			
		||||
 | 
			
		||||
		err = rows.Scan(&indexName, &colName, &isUnique)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i, err := strconv.ParseBool(isUnique)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if i {
 | 
			
		||||
			indexType = core.UniqueType
 | 
			
		||||
		} else {
 | 
			
		||||
			indexType = core.IndexType
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		colName = strings.Trim(colName, "` ")
 | 
			
		||||
		var isRegular bool
 | 
			
		||||
		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 | 
			
		||||
			indexName = indexName[5+len(tableName):]
 | 
			
		||||
			isRegular = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var index *core.Index
 | 
			
		||||
		var ok bool
 | 
			
		||||
		if index, ok = indexes[indexName]; !ok {
 | 
			
		||||
			index = new(core.Index)
 | 
			
		||||
			index.Type = indexType
 | 
			
		||||
			index.Name = indexName
 | 
			
		||||
			index.IsRegular = isRegular
 | 
			
		||||
			indexes[indexName] = index
 | 
			
		||||
		}
 | 
			
		||||
		index.AddColumn(colName)
 | 
			
		||||
	}
 | 
			
		||||
	return indexes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
 | 
			
		||||
	var sql string
 | 
			
		||||
	if tableName == "" {
 | 
			
		||||
		tableName = table.Name
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE "
 | 
			
		||||
 | 
			
		||||
	sql += db.Quote(tableName) + " ("
 | 
			
		||||
 | 
			
		||||
	pkList := table.PrimaryKeys
 | 
			
		||||
 | 
			
		||||
	for _, colName := range table.ColumnsSeq() {
 | 
			
		||||
		col := table.GetColumn(colName)
 | 
			
		||||
		if col.IsPrimaryKey && len(pkList) == 1 {
 | 
			
		||||
			sql += col.String(db)
 | 
			
		||||
		} else {
 | 
			
		||||
			sql += col.StringNoPk(db)
 | 
			
		||||
		}
 | 
			
		||||
		sql = strings.TrimSpace(sql)
 | 
			
		||||
		sql += ", "
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(pkList) > 1 {
 | 
			
		||||
		sql += "PRIMARY KEY ( "
 | 
			
		||||
		sql += strings.Join(pkList, ",")
 | 
			
		||||
		sql += " ), "
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sql = sql[:len(sql)-2] + ")"
 | 
			
		||||
	sql += ";"
 | 
			
		||||
	return sql
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) ForUpdateSql(query string) string {
 | 
			
		||||
	return query
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mssql) Filters() []core.Filter {
 | 
			
		||||
	return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type odbcDriver struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 | 
			
		||||
	var dbName string
 | 
			
		||||
 | 
			
		||||
	if strings.HasPrefix(dataSourceName, "sqlserver://") {
 | 
			
		||||
		u, err := url.Parse(dataSourceName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		dbName = u.Query().Get("database")
 | 
			
		||||
	} else {
 | 
			
		||||
		kv := strings.Split(dataSourceName, ";")
 | 
			
		||||
		for _, c := range kv {
 | 
			
		||||
			vv := strings.Split(strings.TrimSpace(c), "=")
 | 
			
		||||
			if len(vv) == 2 {
 | 
			
		||||
				switch strings.ToLower(vv[0]) {
 | 
			
		||||
				case "database":
 | 
			
		||||
					dbName = vv[1]
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if dbName == "" {
 | 
			
		||||
		return nil, errors.New("no db name provided")
 | 
			
		||||
	}
 | 
			
		||||
	return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										654
									
								
								vendor/xorm.io/xorm/dialect_mysql.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										654
									
								
								vendor/xorm.io/xorm/dialect_mysql.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,654 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	mysqlReservedWords = map[string]bool{
 | 
			
		||||
		"ADD":               true,
 | 
			
		||||
		"ALL":               true,
 | 
			
		||||
		"ALTER":             true,
 | 
			
		||||
		"ANALYZE":           true,
 | 
			
		||||
		"AND":               true,
 | 
			
		||||
		"AS":                true,
 | 
			
		||||
		"ASC":               true,
 | 
			
		||||
		"ASENSITIVE":        true,
 | 
			
		||||
		"BEFORE":            true,
 | 
			
		||||
		"BETWEEN":           true,
 | 
			
		||||
		"BIGINT":            true,
 | 
			
		||||
		"BINARY":            true,
 | 
			
		||||
		"BLOB":              true,
 | 
			
		||||
		"BOTH":              true,
 | 
			
		||||
		"BY":                true,
 | 
			
		||||
		"CALL":              true,
 | 
			
		||||
		"CASCADE":           true,
 | 
			
		||||
		"CASE":              true,
 | 
			
		||||
		"CHANGE":            true,
 | 
			
		||||
		"CHAR":              true,
 | 
			
		||||
		"CHARACTER":         true,
 | 
			
		||||
		"CHECK":             true,
 | 
			
		||||
		"COLLATE":           true,
 | 
			
		||||
		"COLUMN":            true,
 | 
			
		||||
		"CONDITION":         true,
 | 
			
		||||
		"CONNECTION":        true,
 | 
			
		||||
		"CONSTRAINT":        true,
 | 
			
		||||
		"CONTINUE":          true,
 | 
			
		||||
		"CONVERT":           true,
 | 
			
		||||
		"CREATE":            true,
 | 
			
		||||
		"CROSS":             true,
 | 
			
		||||
		"CURRENT_DATE":      true,
 | 
			
		||||
		"CURRENT_TIME":      true,
 | 
			
		||||
		"CURRENT_TIMESTAMP": true,
 | 
			
		||||
		"CURRENT_USER":      true,
 | 
			
		||||
		"CURSOR":            true,
 | 
			
		||||
		"DATABASE":          true,
 | 
			
		||||
		"DATABASES":         true,
 | 
			
		||||
		"DAY_HOUR":          true,
 | 
			
		||||
		"DAY_MICROSECOND":   true,
 | 
			
		||||
		"DAY_MINUTE":        true,
 | 
			
		||||
		"DAY_SECOND":        true,
 | 
			
		||||
		"DEC":               true,
 | 
			
		||||
		"DECIMAL":           true,
 | 
			
		||||
		"DECLARE":           true,
 | 
			
		||||
		"DEFAULT":           true,
 | 
			
		||||
		"DELAYED":           true,
 | 
			
		||||
		"DELETE":            true,
 | 
			
		||||
		"DESC":              true,
 | 
			
		||||
		"DESCRIBE":          true,
 | 
			
		||||
		"DETERMINISTIC":     true,
 | 
			
		||||
		"DISTINCT":          true,
 | 
			
		||||
		"DISTINCTROW":       true,
 | 
			
		||||
		"DIV":               true,
 | 
			
		||||
		"DOUBLE":            true,
 | 
			
		||||
		"DROP":              true,
 | 
			
		||||
		"DUAL":              true,
 | 
			
		||||
		"EACH":              true,
 | 
			
		||||
		"ELSE":              true,
 | 
			
		||||
		"ELSEIF":            true,
 | 
			
		||||
		"ENCLOSED":          true,
 | 
			
		||||
		"ESCAPED":           true,
 | 
			
		||||
		"EXISTS":            true,
 | 
			
		||||
		"EXIT":              true,
 | 
			
		||||
		"EXPLAIN":           true,
 | 
			
		||||
		"FALSE":             true,
 | 
			
		||||
		"FETCH":             true,
 | 
			
		||||
		"FLOAT":             true,
 | 
			
		||||
		"FLOAT4":            true,
 | 
			
		||||
		"FLOAT8":            true,
 | 
			
		||||
		"FOR":               true,
 | 
			
		||||
		"FORCE":             true,
 | 
			
		||||
		"FOREIGN":           true,
 | 
			
		||||
		"FROM":              true,
 | 
			
		||||
		"FULLTEXT":          true,
 | 
			
		||||
		"GOTO":              true,
 | 
			
		||||
		"GRANT":             true,
 | 
			
		||||
		"GROUP":             true,
 | 
			
		||||
		"HAVING":            true,
 | 
			
		||||
		"HIGH_PRIORITY":     true,
 | 
			
		||||
		"HOUR_MICROSECOND":  true,
 | 
			
		||||
		"HOUR_MINUTE":       true,
 | 
			
		||||
		"HOUR_SECOND":       true,
 | 
			
		||||
		"IF":                true,
 | 
			
		||||
		"IGNORE":            true,
 | 
			
		||||
		"IN":                true, "INDEX": true,
 | 
			
		||||
		"INFILE": true, "INNER": true, "INOUT": true,
 | 
			
		||||
		"INSENSITIVE": true, "INSERT": true, "INT": true,
 | 
			
		||||
		"INT1": true, "INT2": true, "INT3": true,
 | 
			
		||||
		"INT4": true, "INT8": true, "INTEGER": true,
 | 
			
		||||
		"INTERVAL": true, "INTO": true, "IS": true,
 | 
			
		||||
		"ITERATE": true, "JOIN": true, "KEY": true,
 | 
			
		||||
		"KEYS": true, "KILL": true, "LABEL": true,
 | 
			
		||||
		"LEADING": true, "LEAVE": true, "LEFT": true,
 | 
			
		||||
		"LIKE": true, "LIMIT": true, "LINEAR": true,
 | 
			
		||||
		"LINES": true, "LOAD": true, "LOCALTIME": true,
 | 
			
		||||
		"LOCALTIMESTAMP": true, "LOCK": true, "LONG": true,
 | 
			
		||||
		"LONGBLOB": true, "LONGTEXT": true, "LOOP": true,
 | 
			
		||||
		"LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true,
 | 
			
		||||
		"MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true,
 | 
			
		||||
		"MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true,
 | 
			
		||||
		"MODIFIES": true, "NATURAL": true, "NOT": true,
 | 
			
		||||
		"NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true,
 | 
			
		||||
		"ON	OPTIMIZE": true, "OPTION": true,
 | 
			
		||||
		"OPTIONALLY": true, "OR": true, "ORDER": true,
 | 
			
		||||
		"OUT": true, "OUTER": true, "OUTFILE": true,
 | 
			
		||||
		"PRECISION": true, "PRIMARY": true, "PROCEDURE": true,
 | 
			
		||||
		"PURGE": true, "RAID0": true, "RANGE": true,
 | 
			
		||||
		"READ": true, "READS": true, "REAL": true,
 | 
			
		||||
		"REFERENCES": true, "REGEXP": true, "RELEASE": true,
 | 
			
		||||
		"RENAME": true, "REPEAT": true, "REPLACE": true,
 | 
			
		||||
		"REQUIRE": true, "RESTRICT": true, "RETURN": true,
 | 
			
		||||
		"REVOKE": true, "RIGHT": true, "RLIKE": true,
 | 
			
		||||
		"SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true,
 | 
			
		||||
		"SELECT": true, "SENSITIVE": true, "SEPARATOR": true,
 | 
			
		||||
		"SET": true, "SHOW": true, "SMALLINT": true,
 | 
			
		||||
		"SPATIAL": true, "SPECIFIC": true, "SQL": true,
 | 
			
		||||
		"SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true,
 | 
			
		||||
		"SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true,
 | 
			
		||||
		"SSL": true, "STARTING": true, "STRAIGHT_JOIN": true,
 | 
			
		||||
		"TABLE": true, "TERMINATED": true, "THEN": true,
 | 
			
		||||
		"TINYBLOB": true, "TINYINT": true, "TINYTEXT": true,
 | 
			
		||||
		"TO": true, "TRAILING": true, "TRIGGER": true,
 | 
			
		||||
		"TRUE": true, "UNDO": true, "UNION": true,
 | 
			
		||||
		"UNIQUE": true, "UNLOCK": true, "UNSIGNED": true,
 | 
			
		||||
		"UPDATE": true, "USAGE": true, "USE": true,
 | 
			
		||||
		"USING": true, "UTC_DATE": true, "UTC_TIME": true,
 | 
			
		||||
		"UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true,
 | 
			
		||||
		"VARCHAR":      true,
 | 
			
		||||
		"VARCHARACTER": true,
 | 
			
		||||
		"VARYING":      true,
 | 
			
		||||
		"WHEN":         true,
 | 
			
		||||
		"WHERE":        true,
 | 
			
		||||
		"WHILE":        true,
 | 
			
		||||
		"WITH":         true,
 | 
			
		||||
		"WRITE":        true,
 | 
			
		||||
		"X509":         true,
 | 
			
		||||
		"XOR":          true,
 | 
			
		||||
		"YEAR_MONTH":   true,
 | 
			
		||||
		"ZEROFILL":     true,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type mysql struct {
 | 
			
		||||
	core.Base
 | 
			
		||||
	net               string
 | 
			
		||||
	addr              string
 | 
			
		||||
	params            map[string]string
 | 
			
		||||
	loc               *time.Location
 | 
			
		||||
	timeout           time.Duration
 | 
			
		||||
	tls               *tls.Config
 | 
			
		||||
	allowAllFiles     bool
 | 
			
		||||
	allowOldPasswords bool
 | 
			
		||||
	clientFoundRows   bool
 | 
			
		||||
	rowFormat         string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
 | 
			
		||||
	return db.Base.Init(d, db, uri, drivername, dataSourceName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) SetParams(params map[string]string) {
 | 
			
		||||
	rowFormat, ok := params["rowFormat"]
 | 
			
		||||
	if ok {
 | 
			
		||||
		var t = strings.ToUpper(rowFormat)
 | 
			
		||||
		switch t {
 | 
			
		||||
		case "COMPACT":
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case "REDUNDANT":
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case "DYNAMIC":
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case "COMPRESSED":
 | 
			
		||||
			db.rowFormat = t
 | 
			
		||||
			break
 | 
			
		||||
		default:
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) SqlType(c *core.Column) string {
 | 
			
		||||
	var res string
 | 
			
		||||
	switch t := c.SQLType.Name; t {
 | 
			
		||||
	case core.Bool:
 | 
			
		||||
		res = core.TinyInt
 | 
			
		||||
		c.Length = 1
 | 
			
		||||
	case core.Serial:
 | 
			
		||||
		c.IsAutoIncrement = true
 | 
			
		||||
		c.IsPrimaryKey = true
 | 
			
		||||
		c.Nullable = false
 | 
			
		||||
		res = core.Int
 | 
			
		||||
	case core.BigSerial:
 | 
			
		||||
		c.IsAutoIncrement = true
 | 
			
		||||
		c.IsPrimaryKey = true
 | 
			
		||||
		c.Nullable = false
 | 
			
		||||
		res = core.BigInt
 | 
			
		||||
	case core.Bytea:
 | 
			
		||||
		res = core.Blob
 | 
			
		||||
	case core.TimeStampz:
 | 
			
		||||
		res = core.Char
 | 
			
		||||
		c.Length = 64
 | 
			
		||||
	case core.Enum: // mysql enum
 | 
			
		||||
		res = core.Enum
 | 
			
		||||
		res += "("
 | 
			
		||||
		opts := ""
 | 
			
		||||
		for v := range c.EnumOptions {
 | 
			
		||||
			opts += fmt.Sprintf(",'%v'", v)
 | 
			
		||||
		}
 | 
			
		||||
		res += strings.TrimLeft(opts, ",")
 | 
			
		||||
		res += ")"
 | 
			
		||||
	case core.Set: // mysql set
 | 
			
		||||
		res = core.Set
 | 
			
		||||
		res += "("
 | 
			
		||||
		opts := ""
 | 
			
		||||
		for v := range c.SetOptions {
 | 
			
		||||
			opts += fmt.Sprintf(",'%v'", v)
 | 
			
		||||
		}
 | 
			
		||||
		res += strings.TrimLeft(opts, ",")
 | 
			
		||||
		res += ")"
 | 
			
		||||
	case core.NVarchar:
 | 
			
		||||
		res = core.Varchar
 | 
			
		||||
	case core.Uuid:
 | 
			
		||||
		res = core.Varchar
 | 
			
		||||
		c.Length = 40
 | 
			
		||||
	case core.Json:
 | 
			
		||||
		res = core.Text
 | 
			
		||||
	default:
 | 
			
		||||
		res = t
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hasLen1 := (c.Length > 0)
 | 
			
		||||
	hasLen2 := (c.Length2 > 0)
 | 
			
		||||
 | 
			
		||||
	if res == core.BigInt && !hasLen1 && !hasLen2 {
 | 
			
		||||
		c.Length = 20
 | 
			
		||||
		hasLen1 = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hasLen2 {
 | 
			
		||||
		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 | 
			
		||||
	} else if hasLen1 {
 | 
			
		||||
		res += "(" + strconv.Itoa(c.Length) + ")"
 | 
			
		||||
	}
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) SupportInsertMany() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) IsReserved(name string) bool {
 | 
			
		||||
	_, ok := mysqlReservedWords[name]
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) Quote(name string) string {
 | 
			
		||||
	return "`" + name + "`"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) SupportEngine() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) AutoIncrStr() string {
 | 
			
		||||
	return "AUTO_INCREMENT"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) SupportCharset() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) IndexOnTable() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{db.DbName, tableName, idxName}
 | 
			
		||||
	sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
 | 
			
		||||
	sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
 | 
			
		||||
	return sql, args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{db.DbName, tableName, colName}
 | 
			
		||||
	sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
 | 
			
		||||
	return sql, args
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{db.DbName, tableName}
 | 
			
		||||
	sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
 | 
			
		||||
	return sql, args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 | 
			
		||||
	args := []interface{}{db.DbName, tableName}
 | 
			
		||||
	s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
 | 
			
		||||
		" `COLUMN_KEY`, `EXTRA`,`COLUMN_COMMENT` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	cols := make(map[string]*core.Column)
 | 
			
		||||
	colSeq := make([]string, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		col := new(core.Column)
 | 
			
		||||
		col.Indexes = make(map[string]int)
 | 
			
		||||
 | 
			
		||||
		var columnName, isNullable, colType, colKey, extra, comment string
 | 
			
		||||
		var colDefault *string
 | 
			
		||||
		err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		col.Name = strings.Trim(columnName, "` ")
 | 
			
		||||
		col.Comment = comment
 | 
			
		||||
		if "YES" == isNullable {
 | 
			
		||||
			col.Nullable = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if colDefault != nil {
 | 
			
		||||
			col.Default = *colDefault
 | 
			
		||||
			col.DefaultIsEmpty = false
 | 
			
		||||
		} else {
 | 
			
		||||
			col.DefaultIsEmpty = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cts := strings.Split(colType, "(")
 | 
			
		||||
		colName := cts[0]
 | 
			
		||||
		colType = strings.ToUpper(colName)
 | 
			
		||||
		var len1, len2 int
 | 
			
		||||
		if len(cts) == 2 {
 | 
			
		||||
			idx := strings.Index(cts[1], ")")
 | 
			
		||||
			if colType == core.Enum && cts[1][0] == '\'' { // enum
 | 
			
		||||
				options := strings.Split(cts[1][0:idx], ",")
 | 
			
		||||
				col.EnumOptions = make(map[string]int)
 | 
			
		||||
				for k, v := range options {
 | 
			
		||||
					v = strings.TrimSpace(v)
 | 
			
		||||
					v = strings.Trim(v, "'")
 | 
			
		||||
					col.EnumOptions[v] = k
 | 
			
		||||
				}
 | 
			
		||||
			} else if colType == core.Set && cts[1][0] == '\'' {
 | 
			
		||||
				options := strings.Split(cts[1][0:idx], ",")
 | 
			
		||||
				col.SetOptions = make(map[string]int)
 | 
			
		||||
				for k, v := range options {
 | 
			
		||||
					v = strings.TrimSpace(v)
 | 
			
		||||
					v = strings.Trim(v, "'")
 | 
			
		||||
					col.SetOptions[v] = k
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				lens := strings.Split(cts[1][0:idx], ",")
 | 
			
		||||
				len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, nil, err
 | 
			
		||||
				}
 | 
			
		||||
				if len(lens) == 2 {
 | 
			
		||||
					len2, err = strconv.Atoi(lens[1])
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, nil, err
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if colType == "FLOAT UNSIGNED" {
 | 
			
		||||
			colType = "FLOAT"
 | 
			
		||||
		}
 | 
			
		||||
		if colType == "DOUBLE UNSIGNED" {
 | 
			
		||||
			colType = "DOUBLE"
 | 
			
		||||
		}
 | 
			
		||||
		col.Length = len1
 | 
			
		||||
		col.Length2 = len2
 | 
			
		||||
		if _, ok := core.SqlTypes[colType]; ok {
 | 
			
		||||
			col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, nil, fmt.Errorf("Unknown colType %v", colType)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if colKey == "PRI" {
 | 
			
		||||
			col.IsPrimaryKey = true
 | 
			
		||||
		}
 | 
			
		||||
		if colKey == "UNI" {
 | 
			
		||||
			// col.is
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if extra == "auto_increment" {
 | 
			
		||||
			col.IsAutoIncrement = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !col.DefaultIsEmpty {
 | 
			
		||||
			if col.SQLType.IsText() {
 | 
			
		||||
				col.Default = "'" + col.Default + "'"
 | 
			
		||||
			} else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" {
 | 
			
		||||
				col.Default = "'" + col.Default + "'"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cols[col.Name] = col
 | 
			
		||||
		colSeq = append(colSeq, col.Name)
 | 
			
		||||
	}
 | 
			
		||||
	return colSeq, cols, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) GetTables() ([]*core.Table, error) {
 | 
			
		||||
	args := []interface{}{db.DbName}
 | 
			
		||||
	s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " +
 | 
			
		||||
		"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	tables := make([]*core.Table, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		table := core.NewEmptyTable()
 | 
			
		||||
		var name, engine, tableRows, comment string
 | 
			
		||||
		var autoIncr *string
 | 
			
		||||
		err = rows.Scan(&name, &engine, &tableRows, &autoIncr, &comment)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		table.Name = name
 | 
			
		||||
		table.Comment = comment
 | 
			
		||||
		table.StoreEngine = engine
 | 
			
		||||
		tables = append(tables, table)
 | 
			
		||||
	}
 | 
			
		||||
	return tables, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
 | 
			
		||||
	args := []interface{}{db.DbName, tableName}
 | 
			
		||||
	s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	indexes := make(map[string]*core.Index, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var indexType int
 | 
			
		||||
		var indexName, colName, nonUnique string
 | 
			
		||||
		err = rows.Scan(&indexName, &nonUnique, &colName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if indexName == "PRIMARY" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if "YES" == nonUnique || nonUnique == "1" {
 | 
			
		||||
			indexType = core.IndexType
 | 
			
		||||
		} else {
 | 
			
		||||
			indexType = core.UniqueType
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		colName = strings.Trim(colName, "` ")
 | 
			
		||||
		var isRegular bool
 | 
			
		||||
		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 | 
			
		||||
			indexName = indexName[5+len(tableName):]
 | 
			
		||||
			isRegular = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var index *core.Index
 | 
			
		||||
		var ok bool
 | 
			
		||||
		if index, ok = indexes[indexName]; !ok {
 | 
			
		||||
			index = new(core.Index)
 | 
			
		||||
			index.IsRegular = isRegular
 | 
			
		||||
			index.Type = indexType
 | 
			
		||||
			index.Name = indexName
 | 
			
		||||
			indexes[indexName] = index
 | 
			
		||||
		}
 | 
			
		||||
		index.AddColumn(colName)
 | 
			
		||||
	}
 | 
			
		||||
	return indexes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
 | 
			
		||||
	var sql string
 | 
			
		||||
	sql = "CREATE TABLE IF NOT EXISTS "
 | 
			
		||||
	if tableName == "" {
 | 
			
		||||
		tableName = table.Name
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sql += db.Quote(tableName)
 | 
			
		||||
	sql += " ("
 | 
			
		||||
 | 
			
		||||
	if len(table.ColumnsSeq()) > 0 {
 | 
			
		||||
		pkList := table.PrimaryKeys
 | 
			
		||||
 | 
			
		||||
		for _, colName := range table.ColumnsSeq() {
 | 
			
		||||
			col := table.GetColumn(colName)
 | 
			
		||||
			if col.IsPrimaryKey && len(pkList) == 1 {
 | 
			
		||||
				sql += col.String(db)
 | 
			
		||||
			} else {
 | 
			
		||||
				sql += col.StringNoPk(db)
 | 
			
		||||
			}
 | 
			
		||||
			sql = strings.TrimSpace(sql)
 | 
			
		||||
			if len(col.Comment) > 0 {
 | 
			
		||||
				sql += " COMMENT '" + col.Comment + "'"
 | 
			
		||||
			}
 | 
			
		||||
			sql += ", "
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(pkList) > 1 {
 | 
			
		||||
			sql += "PRIMARY KEY ( "
 | 
			
		||||
			sql += db.Quote(strings.Join(pkList, db.Quote(",")))
 | 
			
		||||
			sql += " ), "
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sql = sql[:len(sql)-2]
 | 
			
		||||
	}
 | 
			
		||||
	sql += ")"
 | 
			
		||||
 | 
			
		||||
	if storeEngine != "" {
 | 
			
		||||
		sql += " ENGINE=" + storeEngine
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(charset) == 0 {
 | 
			
		||||
		charset = db.URI().Charset
 | 
			
		||||
	}
 | 
			
		||||
	if len(charset) != 0 {
 | 
			
		||||
		sql += " DEFAULT CHARSET " + charset
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if db.rowFormat != "" {
 | 
			
		||||
		sql += " ROW_FORMAT=" + db.rowFormat
 | 
			
		||||
	}
 | 
			
		||||
	return sql
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *mysql) Filters() []core.Filter {
 | 
			
		||||
	return []core.Filter{&core.IdFilter{}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mymysqlDriver struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 | 
			
		||||
	db := &core.Uri{DbType: core.MYSQL}
 | 
			
		||||
 | 
			
		||||
	pd := strings.SplitN(dataSourceName, "*", 2)
 | 
			
		||||
	if len(pd) == 2 {
 | 
			
		||||
		// Parse protocol part of URI
 | 
			
		||||
		p := strings.SplitN(pd[0], ":", 2)
 | 
			
		||||
		if len(p) != 2 {
 | 
			
		||||
			return nil, errors.New("Wrong protocol part of URI")
 | 
			
		||||
		}
 | 
			
		||||
		db.Proto = p[0]
 | 
			
		||||
		options := strings.Split(p[1], ",")
 | 
			
		||||
		db.Raddr = options[0]
 | 
			
		||||
		for _, o := range options[1:] {
 | 
			
		||||
			kv := strings.SplitN(o, "=", 2)
 | 
			
		||||
			var k, v string
 | 
			
		||||
			if len(kv) == 2 {
 | 
			
		||||
				k, v = kv[0], kv[1]
 | 
			
		||||
			} else {
 | 
			
		||||
				k, v = o, "true"
 | 
			
		||||
			}
 | 
			
		||||
			switch k {
 | 
			
		||||
			case "laddr":
 | 
			
		||||
				db.Laddr = v
 | 
			
		||||
			case "timeout":
 | 
			
		||||
				to, err := time.ParseDuration(v)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				db.Timeout = to
 | 
			
		||||
			default:
 | 
			
		||||
				return nil, errors.New("Unknown option: " + k)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// Remove protocol part
 | 
			
		||||
		pd = pd[1:]
 | 
			
		||||
	}
 | 
			
		||||
	// Parse database part of URI
 | 
			
		||||
	dup := strings.SplitN(pd[0], "/", 3)
 | 
			
		||||
	if len(dup) != 3 {
 | 
			
		||||
		return nil, errors.New("Wrong database part of URI")
 | 
			
		||||
	}
 | 
			
		||||
	db.DbName = dup[0]
 | 
			
		||||
	db.User = dup[1]
 | 
			
		||||
	db.Passwd = dup[2]
 | 
			
		||||
 | 
			
		||||
	return db, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mysqlDriver struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 | 
			
		||||
	dsnPattern := regexp.MustCompile(
 | 
			
		||||
		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
 | 
			
		||||
			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
 | 
			
		||||
			`\/(?P<dbname>.*?)` + // /dbname
 | 
			
		||||
			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1¶mN=valueN]
 | 
			
		||||
	matches := dsnPattern.FindStringSubmatch(dataSourceName)
 | 
			
		||||
	// tlsConfigRegister := make(map[string]*tls.Config)
 | 
			
		||||
	names := dsnPattern.SubexpNames()
 | 
			
		||||
 | 
			
		||||
	uri := &core.Uri{DbType: core.MYSQL}
 | 
			
		||||
 | 
			
		||||
	for i, match := range matches {
 | 
			
		||||
		switch names[i] {
 | 
			
		||||
		case "dbname":
 | 
			
		||||
			uri.DbName = match
 | 
			
		||||
		case "params":
 | 
			
		||||
			if len(match) > 0 {
 | 
			
		||||
				kvs := strings.Split(match, "&")
 | 
			
		||||
				for _, kv := range kvs {
 | 
			
		||||
					splits := strings.Split(kv, "=")
 | 
			
		||||
					if len(splits) == 2 {
 | 
			
		||||
						switch splits[0] {
 | 
			
		||||
						case "charset":
 | 
			
		||||
							uri.Charset = splits[1]
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return uri, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										902
									
								
								vendor/xorm.io/xorm/dialect_oracle.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										902
									
								
								vendor/xorm.io/xorm/dialect_oracle.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,902 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	oracleReservedWords = map[string]bool{
 | 
			
		||||
		"ACCESS":                    true,
 | 
			
		||||
		"ACCOUNT":                   true,
 | 
			
		||||
		"ACTIVATE":                  true,
 | 
			
		||||
		"ADD":                       true,
 | 
			
		||||
		"ADMIN":                     true,
 | 
			
		||||
		"ADVISE":                    true,
 | 
			
		||||
		"AFTER":                     true,
 | 
			
		||||
		"ALL":                       true,
 | 
			
		||||
		"ALL_ROWS":                  true,
 | 
			
		||||
		"ALLOCATE":                  true,
 | 
			
		||||
		"ALTER":                     true,
 | 
			
		||||
		"ANALYZE":                   true,
 | 
			
		||||
		"AND":                       true,
 | 
			
		||||
		"ANY":                       true,
 | 
			
		||||
		"ARCHIVE":                   true,
 | 
			
		||||
		"ARCHIVELOG":                true,
 | 
			
		||||
		"ARRAY":                     true,
 | 
			
		||||
		"AS":                        true,
 | 
			
		||||
		"ASC":                       true,
 | 
			
		||||
		"AT":                        true,
 | 
			
		||||
		"AUDIT":                     true,
 | 
			
		||||
		"AUTHENTICATED":             true,
 | 
			
		||||
		"AUTHORIZATION":             true,
 | 
			
		||||
		"AUTOEXTEND":                true,
 | 
			
		||||
		"AUTOMATIC":                 true,
 | 
			
		||||
		"BACKUP":                    true,
 | 
			
		||||
		"BECOME":                    true,
 | 
			
		||||
		"BEFORE":                    true,
 | 
			
		||||
		"BEGIN":                     true,
 | 
			
		||||
		"BETWEEN":                   true,
 | 
			
		||||
		"BFILE":                     true,
 | 
			
		||||
		"BITMAP":                    true,
 | 
			
		||||
		"BLOB":                      true,
 | 
			
		||||
		"BLOCK":                     true,
 | 
			
		||||
		"BODY":                      true,
 | 
			
		||||
		"BY":                        true,
 | 
			
		||||
		"CACHE":                     true,
 | 
			
		||||
		"CACHE_INSTANCES":           true,
 | 
			
		||||
		"CANCEL":                    true,
 | 
			
		||||
		"CASCADE":                   true,
 | 
			
		||||
		"CAST":                      true,
 | 
			
		||||
		"CFILE":                     true,
 | 
			
		||||
		"CHAINED":                   true,
 | 
			
		||||
		"CHANGE":                    true,
 | 
			
		||||
		"CHAR":                      true,
 | 
			
		||||
		"CHAR_CS":                   true,
 | 
			
		||||
		"CHARACTER":                 true,
 | 
			
		||||
		"CHECK":                     true,
 | 
			
		||||
		"CHECKPOINT":                true,
 | 
			
		||||
		"CHOOSE":                    true,
 | 
			
		||||
		"CHUNK":                     true,
 | 
			
		||||
		"CLEAR":                     true,
 | 
			
		||||
		"CLOB":                      true,
 | 
			
		||||
		"CLONE":                     true,
 | 
			
		||||
		"CLOSE":                     true,
 | 
			
		||||
		"CLOSE_CACHED_OPEN_CURSORS": true,
 | 
			
		||||
		"CLUSTER":                   true,
 | 
			
		||||
		"COALESCE":                  true,
 | 
			
		||||
		"COLUMN":                    true,
 | 
			
		||||
		"COLUMNS":                   true,
 | 
			
		||||
		"COMMENT":                   true,
 | 
			
		||||
		"COMMIT":                    true,
 | 
			
		||||
		"COMMITTED":                 true,
 | 
			
		||||
		"COMPATIBILITY":             true,
 | 
			
		||||
		"COMPILE":                   true,
 | 
			
		||||
		"COMPLETE":                  true,
 | 
			
		||||
		"COMPOSITE_LIMIT":           true,
 | 
			
		||||
		"COMPRESS":                  true,
 | 
			
		||||
		"COMPUTE":                   true,
 | 
			
		||||
		"CONNECT":                   true,
 | 
			
		||||
		"CONNECT_TIME":              true,
 | 
			
		||||
		"CONSTRAINT":                true,
 | 
			
		||||
		"CONSTRAINTS":               true,
 | 
			
		||||
		"CONTENTS":                  true,
 | 
			
		||||
		"CONTINUE":                  true,
 | 
			
		||||
		"CONTROLFILE":               true,
 | 
			
		||||
		"CONVERT":                   true,
 | 
			
		||||
		"COST":                      true,
 | 
			
		||||
		"CPU_PER_CALL":              true,
 | 
			
		||||
		"CPU_PER_SESSION":           true,
 | 
			
		||||
		"CREATE":                    true,
 | 
			
		||||
		"CURRENT":                   true,
 | 
			
		||||
		"CURRENT_SCHEMA":            true,
 | 
			
		||||
		"CURREN_USER":               true,
 | 
			
		||||
		"CURSOR":                    true,
 | 
			
		||||
		"CYCLE":                     true,
 | 
			
		||||
		"DANGLING":                  true,
 | 
			
		||||
		"DATABASE":                  true,
 | 
			
		||||
		"DATAFILE":                  true,
 | 
			
		||||
		"DATAFILES":                 true,
 | 
			
		||||
		"DATAOBJNO":                 true,
 | 
			
		||||
		"DATE":                      true,
 | 
			
		||||
		"DBA":                       true,
 | 
			
		||||
		"DBHIGH":                    true,
 | 
			
		||||
		"DBLOW":                     true,
 | 
			
		||||
		"DBMAC":                     true,
 | 
			
		||||
		"DEALLOCATE":                true,
 | 
			
		||||
		"DEBUG":                     true,
 | 
			
		||||
		"DEC":                       true,
 | 
			
		||||
		"DECIMAL":                   true,
 | 
			
		||||
		"DECLARE":                   true,
 | 
			
		||||
		"DEFAULT":                   true,
 | 
			
		||||
		"DEFERRABLE":                true,
 | 
			
		||||
		"DEFERRED":                  true,
 | 
			
		||||
		"DEGREE":                    true,
 | 
			
		||||
		"DELETE":                    true,
 | 
			
		||||
		"DEREF":                     true,
 | 
			
		||||
		"DESC":                      true,
 | 
			
		||||
		"DIRECTORY":                 true,
 | 
			
		||||
		"DISABLE":                   true,
 | 
			
		||||
		"DISCONNECT":                true,
 | 
			
		||||
		"DISMOUNT":                  true,
 | 
			
		||||
		"DISTINCT":                  true,
 | 
			
		||||
		"DISTRIBUTED":               true,
 | 
			
		||||
		"DML":                       true,
 | 
			
		||||
		"DOUBLE":                    true,
 | 
			
		||||
		"DROP":                      true,
 | 
			
		||||
		"DUMP":                      true,
 | 
			
		||||
		"EACH":                      true,
 | 
			
		||||
		"ELSE":                      true,
 | 
			
		||||
		"ENABLE":                    true,
 | 
			
		||||
		"END":                       true,
 | 
			
		||||
		"ENFORCE":                   true,
 | 
			
		||||
		"ENTRY":                     true,
 | 
			
		||||
		"ESCAPE":                    true,
 | 
			
		||||
		"EXCEPT":                    true,
 | 
			
		||||
		"EXCEPTIONS":                true,
 | 
			
		||||
		"EXCHANGE":                  true,
 | 
			
		||||
		"EXCLUDING":                 true,
 | 
			
		||||
		"EXCLUSIVE":                 true,
 | 
			
		||||
		"EXECUTE":                   true,
 | 
			
		||||
		"EXISTS":                    true,
 | 
			
		||||
		"EXPIRE":                    true,
 | 
			
		||||
		"EXPLAIN":                   true,
 | 
			
		||||
		"EXTENT":                    true,
 | 
			
		||||
		"EXTENTS":                   true,
 | 
			
		||||
		"EXTERNALLY":                true,
 | 
			
		||||
		"FAILED_LOGIN_ATTEMPTS":     true,
 | 
			
		||||
		"FALSE":                     true,
 | 
			
		||||
		"FAST":                      true,
 | 
			
		||||
		"FILE":                      true,
 | 
			
		||||
		"FIRST_ROWS":                true,
 | 
			
		||||
		"FLAGGER":                   true,
 | 
			
		||||
		"FLOAT":                     true,
 | 
			
		||||
		"FLOB":                      true,
 | 
			
		||||
		"FLUSH":                     true,
 | 
			
		||||
		"FOR":                       true,
 | 
			
		||||
		"FORCE":                     true,
 | 
			
		||||
		"FOREIGN":                   true,
 | 
			
		||||
		"FREELIST":                  true,
 | 
			
		||||
		"FREELISTS":                 true,
 | 
			
		||||
		"FROM":                      true,
 | 
			
		||||
		"FULL":                      true,
 | 
			
		||||
		"FUNCTION":                  true,
 | 
			
		||||
		"GLOBAL":                    true,
 | 
			
		||||
		"GLOBALLY":                  true,
 | 
			
		||||
		"GLOBAL_NAME":               true,
 | 
			
		||||
		"GRANT":                     true,
 | 
			
		||||
		"GROUP":                     true,
 | 
			
		||||
		"GROUPS":                    true,
 | 
			
		||||
		"HASH":                      true,
 | 
			
		||||
		"HASHKEYS":                  true,
 | 
			
		||||
		"HAVING":                    true,
 | 
			
		||||
		"HEADER":                    true,
 | 
			
		||||
		"HEAP":                      true,
 | 
			
		||||
		"IDENTIFIED":                true,
 | 
			
		||||
		"IDGENERATORS":              true,
 | 
			
		||||
		"IDLE_TIME":                 true,
 | 
			
		||||
		"IF":                        true,
 | 
			
		||||
		"IMMEDIATE":                 true,
 | 
			
		||||
		"IN":                        true,
 | 
			
		||||
		"INCLUDING":                 true,
 | 
			
		||||
		"INCREMENT":                 true,
 | 
			
		||||
		"INDEX":                     true,
 | 
			
		||||
		"INDEXED":                   true,
 | 
			
		||||
		"INDEXES":                   true,
 | 
			
		||||
		"INDICATOR":                 true,
 | 
			
		||||
		"IND_PARTITION":             true,
 | 
			
		||||
		"INITIAL":                   true,
 | 
			
		||||
		"INITIALLY":                 true,
 | 
			
		||||
		"INITRANS":                  true,
 | 
			
		||||
		"INSERT":                    true,
 | 
			
		||||
		"INSTANCE":                  true,
 | 
			
		||||
		"INSTANCES":                 true,
 | 
			
		||||
		"INSTEAD":                   true,
 | 
			
		||||
		"INT":                       true,
 | 
			
		||||
		"INTEGER":                   true,
 | 
			
		||||
		"INTERMEDIATE":              true,
 | 
			
		||||
		"INTERSECT":                 true,
 | 
			
		||||
		"INTO":                      true,
 | 
			
		||||
		"IS":                        true,
 | 
			
		||||
		"ISOLATION":                 true,
 | 
			
		||||
		"ISOLATION_LEVEL":           true,
 | 
			
		||||
		"KEEP":                      true,
 | 
			
		||||
		"KEY":                       true,
 | 
			
		||||
		"KILL":                      true,
 | 
			
		||||
		"LABEL":                     true,
 | 
			
		||||
		"LAYER":                     true,
 | 
			
		||||
		"LESS":                      true,
 | 
			
		||||
		"LEVEL":                     true,
 | 
			
		||||
		"LIBRARY":                   true,
 | 
			
		||||
		"LIKE":                      true,
 | 
			
		||||
		"LIMIT":                     true,
 | 
			
		||||
		"LINK":                      true,
 | 
			
		||||
		"LIST":                      true,
 | 
			
		||||
		"LOB":                       true,
 | 
			
		||||
		"LOCAL":                     true,
 | 
			
		||||
		"LOCK":                      true,
 | 
			
		||||
		"LOCKED":                    true,
 | 
			
		||||
		"LOG":                       true,
 | 
			
		||||
		"LOGFILE":                   true,
 | 
			
		||||
		"LOGGING":                   true,
 | 
			
		||||
		"LOGICAL_READS_PER_CALL":    true,
 | 
			
		||||
		"LOGICAL_READS_PER_SESSION": true,
 | 
			
		||||
		"LONG":                      true,
 | 
			
		||||
		"MANAGE":                    true,
 | 
			
		||||
		"MASTER":                    true,
 | 
			
		||||
		"MAX":                       true,
 | 
			
		||||
		"MAXARCHLOGS":               true,
 | 
			
		||||
		"MAXDATAFILES":              true,
 | 
			
		||||
		"MAXEXTENTS":                true,
 | 
			
		||||
		"MAXINSTANCES":              true,
 | 
			
		||||
		"MAXLOGFILES":               true,
 | 
			
		||||
		"MAXLOGHISTORY":             true,
 | 
			
		||||
		"MAXLOGMEMBERS":             true,
 | 
			
		||||
		"MAXSIZE":                   true,
 | 
			
		||||
		"MAXTRANS":                  true,
 | 
			
		||||
		"MAXVALUE":                  true,
 | 
			
		||||
		"MIN":                       true,
 | 
			
		||||
		"MEMBER":                    true,
 | 
			
		||||
		"MINIMUM":                   true,
 | 
			
		||||
		"MINEXTENTS":                true,
 | 
			
		||||
		"MINUS":                     true,
 | 
			
		||||
		"MINVALUE":                  true,
 | 
			
		||||
		"MLSLABEL":                  true,
 | 
			
		||||
		"MLS_LABEL_FORMAT":          true,
 | 
			
		||||
		"MODE":                      true,
 | 
			
		||||
		"MODIFY":                    true,
 | 
			
		||||
		"MOUNT":                     true,
 | 
			
		||||
		"MOVE":                      true,
 | 
			
		||||
		"MTS_DISPATCHERS":           true,
 | 
			
		||||
		"MULTISET":                  true,
 | 
			
		||||
		"NATIONAL":                  true,
 | 
			
		||||
		"NCHAR":                     true,
 | 
			
		||||
		"NCHAR_CS":                  true,
 | 
			
		||||
		"NCLOB":                     true,
 | 
			
		||||
		"NEEDED":                    true,
 | 
			
		||||
		"NESTED":                    true,
 | 
			
		||||
		"NETWORK":                   true,
 | 
			
		||||
		"NEW":                       true,
 | 
			
		||||
		"NEXT":                      true,
 | 
			
		||||
		"NOARCHIVELOG":              true,
 | 
			
		||||
		"NOAUDIT":                   true,
 | 
			
		||||
		"NOCACHE":                   true,
 | 
			
		||||
		"NOCOMPRESS":                true,
 | 
			
		||||
		"NOCYCLE":                   true,
 | 
			
		||||
		"NOFORCE":                   true,
 | 
			
		||||
		"NOLOGGING":                 true,
 | 
			
		||||
		"NOMAXVALUE":                true,
 | 
			
		||||
		"NOMINVALUE":                true,
 | 
			
		||||
		"NONE":                      true,
 | 
			
		||||
		"NOORDER":                   true,
 | 
			
		||||
		"NOOVERRIDE":                true,
 | 
			
		||||
		"NOPARALLEL":                true,
 | 
			
		||||
		"NOREVERSE":                 true,
 | 
			
		||||
		"NORMAL":                    true,
 | 
			
		||||
		"NOSORT":                    true,
 | 
			
		||||
		"NOT":                       true,
 | 
			
		||||
		"NOTHING":                   true,
 | 
			
		||||
		"NOWAIT":                    true,
 | 
			
		||||
		"NULL":                      true,
 | 
			
		||||
		"NUMBER":                    true,
 | 
			
		||||
		"NUMERIC":                   true,
 | 
			
		||||
		"NVARCHAR2":                 true,
 | 
			
		||||
		"OBJECT":                    true,
 | 
			
		||||
		"OBJNO":                     true,
 | 
			
		||||
		"OBJNO_REUSE":               true,
 | 
			
		||||
		"OF":                        true,
 | 
			
		||||
		"OFF":                       true,
 | 
			
		||||
		"OFFLINE":                   true,
 | 
			
		||||
		"OID":                       true,
 | 
			
		||||
		"OIDINDEX":                  true,
 | 
			
		||||
		"OLD":                       true,
 | 
			
		||||
		"ON":                        true,
 | 
			
		||||
		"ONLINE":                    true,
 | 
			
		||||
		"ONLY":                      true,
 | 
			
		||||
		"OPCODE":                    true,
 | 
			
		||||
		"OPEN":                      true,
 | 
			
		||||
		"OPTIMAL":                   true,
 | 
			
		||||
		"OPTIMIZER_GOAL":            true,
 | 
			
		||||
		"OPTION":                    true,
 | 
			
		||||
		"OR":                        true,
 | 
			
		||||
		"ORDER":                     true,
 | 
			
		||||
		"ORGANIZATION":              true,
 | 
			
		||||
		"OSLABEL":                   true,
 | 
			
		||||
		"OVERFLOW":                  true,
 | 
			
		||||
		"OWN":                       true,
 | 
			
		||||
		"PACKAGE":                   true,
 | 
			
		||||
		"PARALLEL":                  true,
 | 
			
		||||
		"PARTITION":                 true,
 | 
			
		||||
		"PASSWORD":                  true,
 | 
			
		||||
		"PASSWORD_GRACE_TIME":       true,
 | 
			
		||||
		"PASSWORD_LIFE_TIME":        true,
 | 
			
		||||
		"PASSWORD_LOCK_TIME":        true,
 | 
			
		||||
		"PASSWORD_REUSE_MAX":        true,
 | 
			
		||||
		"PASSWORD_REUSE_TIME":       true,
 | 
			
		||||
		"PASSWORD_VERIFY_FUNCTION":  true,
 | 
			
		||||
		"PCTFREE":                   true,
 | 
			
		||||
		"PCTINCREASE":               true,
 | 
			
		||||
		"PCTTHRESHOLD":              true,
 | 
			
		||||
		"PCTUSED":                   true,
 | 
			
		||||
		"PCTVERSION":                true,
 | 
			
		||||
		"PERCENT":                   true,
 | 
			
		||||
		"PERMANENT":                 true,
 | 
			
		||||
		"PLAN":                      true,
 | 
			
		||||
		"PLSQL_DEBUG":               true,
 | 
			
		||||
		"POST_TRANSACTION":          true,
 | 
			
		||||
		"PRECISION":                 true,
 | 
			
		||||
		"PRESERVE":                  true,
 | 
			
		||||
		"PRIMARY":                   true,
 | 
			
		||||
		"PRIOR":                     true,
 | 
			
		||||
		"PRIVATE":                   true,
 | 
			
		||||
		"PRIVATE_SGA":               true,
 | 
			
		||||
		"PRIVILEGE":                 true,
 | 
			
		||||
		"PRIVILEGES":                true,
 | 
			
		||||
		"PROCEDURE":                 true,
 | 
			
		||||
		"PROFILE":                   true,
 | 
			
		||||
		"PUBLIC":                    true,
 | 
			
		||||
		"PURGE":                     true,
 | 
			
		||||
		"QUEUE":                     true,
 | 
			
		||||
		"QUOTA":                     true,
 | 
			
		||||
		"RANGE":                     true,
 | 
			
		||||
		"RAW":                       true,
 | 
			
		||||
		"RBA":                       true,
 | 
			
		||||
		"READ":                      true,
 | 
			
		||||
		"READUP":                    true,
 | 
			
		||||
		"REAL":                      true,
 | 
			
		||||
		"REBUILD":                   true,
 | 
			
		||||
		"RECOVER":                   true,
 | 
			
		||||
		"RECOVERABLE":               true,
 | 
			
		||||
		"RECOVERY":                  true,
 | 
			
		||||
		"REF":                       true,
 | 
			
		||||
		"REFERENCES":                true,
 | 
			
		||||
		"REFERENCING":               true,
 | 
			
		||||
		"REFRESH":                   true,
 | 
			
		||||
		"RENAME":                    true,
 | 
			
		||||
		"REPLACE":                   true,
 | 
			
		||||
		"RESET":                     true,
 | 
			
		||||
		"RESETLOGS":                 true,
 | 
			
		||||
		"RESIZE":                    true,
 | 
			
		||||
		"RESOURCE":                  true,
 | 
			
		||||
		"RESTRICTED":                true,
 | 
			
		||||
		"RETURN":                    true,
 | 
			
		||||
		"RETURNING":                 true,
 | 
			
		||||
		"REUSE":                     true,
 | 
			
		||||
		"REVERSE":                   true,
 | 
			
		||||
		"REVOKE":                    true,
 | 
			
		||||
		"ROLE":                      true,
 | 
			
		||||
		"ROLES":                     true,
 | 
			
		||||
		"ROLLBACK":                  true,
 | 
			
		||||
		"ROW":                       true,
 | 
			
		||||
		"ROWID":                     true,
 | 
			
		||||
		"ROWNUM":                    true,
 | 
			
		||||
		"ROWS":                      true,
 | 
			
		||||
		"RULE":                      true,
 | 
			
		||||
		"SAMPLE":                    true,
 | 
			
		||||
		"SAVEPOINT":                 true,
 | 
			
		||||
		"SB4":                       true,
 | 
			
		||||
		"SCAN_INSTANCES":            true,
 | 
			
		||||
		"SCHEMA":                    true,
 | 
			
		||||
		"SCN":                       true,
 | 
			
		||||
		"SCOPE":                     true,
 | 
			
		||||
		"SD_ALL":                    true,
 | 
			
		||||
		"SD_INHIBIT":                true,
 | 
			
		||||
		"SD_SHOW":                   true,
 | 
			
		||||
		"SEGMENT":                   true,
 | 
			
		||||
		"SEG_BLOCK":                 true,
 | 
			
		||||
		"SEG_FILE":                  true,
 | 
			
		||||
		"SELECT":                    true,
 | 
			
		||||
		"SEQUENCE":                  true,
 | 
			
		||||
		"SERIALIZABLE":              true,
 | 
			
		||||
		"SESSION":                   true,
 | 
			
		||||
		"SESSION_CACHED_CURSORS":    true,
 | 
			
		||||
		"SESSIONS_PER_USER":         true,
 | 
			
		||||
		"SET":                       true,
 | 
			
		||||
		"SHARE":                     true,
 | 
			
		||||
		"SHARED":                    true,
 | 
			
		||||
		"SHARED_POOL":               true,
 | 
			
		||||
		"SHRINK":                    true,
 | 
			
		||||
		"SIZE":                      true,
 | 
			
		||||
		"SKIP":                      true,
 | 
			
		||||
		"SKIP_UNUSABLE_INDEXES":     true,
 | 
			
		||||
		"SMALLINT":                  true,
 | 
			
		||||
		"SNAPSHOT":                  true,
 | 
			
		||||
		"SOME":                      true,
 | 
			
		||||
		"SORT":                      true,
 | 
			
		||||
		"SPECIFICATION":             true,
 | 
			
		||||
		"SPLIT":                     true,
 | 
			
		||||
		"SQL_TRACE":                 true,
 | 
			
		||||
		"STANDBY":                   true,
 | 
			
		||||
		"START":                     true,
 | 
			
		||||
		"STATEMENT_ID":              true,
 | 
			
		||||
		"STATISTICS":                true,
 | 
			
		||||
		"STOP":                      true,
 | 
			
		||||
		"STORAGE":                   true,
 | 
			
		||||
		"STORE":                     true,
 | 
			
		||||
		"STRUCTURE":                 true,
 | 
			
		||||
		"SUCCESSFUL":                true,
 | 
			
		||||
		"SWITCH":                    true,
 | 
			
		||||
		"SYS_OP_ENFORCE_NOT_NULL$":  true,
 | 
			
		||||
		"SYS_OP_NTCIMG$":            true,
 | 
			
		||||
		"SYNONYM":                   true,
 | 
			
		||||
		"SYSDATE":                   true,
 | 
			
		||||
		"SYSDBA":                    true,
 | 
			
		||||
		"SYSOPER":                   true,
 | 
			
		||||
		"SYSTEM":                    true,
 | 
			
		||||
		"TABLE":                     true,
 | 
			
		||||
		"TABLES":                    true,
 | 
			
		||||
		"TABLESPACE":                true,
 | 
			
		||||
		"TABLESPACE_NO":             true,
 | 
			
		||||
		"TABNO":                     true,
 | 
			
		||||
		"TEMPORARY":                 true,
 | 
			
		||||
		"THAN":                      true,
 | 
			
		||||
		"THE":                       true,
 | 
			
		||||
		"THEN":                      true,
 | 
			
		||||
		"THREAD":                    true,
 | 
			
		||||
		"TIMESTAMP":                 true,
 | 
			
		||||
		"TIME":                      true,
 | 
			
		||||
		"TO":                        true,
 | 
			
		||||
		"TOPLEVEL":                  true,
 | 
			
		||||
		"TRACE":                     true,
 | 
			
		||||
		"TRACING":                   true,
 | 
			
		||||
		"TRANSACTION":               true,
 | 
			
		||||
		"TRANSITIONAL":              true,
 | 
			
		||||
		"TRIGGER":                   true,
 | 
			
		||||
		"TRIGGERS":                  true,
 | 
			
		||||
		"TRUE":                      true,
 | 
			
		||||
		"TRUNCATE":                  true,
 | 
			
		||||
		"TX":                        true,
 | 
			
		||||
		"TYPE":                      true,
 | 
			
		||||
		"UB2":                       true,
 | 
			
		||||
		"UBA":                       true,
 | 
			
		||||
		"UID":                       true,
 | 
			
		||||
		"UNARCHIVED":                true,
 | 
			
		||||
		"UNDO":                      true,
 | 
			
		||||
		"UNION":                     true,
 | 
			
		||||
		"UNIQUE":                    true,
 | 
			
		||||
		"UNLIMITED":                 true,
 | 
			
		||||
		"UNLOCK":                    true,
 | 
			
		||||
		"UNRECOVERABLE":             true,
 | 
			
		||||
		"UNTIL":                     true,
 | 
			
		||||
		"UNUSABLE":                  true,
 | 
			
		||||
		"UNUSED":                    true,
 | 
			
		||||
		"UPDATABLE":                 true,
 | 
			
		||||
		"UPDATE":                    true,
 | 
			
		||||
		"USAGE":                     true,
 | 
			
		||||
		"USE":                       true,
 | 
			
		||||
		"USER":                      true,
 | 
			
		||||
		"USING":                     true,
 | 
			
		||||
		"VALIDATE":                  true,
 | 
			
		||||
		"VALIDATION":                true,
 | 
			
		||||
		"VALUE":                     true,
 | 
			
		||||
		"VALUES":                    true,
 | 
			
		||||
		"VARCHAR":                   true,
 | 
			
		||||
		"VARCHAR2":                  true,
 | 
			
		||||
		"VARYING":                   true,
 | 
			
		||||
		"VIEW":                      true,
 | 
			
		||||
		"WHEN":                      true,
 | 
			
		||||
		"WHENEVER":                  true,
 | 
			
		||||
		"WHERE":                     true,
 | 
			
		||||
		"WITH":                      true,
 | 
			
		||||
		"WITHOUT":                   true,
 | 
			
		||||
		"WORK":                      true,
 | 
			
		||||
		"WRITE":                     true,
 | 
			
		||||
		"WRITEDOWN":                 true,
 | 
			
		||||
		"WRITEUP":                   true,
 | 
			
		||||
		"XID":                       true,
 | 
			
		||||
		"YEAR":                      true,
 | 
			
		||||
		"ZONE":                      true,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type oracle struct {
 | 
			
		||||
	core.Base
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
 | 
			
		||||
	return db.Base.Init(d, db, uri, drivername, dataSourceName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) SqlType(c *core.Column) string {
 | 
			
		||||
	var res string
 | 
			
		||||
	switch t := c.SQLType.Name; t {
 | 
			
		||||
	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial:
 | 
			
		||||
		res = "NUMBER"
 | 
			
		||||
	case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea:
 | 
			
		||||
		return core.Blob
 | 
			
		||||
	case core.Time, core.DateTime, core.TimeStamp:
 | 
			
		||||
		res = core.TimeStamp
 | 
			
		||||
	case core.TimeStampz:
 | 
			
		||||
		res = "TIMESTAMP WITH TIME ZONE"
 | 
			
		||||
	case core.Float, core.Double, core.Numeric, core.Decimal:
 | 
			
		||||
		res = "NUMBER"
 | 
			
		||||
	case core.Text, core.MediumText, core.LongText, core.Json:
 | 
			
		||||
		res = "CLOB"
 | 
			
		||||
	case core.Char, core.Varchar, core.TinyText:
 | 
			
		||||
		res = "VARCHAR2"
 | 
			
		||||
	default:
 | 
			
		||||
		res = t
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hasLen1 := (c.Length > 0)
 | 
			
		||||
	hasLen2 := (c.Length2 > 0)
 | 
			
		||||
 | 
			
		||||
	if hasLen2 {
 | 
			
		||||
		res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
 | 
			
		||||
	} else if hasLen1 {
 | 
			
		||||
		res += "(" + strconv.Itoa(c.Length) + ")"
 | 
			
		||||
	}
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) AutoIncrStr() string {
 | 
			
		||||
	return "AUTO_INCREMENT"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) SupportInsertMany() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) IsReserved(name string) bool {
 | 
			
		||||
	_, ok := oracleReservedWords[name]
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) Quote(name string) string {
 | 
			
		||||
	return "[" + name + "]"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) SupportEngine() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) SupportCharset() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) SupportDropIfExists() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) IndexOnTable() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) DropTableSql(tableName string) string {
 | 
			
		||||
	return fmt.Sprintf("DROP TABLE `%s`", tableName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
 | 
			
		||||
	var sql string
 | 
			
		||||
	sql = "CREATE TABLE "
 | 
			
		||||
	if tableName == "" {
 | 
			
		||||
		tableName = table.Name
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sql += db.Quote(tableName) + " ("
 | 
			
		||||
 | 
			
		||||
	pkList := table.PrimaryKeys
 | 
			
		||||
 | 
			
		||||
	for _, colName := range table.ColumnsSeq() {
 | 
			
		||||
		col := table.GetColumn(colName)
 | 
			
		||||
		/*if col.IsPrimaryKey && len(pkList) == 1 {
 | 
			
		||||
			sql += col.String(b.dialect)
 | 
			
		||||
		} else {*/
 | 
			
		||||
		sql += col.StringNoPk(db)
 | 
			
		||||
		// }
 | 
			
		||||
		sql = strings.TrimSpace(sql)
 | 
			
		||||
		sql += ", "
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(pkList) > 0 {
 | 
			
		||||
		sql += "PRIMARY KEY ( "
 | 
			
		||||
		sql += db.Quote(strings.Join(pkList, db.Quote(",")))
 | 
			
		||||
		sql += " ), "
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sql = sql[:len(sql)-2] + ")"
 | 
			
		||||
	if db.SupportEngine() && storeEngine != "" {
 | 
			
		||||
		sql += " ENGINE=" + storeEngine
 | 
			
		||||
	}
 | 
			
		||||
	if db.SupportCharset() {
 | 
			
		||||
		if len(charset) == 0 {
 | 
			
		||||
			charset = db.URI().Charset
 | 
			
		||||
		}
 | 
			
		||||
		if len(charset) > 0 {
 | 
			
		||||
			sql += " DEFAULT CHARSET " + charset
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return sql
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{tableName, idxName}
 | 
			
		||||
	return `SELECT INDEX_NAME FROM USER_INDEXES ` +
 | 
			
		||||
		`WHERE TABLE_NAME = :1 AND INDEX_NAME = :2`, args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	return `SELECT table_name FROM user_tables WHERE table_name = :1`, args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) MustDropTable(tableName string) error {
 | 
			
		||||
	sql, args := db.TableCheckSql(tableName)
 | 
			
		||||
	db.LogSQL(sql, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(sql, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	if !rows.Next() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sql = "Drop Table \"" + tableName + "\""
 | 
			
		||||
	db.LogSQL(sql, args)
 | 
			
		||||
 | 
			
		||||
	_, err = db.DB().Exec(sql)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)}
 | 
			
		||||
	return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" +
 | 
			
		||||
		" AND column_name = ?", args
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
 | 
			
		||||
	args := []interface{}{tableName, colName}
 | 
			
		||||
	query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
 | 
			
		||||
		" AND column_name = :2"
 | 
			
		||||
	db.LogSQL(query, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(query, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	if rows.Next() {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
 | 
			
		||||
		"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	cols := make(map[string]*core.Column)
 | 
			
		||||
	colSeq := make([]string, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		col := new(core.Column)
 | 
			
		||||
		col.Indexes = make(map[string]int)
 | 
			
		||||
 | 
			
		||||
		var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
 | 
			
		||||
		var dataLen int
 | 
			
		||||
 | 
			
		||||
		err = rows.Scan(&colName, &colDefault, &dataType, &dataLen, &dataPrecision,
 | 
			
		||||
			&dataScale, &nullable)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		col.Name = strings.Trim(*colName, `" `)
 | 
			
		||||
		if colDefault != nil {
 | 
			
		||||
			col.Default = *colDefault
 | 
			
		||||
			col.DefaultIsEmpty = false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if *nullable == "Y" {
 | 
			
		||||
			col.Nullable = true
 | 
			
		||||
		} else {
 | 
			
		||||
			col.Nullable = false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var ignore bool
 | 
			
		||||
 | 
			
		||||
		var dt string
 | 
			
		||||
		var len1, len2 int
 | 
			
		||||
		dts := strings.Split(*dataType, "(")
 | 
			
		||||
		dt = dts[0]
 | 
			
		||||
		if len(dts) > 1 {
 | 
			
		||||
			lens := strings.Split(dts[1][:len(dts[1])-1], ",")
 | 
			
		||||
			if len(lens) > 1 {
 | 
			
		||||
				len1, _ = strconv.Atoi(lens[0])
 | 
			
		||||
				len2, _ = strconv.Atoi(lens[1])
 | 
			
		||||
			} else {
 | 
			
		||||
				len1, _ = strconv.Atoi(lens[0])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch dt {
 | 
			
		||||
		case "VARCHAR2":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: len1, DefaultLength2: len2}
 | 
			
		||||
		case "NVARCHAR2":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: len1, DefaultLength2: len2}
 | 
			
		||||
		case "TIMESTAMP WITH TIME ZONE":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
		case "NUMBER":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.Double, DefaultLength: len1, DefaultLength2: len2}
 | 
			
		||||
		case "LONG", "LONG RAW":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.Text, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
		case "RAW":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.Binary, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
		case "ROWID":
 | 
			
		||||
			col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 18, DefaultLength2: 0}
 | 
			
		||||
		case "AQ$_SUBSCRIBERS":
 | 
			
		||||
			ignore = true
 | 
			
		||||
		default:
 | 
			
		||||
			col.SQLType = core.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ignore {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
 | 
			
		||||
			return nil, nil, fmt.Errorf("Unknown colType %v %v", *dataType, col.SQLType)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		col.Length = dataLen
 | 
			
		||||
 | 
			
		||||
		if col.SQLType.IsText() || col.SQLType.IsTime() {
 | 
			
		||||
			if !col.DefaultIsEmpty {
 | 
			
		||||
				col.Default = "'" + col.Default + "'"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cols[col.Name] = col
 | 
			
		||||
		colSeq = append(colSeq, col.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return colSeq, cols, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) GetTables() ([]*core.Table, error) {
 | 
			
		||||
	args := []interface{}{}
 | 
			
		||||
	s := "SELECT table_name FROM user_tables"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	tables := make([]*core.Table, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		table := core.NewEmptyTable()
 | 
			
		||||
		err = rows.Scan(&table.Name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tables = append(tables, table)
 | 
			
		||||
	}
 | 
			
		||||
	return tables, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
 | 
			
		||||
		"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	indexes := make(map[string]*core.Index, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var indexType int
 | 
			
		||||
		var indexName, colName, uniqueness string
 | 
			
		||||
 | 
			
		||||
		err = rows.Scan(&colName, &uniqueness, &indexName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		indexName = strings.Trim(indexName, `" `)
 | 
			
		||||
 | 
			
		||||
		var isRegular bool
 | 
			
		||||
		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 | 
			
		||||
			indexName = indexName[5+len(tableName):]
 | 
			
		||||
			isRegular = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if uniqueness == "UNIQUE" {
 | 
			
		||||
			indexType = core.UniqueType
 | 
			
		||||
		} else {
 | 
			
		||||
			indexType = core.IndexType
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var index *core.Index
 | 
			
		||||
		var ok bool
 | 
			
		||||
		if index, ok = indexes[indexName]; !ok {
 | 
			
		||||
			index = new(core.Index)
 | 
			
		||||
			index.Type = indexType
 | 
			
		||||
			index.Name = indexName
 | 
			
		||||
			index.IsRegular = isRegular
 | 
			
		||||
			indexes[indexName] = index
 | 
			
		||||
		}
 | 
			
		||||
		index.AddColumn(colName)
 | 
			
		||||
	}
 | 
			
		||||
	return indexes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *oracle) Filters() []core.Filter {
 | 
			
		||||
	return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{Prefix: ":", Start: 1}, &core.IdFilter{}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type goracleDriver struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 | 
			
		||||
	db := &core.Uri{DbType: core.ORACLE}
 | 
			
		||||
	dsnPattern := regexp.MustCompile(
 | 
			
		||||
		`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
 | 
			
		||||
			`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
 | 
			
		||||
			`\/(?P<dbname>.*?)` + // /dbname
 | 
			
		||||
			`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1¶mN=valueN]
 | 
			
		||||
	matches := dsnPattern.FindStringSubmatch(dataSourceName)
 | 
			
		||||
	// tlsConfigRegister := make(map[string]*tls.Config)
 | 
			
		||||
	names := dsnPattern.SubexpNames()
 | 
			
		||||
 | 
			
		||||
	for i, match := range matches {
 | 
			
		||||
		switch names[i] {
 | 
			
		||||
		case "dbname":
 | 
			
		||||
			db.DbName = match
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if db.DbName == "" {
 | 
			
		||||
		return nil, errors.New("dbname is empty")
 | 
			
		||||
	}
 | 
			
		||||
	return db, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type oci8Driver struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// dataSourceName=user/password@ipv4:port/dbname
 | 
			
		||||
// dataSourceName=user/password@[ipv6]:port/dbname
 | 
			
		||||
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 | 
			
		||||
	db := &core.Uri{DbType: core.ORACLE}
 | 
			
		||||
	dsnPattern := regexp.MustCompile(
 | 
			
		||||
		`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
 | 
			
		||||
			`(?P<net>.*)` + // ip:port
 | 
			
		||||
			`\/(?P<dbname>.*)`) // dbname
 | 
			
		||||
	matches := dsnPattern.FindStringSubmatch(dataSourceName)
 | 
			
		||||
	names := dsnPattern.SubexpNames()
 | 
			
		||||
	for i, match := range matches {
 | 
			
		||||
		switch names[i] {
 | 
			
		||||
		case "dbname":
 | 
			
		||||
			db.DbName = match
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if db.DbName == "" {
 | 
			
		||||
		return nil, errors.New("dbname is empty")
 | 
			
		||||
	}
 | 
			
		||||
	return db, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1253
									
								
								vendor/xorm.io/xorm/dialect_postgres.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1253
									
								
								vendor/xorm.io/xorm/dialect_postgres.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										492
									
								
								vendor/xorm.io/xorm/dialect_sqlite3.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										492
									
								
								vendor/xorm.io/xorm/dialect_sqlite3.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,492 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	sqlite3ReservedWords = map[string]bool{
 | 
			
		||||
		"ABORT":             true,
 | 
			
		||||
		"ACTION":            true,
 | 
			
		||||
		"ADD":               true,
 | 
			
		||||
		"AFTER":             true,
 | 
			
		||||
		"ALL":               true,
 | 
			
		||||
		"ALTER":             true,
 | 
			
		||||
		"ANALYZE":           true,
 | 
			
		||||
		"AND":               true,
 | 
			
		||||
		"AS":                true,
 | 
			
		||||
		"ASC":               true,
 | 
			
		||||
		"ATTACH":            true,
 | 
			
		||||
		"AUTOINCREMENT":     true,
 | 
			
		||||
		"BEFORE":            true,
 | 
			
		||||
		"BEGIN":             true,
 | 
			
		||||
		"BETWEEN":           true,
 | 
			
		||||
		"BY":                true,
 | 
			
		||||
		"CASCADE":           true,
 | 
			
		||||
		"CASE":              true,
 | 
			
		||||
		"CAST":              true,
 | 
			
		||||
		"CHECK":             true,
 | 
			
		||||
		"COLLATE":           true,
 | 
			
		||||
		"COLUMN":            true,
 | 
			
		||||
		"COMMIT":            true,
 | 
			
		||||
		"CONFLICT":          true,
 | 
			
		||||
		"CONSTRAINT":        true,
 | 
			
		||||
		"CREATE":            true,
 | 
			
		||||
		"CROSS":             true,
 | 
			
		||||
		"CURRENT_DATE":      true,
 | 
			
		||||
		"CURRENT_TIME":      true,
 | 
			
		||||
		"CURRENT_TIMESTAMP": true,
 | 
			
		||||
		"DATABASE":          true,
 | 
			
		||||
		"DEFAULT":           true,
 | 
			
		||||
		"DEFERRABLE":        true,
 | 
			
		||||
		"DEFERRED":          true,
 | 
			
		||||
		"DELETE":            true,
 | 
			
		||||
		"DESC":              true,
 | 
			
		||||
		"DETACH":            true,
 | 
			
		||||
		"DISTINCT":          true,
 | 
			
		||||
		"DROP":              true,
 | 
			
		||||
		"EACH":              true,
 | 
			
		||||
		"ELSE":              true,
 | 
			
		||||
		"END":               true,
 | 
			
		||||
		"ESCAPE":            true,
 | 
			
		||||
		"EXCEPT":            true,
 | 
			
		||||
		"EXCLUSIVE":         true,
 | 
			
		||||
		"EXISTS":            true,
 | 
			
		||||
		"EXPLAIN":           true,
 | 
			
		||||
		"FAIL":              true,
 | 
			
		||||
		"FOR":               true,
 | 
			
		||||
		"FOREIGN":           true,
 | 
			
		||||
		"FROM":              true,
 | 
			
		||||
		"FULL":              true,
 | 
			
		||||
		"GLOB":              true,
 | 
			
		||||
		"GROUP":             true,
 | 
			
		||||
		"HAVING":            true,
 | 
			
		||||
		"IF":                true,
 | 
			
		||||
		"IGNORE":            true,
 | 
			
		||||
		"IMMEDIATE":         true,
 | 
			
		||||
		"IN":                true,
 | 
			
		||||
		"INDEX":             true,
 | 
			
		||||
		"INDEXED":           true,
 | 
			
		||||
		"INITIALLY":         true,
 | 
			
		||||
		"INNER":             true,
 | 
			
		||||
		"INSERT":            true,
 | 
			
		||||
		"INSTEAD":           true,
 | 
			
		||||
		"INTERSECT":         true,
 | 
			
		||||
		"INTO":              true,
 | 
			
		||||
		"IS":                true,
 | 
			
		||||
		"ISNULL":            true,
 | 
			
		||||
		"JOIN":              true,
 | 
			
		||||
		"KEY":               true,
 | 
			
		||||
		"LEFT":              true,
 | 
			
		||||
		"LIKE":              true,
 | 
			
		||||
		"LIMIT":             true,
 | 
			
		||||
		"MATCH":             true,
 | 
			
		||||
		"NATURAL":           true,
 | 
			
		||||
		"NO":                true,
 | 
			
		||||
		"NOT":               true,
 | 
			
		||||
		"NOTNULL":           true,
 | 
			
		||||
		"NULL":              true,
 | 
			
		||||
		"OF":                true,
 | 
			
		||||
		"OFFSET":            true,
 | 
			
		||||
		"ON":                true,
 | 
			
		||||
		"OR":                true,
 | 
			
		||||
		"ORDER":             true,
 | 
			
		||||
		"OUTER":             true,
 | 
			
		||||
		"PLAN":              true,
 | 
			
		||||
		"PRAGMA":            true,
 | 
			
		||||
		"PRIMARY":           true,
 | 
			
		||||
		"QUERY":             true,
 | 
			
		||||
		"RAISE":             true,
 | 
			
		||||
		"RECURSIVE":         true,
 | 
			
		||||
		"REFERENCES":        true,
 | 
			
		||||
		"REGEXP":            true,
 | 
			
		||||
		"REINDEX":           true,
 | 
			
		||||
		"RELEASE":           true,
 | 
			
		||||
		"RENAME":            true,
 | 
			
		||||
		"REPLACE":           true,
 | 
			
		||||
		"RESTRICT":          true,
 | 
			
		||||
		"RIGHT":             true,
 | 
			
		||||
		"ROLLBACK":          true,
 | 
			
		||||
		"ROW":               true,
 | 
			
		||||
		"SAVEPOINT":         true,
 | 
			
		||||
		"SELECT":            true,
 | 
			
		||||
		"SET":               true,
 | 
			
		||||
		"TABLE":             true,
 | 
			
		||||
		"TEMP":              true,
 | 
			
		||||
		"TEMPORARY":         true,
 | 
			
		||||
		"THEN":              true,
 | 
			
		||||
		"TO":                true,
 | 
			
		||||
		"TRANSACTI":         true,
 | 
			
		||||
		"TRIGGER":           true,
 | 
			
		||||
		"UNION":             true,
 | 
			
		||||
		"UNIQUE":            true,
 | 
			
		||||
		"UPDATE":            true,
 | 
			
		||||
		"USING":             true,
 | 
			
		||||
		"VACUUM":            true,
 | 
			
		||||
		"VALUES":            true,
 | 
			
		||||
		"VIEW":              true,
 | 
			
		||||
		"VIRTUAL":           true,
 | 
			
		||||
		"WHEN":              true,
 | 
			
		||||
		"WHERE":             true,
 | 
			
		||||
		"WITH":              true,
 | 
			
		||||
		"WITHOUT":           true,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type sqlite3 struct {
 | 
			
		||||
	core.Base
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
 | 
			
		||||
	return db.Base.Init(d, db, uri, drivername, dataSourceName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) SqlType(c *core.Column) string {
 | 
			
		||||
	switch t := c.SQLType.Name; t {
 | 
			
		||||
	case core.Bool:
 | 
			
		||||
		if c.Default == "true" {
 | 
			
		||||
			c.Default = "1"
 | 
			
		||||
		} else if c.Default == "false" {
 | 
			
		||||
			c.Default = "0"
 | 
			
		||||
		}
 | 
			
		||||
		return core.Integer
 | 
			
		||||
	case core.Date, core.DateTime, core.TimeStamp, core.Time:
 | 
			
		||||
		return core.DateTime
 | 
			
		||||
	case core.TimeStampz:
 | 
			
		||||
		return core.Text
 | 
			
		||||
	case core.Char, core.Varchar, core.NVarchar, core.TinyText,
 | 
			
		||||
		core.Text, core.MediumText, core.LongText, core.Json:
 | 
			
		||||
		return core.Text
 | 
			
		||||
	case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt:
 | 
			
		||||
		return core.Integer
 | 
			
		||||
	case core.Float, core.Double, core.Real:
 | 
			
		||||
		return core.Real
 | 
			
		||||
	case core.Decimal, core.Numeric:
 | 
			
		||||
		return core.Numeric
 | 
			
		||||
	case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary:
 | 
			
		||||
		return core.Blob
 | 
			
		||||
	case core.Serial, core.BigSerial:
 | 
			
		||||
		c.IsPrimaryKey = true
 | 
			
		||||
		c.IsAutoIncrement = true
 | 
			
		||||
		c.Nullable = false
 | 
			
		||||
		return core.Integer
 | 
			
		||||
	default:
 | 
			
		||||
		return t
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) FormatBytes(bs []byte) string {
 | 
			
		||||
	return fmt.Sprintf("X'%x'", bs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) SupportInsertMany() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) IsReserved(name string) bool {
 | 
			
		||||
	_, ok := sqlite3ReservedWords[name]
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) Quote(name string) string {
 | 
			
		||||
	return "`" + name + "`"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) AutoIncrStr() string {
 | 
			
		||||
	return "AUTOINCREMENT"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) SupportEngine() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) SupportCharset() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) IndexOnTable() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{idxName}
 | 
			
		||||
	return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
 | 
			
		||||
	// var unique string
 | 
			
		||||
	quote := db.Quote
 | 
			
		||||
	idxName := index.Name
 | 
			
		||||
 | 
			
		||||
	if !strings.HasPrefix(idxName, "UQE_") &&
 | 
			
		||||
		!strings.HasPrefix(idxName, "IDX_") {
 | 
			
		||||
		if index.Type == core.UniqueType {
 | 
			
		||||
			idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
 | 
			
		||||
		} else {
 | 
			
		||||
			idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("DROP INDEX %v", quote(idxName))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) ForUpdateSql(query string) string {
 | 
			
		||||
	return query
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
 | 
			
		||||
	return sql, args
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
 | 
			
		||||
	db.LogSQL(query, args)
 | 
			
		||||
	rows, err := db.DB().Query(query, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	if rows.Next() {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	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 parseString(colStr string) (*core.Column, error) {
 | 
			
		||||
	fields := splitColStr(colStr)
 | 
			
		||||
	col := new(core.Column)
 | 
			
		||||
	col.Indexes = make(map[string]int)
 | 
			
		||||
	col.Nullable = true
 | 
			
		||||
	col.DefaultIsEmpty = true
 | 
			
		||||
 | 
			
		||||
	for idx, field := range fields {
 | 
			
		||||
		if idx == 0 {
 | 
			
		||||
			col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)
 | 
			
		||||
			continue
 | 
			
		||||
		} else if idx == 1 {
 | 
			
		||||
			col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		switch field {
 | 
			
		||||
		case "PRIMARY":
 | 
			
		||||
			col.IsPrimaryKey = true
 | 
			
		||||
		case "AUTOINCREMENT":
 | 
			
		||||
			col.IsAutoIncrement = true
 | 
			
		||||
		case "NULL":
 | 
			
		||||
			if fields[idx-1] == "NOT" {
 | 
			
		||||
				col.Nullable = false
 | 
			
		||||
			} else {
 | 
			
		||||
				col.Nullable = true
 | 
			
		||||
			}
 | 
			
		||||
		case "DEFAULT":
 | 
			
		||||
			col.Default = fields[idx+1]
 | 
			
		||||
			col.DefaultIsEmpty = false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return col, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 = ?"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	var name string
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		err = rows.Scan(&name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		return nil, nil, errors.New("no table named " + tableName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nStart := strings.Index(name, "(")
 | 
			
		||||
	nEnd := strings.LastIndex(name, ")")
 | 
			
		||||
	reg := regexp.MustCompile(`[^\(,\)]*(\([^\(]*\))?`)
 | 
			
		||||
	colCreates := reg.FindAllString(name[nStart+1:nEnd], -1)
 | 
			
		||||
	cols := make(map[string]*core.Column)
 | 
			
		||||
	colSeq := make([]string, 0)
 | 
			
		||||
 | 
			
		||||
	for _, colStr := range colCreates {
 | 
			
		||||
		reg = regexp.MustCompile(`,\s`)
 | 
			
		||||
		colStr = reg.ReplaceAllString(colStr, ",")
 | 
			
		||||
		if strings.HasPrefix(strings.TrimSpace(colStr), "PRIMARY KEY") {
 | 
			
		||||
			parts := strings.Split(strings.TrimSpace(colStr), "(")
 | 
			
		||||
			if len(parts) == 2 {
 | 
			
		||||
				pkCols := strings.Split(strings.TrimRight(strings.TrimSpace(parts[1]), ")"), ",")
 | 
			
		||||
				for _, pk := range pkCols {
 | 
			
		||||
					if col, ok := cols[strings.Trim(strings.TrimSpace(pk), "`")]; ok {
 | 
			
		||||
						col.IsPrimaryKey = true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		col, err := parseString(colStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return colSeq, cols, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cols[col.Name] = col
 | 
			
		||||
		colSeq = append(colSeq, col.Name)
 | 
			
		||||
	}
 | 
			
		||||
	return colSeq, cols, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) GetTables() ([]*core.Table, error) {
 | 
			
		||||
	args := []interface{}{}
 | 
			
		||||
	s := "SELECT name FROM sqlite_master WHERE type='table'"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	tables := make([]*core.Table, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		table := core.NewEmptyTable()
 | 
			
		||||
		err = rows.Scan(&table.Name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if table.Name == "sqlite_sequence" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		tables = append(tables, table)
 | 
			
		||||
	}
 | 
			
		||||
	return tables, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
 | 
			
		||||
	args := []interface{}{tableName}
 | 
			
		||||
	s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
 | 
			
		||||
	db.LogSQL(s, args)
 | 
			
		||||
 | 
			
		||||
	rows, err := db.DB().Query(s, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	indexes := make(map[string]*core.Index, 0)
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var tmpSQL sql.NullString
 | 
			
		||||
		err = rows.Scan(&tmpSQL)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !tmpSQL.Valid {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		sql := tmpSQL.String
 | 
			
		||||
 | 
			
		||||
		index := new(core.Index)
 | 
			
		||||
		nNStart := strings.Index(sql, "INDEX")
 | 
			
		||||
		nNEnd := strings.Index(sql, "ON")
 | 
			
		||||
		if nNStart == -1 || nNEnd == -1 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
 | 
			
		||||
		var isRegular bool
 | 
			
		||||
		if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
 | 
			
		||||
			index.Name = indexName[5+len(tableName):]
 | 
			
		||||
			isRegular = true
 | 
			
		||||
		} else {
 | 
			
		||||
			index.Name = indexName
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
 | 
			
		||||
			index.Type = core.UniqueType
 | 
			
		||||
		} else {
 | 
			
		||||
			index.Type = core.IndexType
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		nStart := strings.Index(sql, "(")
 | 
			
		||||
		nEnd := strings.Index(sql, ")")
 | 
			
		||||
		colIndexes := strings.Split(sql[nStart+1:nEnd], ",")
 | 
			
		||||
 | 
			
		||||
		index.Cols = make([]string, 0)
 | 
			
		||||
		for _, col := range colIndexes {
 | 
			
		||||
			index.Cols = append(index.Cols, strings.Trim(col, "` []"))
 | 
			
		||||
		}
 | 
			
		||||
		index.IsRegular = isRegular
 | 
			
		||||
		indexes[index.Name] = index
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return indexes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *sqlite3) Filters() []core.Filter {
 | 
			
		||||
	return []core.Filter{&core.IdFilter{}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type sqlite3Driver struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
 | 
			
		||||
	if strings.Contains(dataSourceName, "?") {
 | 
			
		||||
		dataSourceName = dataSourceName[:strings.Index(dataSourceName, "?")]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										184
									
								
								vendor/xorm.io/xorm/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								vendor/xorm.io/xorm/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,184 @@
 | 
			
		||||
// Copyright 2013 - 2016 The XORM Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
Package xorm is a simple and powerful ORM for Go.
 | 
			
		||||
 | 
			
		||||
Installation
 | 
			
		||||
 | 
			
		||||
Make sure you have installed Go 1.6+ and then:
 | 
			
		||||
 | 
			
		||||
    go get xorm.io/xorm
 | 
			
		||||
 | 
			
		||||
Create Engine
 | 
			
		||||
 | 
			
		||||
Firstly, we should new an engine for a database
 | 
			
		||||
 | 
			
		||||
    engine, err := xorm.NewEngine(driverName, dataSourceName)
 | 
			
		||||
 | 
			
		||||
Method NewEngine's parameters is the same as sql.Open. It depends
 | 
			
		||||
drivers' implementation.
 | 
			
		||||
Generally, one engine for an application is enough. You can set it as package variable.
 | 
			
		||||
 | 
			
		||||
Raw Methods
 | 
			
		||||
 | 
			
		||||
XORM also support raw SQL execution:
 | 
			
		||||
 | 
			
		||||
1. query a SQL string, the returned results is []map[string][]byte
 | 
			
		||||
 | 
			
		||||
    results, err := engine.Query("select * from user")
 | 
			
		||||
 | 
			
		||||
2. execute a SQL string, the returned results
 | 
			
		||||
 | 
			
		||||
    affected, err := engine.Exec("update user set .... where ...")
 | 
			
		||||
 | 
			
		||||
ORM Methods
 | 
			
		||||
 | 
			
		||||
There are 8 major ORM methods and many helpful methods to use to operate database.
 | 
			
		||||
 | 
			
		||||
1. Insert one or multiple records to database
 | 
			
		||||
 | 
			
		||||
    affected, err := engine.Insert(&struct)
 | 
			
		||||
    // INSERT INTO struct () values ()
 | 
			
		||||
    affected, err := engine.Insert(&struct1, &struct2)
 | 
			
		||||
    // INSERT INTO struct1 () values ()
 | 
			
		||||
    // INSERT INTO struct2 () values ()
 | 
			
		||||
    affected, err := engine.Insert(&sliceOfStruct)
 | 
			
		||||
    // INSERT INTO struct () values (),(),()
 | 
			
		||||
    affected, err := engine.Insert(&struct1, &sliceOfStruct2)
 | 
			
		||||
    // INSERT INTO struct1 () values ()
 | 
			
		||||
    // INSERT INTO struct2 () values (),(),()
 | 
			
		||||
 | 
			
		||||
2. Query one record or one variable from database
 | 
			
		||||
 | 
			
		||||
    has, err := engine.Get(&user)
 | 
			
		||||
    // SELECT * FROM user LIMIT 1
 | 
			
		||||
 | 
			
		||||
    var id int64
 | 
			
		||||
    has, err := engine.Table("user").Where("name = ?", name).Get(&id)
 | 
			
		||||
    // SELECT id FROM user WHERE name = ? LIMIT 1
 | 
			
		||||
 | 
			
		||||
3. Query multiple records from database
 | 
			
		||||
 | 
			
		||||
    var sliceOfStructs []Struct
 | 
			
		||||
    err := engine.Find(&sliceOfStructs)
 | 
			
		||||
    // SELECT * FROM user
 | 
			
		||||
 | 
			
		||||
    var mapOfStructs = make(map[int64]Struct)
 | 
			
		||||
    err := engine.Find(&mapOfStructs)
 | 
			
		||||
    // SELECT * FROM user
 | 
			
		||||
 | 
			
		||||
    var int64s []int64
 | 
			
		||||
    err := engine.Table("user").Cols("id").Find(&int64s)
 | 
			
		||||
    // SELECT id FROM user
 | 
			
		||||
 | 
			
		||||
4. Query multiple records and record by record handle, there two methods, one is Iterate,
 | 
			
		||||
another is Rows
 | 
			
		||||
 | 
			
		||||
    err := engine.Iterate(...)
 | 
			
		||||
    // SELECT * FROM user
 | 
			
		||||
 | 
			
		||||
    rows, err := engine.Rows(...)
 | 
			
		||||
    // SELECT * FROM user
 | 
			
		||||
    defer rows.Close()
 | 
			
		||||
    bean := new(Struct)
 | 
			
		||||
    for rows.Next() {
 | 
			
		||||
        err = rows.Scan(bean)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
5. Update one or more records
 | 
			
		||||
 | 
			
		||||
    affected, err := engine.ID(...).Update(&user)
 | 
			
		||||
    // UPDATE user SET ...
 | 
			
		||||
 | 
			
		||||
6. Delete one or more records, Delete MUST has condition
 | 
			
		||||
 | 
			
		||||
    affected, err := engine.Where(...).Delete(&user)
 | 
			
		||||
    // DELETE FROM user Where ...
 | 
			
		||||
 | 
			
		||||
7. Count records
 | 
			
		||||
 | 
			
		||||
    counts, err := engine.Count(&user)
 | 
			
		||||
    // SELECT count(*) AS total FROM user
 | 
			
		||||
 | 
			
		||||
    counts, err := engine.SQL("select count(*) FROM user").Count()
 | 
			
		||||
    // select count(*) FROM user
 | 
			
		||||
 | 
			
		||||
8. Sum records
 | 
			
		||||
 | 
			
		||||
    sumFloat64, err := engine.Sum(&user, "id")
 | 
			
		||||
    // SELECT sum(id) from user
 | 
			
		||||
 | 
			
		||||
    sumFloat64s, err := engine.Sums(&user, "id1", "id2")
 | 
			
		||||
    // SELECT sum(id1), sum(id2) from user
 | 
			
		||||
 | 
			
		||||
    sumInt64s, err := engine.SumsInt(&user, "id1", "id2")
 | 
			
		||||
    // SELECT sum(id1), sum(id2) from user
 | 
			
		||||
 | 
			
		||||
Conditions
 | 
			
		||||
 | 
			
		||||
The above 8 methods could use with condition methods chainable.
 | 
			
		||||
Attention: the above 8 methods should be the last chainable method.
 | 
			
		||||
 | 
			
		||||
1. ID, In
 | 
			
		||||
 | 
			
		||||
    engine.ID(1).Get(&user) // for single primary key
 | 
			
		||||
    // SELECT * FROM user WHERE id = 1
 | 
			
		||||
    engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys
 | 
			
		||||
    // SELECT * FROM user WHERE id1 = 1 AND id2 = 2
 | 
			
		||||
    engine.In("id", 1, 2, 3).Find(&users)
 | 
			
		||||
    // SELECT * FROM user WHERE id IN (1, 2, 3)
 | 
			
		||||
    engine.In("id", []int{1, 2, 3}).Find(&users)
 | 
			
		||||
    // SELECT * FROM user WHERE id IN (1, 2, 3)
 | 
			
		||||
 | 
			
		||||
2. Where, And, Or
 | 
			
		||||
 | 
			
		||||
    engine.Where().And().Or().Find()
 | 
			
		||||
    // SELECT * FROM user WHERE (.. AND ..) OR ...
 | 
			
		||||
 | 
			
		||||
3. OrderBy, Asc, Desc
 | 
			
		||||
 | 
			
		||||
    engine.Asc().Desc().Find()
 | 
			
		||||
    // SELECT * FROM user ORDER BY .. ASC, .. DESC
 | 
			
		||||
    engine.OrderBy().Find()
 | 
			
		||||
    // SELECT * FROM user ORDER BY ..
 | 
			
		||||
 | 
			
		||||
4. Limit, Top
 | 
			
		||||
 | 
			
		||||
    engine.Limit().Find()
 | 
			
		||||
    // SELECT * FROM user LIMIT .. OFFSET ..
 | 
			
		||||
    engine.Top(5).Find()
 | 
			
		||||
    // SELECT TOP 5 * FROM user // for mssql
 | 
			
		||||
    // SELECT * FROM user LIMIT .. OFFSET 0 //for other databases
 | 
			
		||||
 | 
			
		||||
5. SQL, let you custom SQL
 | 
			
		||||
 | 
			
		||||
    var users []User
 | 
			
		||||
    engine.SQL("select * from user").Find(&users)
 | 
			
		||||
 | 
			
		||||
6. Cols, Omit, Distinct
 | 
			
		||||
 | 
			
		||||
    var users []*User
 | 
			
		||||
    engine.Cols("col1, col2").Find(&users)
 | 
			
		||||
    // SELECT col1, col2 FROM user
 | 
			
		||||
    engine.Cols("col1", "col2").Where().Update(user)
 | 
			
		||||
    // UPDATE user set col1 = ?, col2 = ? Where ...
 | 
			
		||||
    engine.Omit("col1").Find(&users)
 | 
			
		||||
    // SELECT col2, col3 FROM user
 | 
			
		||||
    engine.Omit("col1").Insert(&user)
 | 
			
		||||
    // INSERT INTO table (non-col1) VALUES ()
 | 
			
		||||
    engine.Distinct("col1").Find(&users)
 | 
			
		||||
    // SELECT DISTINCT col1 FROM user
 | 
			
		||||
 | 
			
		||||
7. Join, GroupBy, Having
 | 
			
		||||
 | 
			
		||||
    engine.GroupBy("name").Having("name='xlw'").Find(&users)
 | 
			
		||||
    //SELECT * FROM user GROUP BY name HAVING name='xlw'
 | 
			
		||||
    engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find(&users)
 | 
			
		||||
    //SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id
 | 
			
		||||
 | 
			
		||||
More usage, please visit http://xorm.io/docs
 | 
			
		||||
*/
 | 
			
		||||
package xorm
 | 
			
		||||
							
								
								
									
										1659
									
								
								vendor/xorm.io/xorm/engine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1659
									
								
								vendor/xorm.io/xorm/engine.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										232
									
								
								vendor/xorm.io/xorm/engine_cond.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								vendor/xorm.io/xorm/engine_cond.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,232 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"database/sql/driver"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (engine *Engine) buildConds(table *core.Table, bean interface{},
 | 
			
		||||
	includeVersion bool, includeUpdated bool, includeNil bool,
 | 
			
		||||
	includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
 | 
			
		||||
	mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
 | 
			
		||||
	var conds []builder.Cond
 | 
			
		||||
	for _, col := range table.Columns() {
 | 
			
		||||
		if !includeVersion && col.IsVersion {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !includeUpdated && col.IsUpdated {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !includeAutoIncr && col.IsAutoIncrement {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if col.SQLType.IsJson() {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var colName string
 | 
			
		||||
		if addedTableName {
 | 
			
		||||
			var nm = tableName
 | 
			
		||||
			if len(aliasName) > 0 {
 | 
			
		||||
				nm = aliasName
 | 
			
		||||
			}
 | 
			
		||||
			colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
 | 
			
		||||
		} else {
 | 
			
		||||
			colName = engine.Quote(col.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fieldValuePtr, err := col.ValueOf(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if !strings.Contains(err.Error(), "is not valid") {
 | 
			
		||||
				engine.logger.Warn(err)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if col.IsDeleted && !unscoped { // tag "deleted" is enabled
 | 
			
		||||
			conds = append(conds, engine.CondDeleted(colName))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fieldValue := *fieldValuePtr
 | 
			
		||||
		if fieldValue.Interface() == nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fieldType := reflect.TypeOf(fieldValue.Interface())
 | 
			
		||||
		requiredField := useAllCols
 | 
			
		||||
 | 
			
		||||
		if b, ok := getFlagForColumn(mustColumnMap, col); ok {
 | 
			
		||||
			if b {
 | 
			
		||||
				requiredField = true
 | 
			
		||||
			} else {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if fieldType.Kind() == reflect.Ptr {
 | 
			
		||||
			if fieldValue.IsNil() {
 | 
			
		||||
				if includeNil {
 | 
			
		||||
					conds = append(conds, builder.Eq{colName: nil})
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			} else if !fieldValue.IsValid() {
 | 
			
		||||
				continue
 | 
			
		||||
			} else {
 | 
			
		||||
				// dereference ptr type to instance type
 | 
			
		||||
				fieldValue = fieldValue.Elem()
 | 
			
		||||
				fieldType = reflect.TypeOf(fieldValue.Interface())
 | 
			
		||||
				requiredField = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var val interface{}
 | 
			
		||||
		switch fieldType.Kind() {
 | 
			
		||||
		case reflect.Bool:
 | 
			
		||||
			if allUseBool || requiredField {
 | 
			
		||||
				val = fieldValue.Interface()
 | 
			
		||||
			} else {
 | 
			
		||||
				// if a bool in a struct, it will not be as a condition because it default is false,
 | 
			
		||||
				// please use Where() instead
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.String:
 | 
			
		||||
			if !requiredField && fieldValue.String() == "" {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// for MyString, should convert to string or panic
 | 
			
		||||
			if fieldType.String() != reflect.String.String() {
 | 
			
		||||
				val = fieldValue.String()
 | 
			
		||||
			} else {
 | 
			
		||||
				val = fieldValue.Interface()
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
 | 
			
		||||
			if !requiredField && fieldValue.Int() == 0 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			val = fieldValue.Interface()
 | 
			
		||||
		case reflect.Float32, reflect.Float64:
 | 
			
		||||
			if !requiredField && fieldValue.Float() == 0.0 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			val = fieldValue.Interface()
 | 
			
		||||
		case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
			if !requiredField && fieldValue.Uint() == 0 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			t := int64(fieldValue.Uint())
 | 
			
		||||
			val = reflect.ValueOf(&t).Interface()
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			if fieldType.ConvertibleTo(core.TimeType) {
 | 
			
		||||
				t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
 | 
			
		||||
				if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				val = engine.formatColTime(col, t)
 | 
			
		||||
			} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
 | 
			
		||||
				continue
 | 
			
		||||
			} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
 | 
			
		||||
				val, _ = valNul.Value()
 | 
			
		||||
				if val == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if col.SQLType.IsJson() {
 | 
			
		||||
					if col.SQLType.IsText() {
 | 
			
		||||
						bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							engine.logger.Error(err)
 | 
			
		||||
							continue
 | 
			
		||||
						}
 | 
			
		||||
						val = string(bytes)
 | 
			
		||||
					} else if col.SQLType.IsBlob() {
 | 
			
		||||
						var bytes []byte
 | 
			
		||||
						var err error
 | 
			
		||||
						bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							engine.logger.Error(err)
 | 
			
		||||
							continue
 | 
			
		||||
						}
 | 
			
		||||
						val = bytes
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					engine.autoMapType(fieldValue)
 | 
			
		||||
					if table, ok := engine.Tables[fieldValue.Type()]; ok {
 | 
			
		||||
						if len(table.PrimaryKeys) == 1 {
 | 
			
		||||
							pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
 | 
			
		||||
							// fix non-int pk issues
 | 
			
		||||
							//if pkField.Int() != 0 {
 | 
			
		||||
							if pkField.IsValid() && !isZero(pkField.Interface()) {
 | 
			
		||||
								val = pkField.Interface()
 | 
			
		||||
							} else {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
						} else {
 | 
			
		||||
							//TODO: how to handler?
 | 
			
		||||
							return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						val = fieldValue.Interface()
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Array:
 | 
			
		||||
			continue
 | 
			
		||||
		case reflect.Slice, reflect.Map:
 | 
			
		||||
			if fieldValue == reflect.Zero(fieldType) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if col.SQLType.IsText() {
 | 
			
		||||
				bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					engine.logger.Error(err)
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				val = string(bytes)
 | 
			
		||||
			} else if col.SQLType.IsBlob() {
 | 
			
		||||
				var bytes []byte
 | 
			
		||||
				var err error
 | 
			
		||||
				if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
 | 
			
		||||
					fieldType.Elem().Kind() == reflect.Uint8 {
 | 
			
		||||
					if fieldValue.Len() > 0 {
 | 
			
		||||
						val = fieldValue.Bytes()
 | 
			
		||||
					} else {
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						engine.logger.Error(err)
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
					val = bytes
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			val = fieldValue.Interface()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		conds = append(conds, builder.Eq{colName: val})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return builder.And(conds...), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/xorm.io/xorm/engine_context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/xorm.io/xorm/engine_context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// +build go1.8
 | 
			
		||||
 | 
			
		||||
package xorm
 | 
			
		||||
 | 
			
		||||
import "context"
 | 
			
		||||
 | 
			
		||||
// Context creates a session with the context
 | 
			
		||||
func (engine *Engine) Context(ctx context.Context) *Session {
 | 
			
		||||
	session := engine.NewSession()
 | 
			
		||||
	session.isAutoClose = true
 | 
			
		||||
	return session.Context(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDefaultContext set the default context
 | 
			
		||||
func (engine *Engine) SetDefaultContext(ctx context.Context) {
 | 
			
		||||
	engine.defaultContext = ctx
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PingContext tests if database is alive
 | 
			
		||||
func (engine *Engine) PingContext(ctx context.Context) error {
 | 
			
		||||
	session := engine.NewSession()
 | 
			
		||||
	defer session.Close()
 | 
			
		||||
	return session.PingContext(ctx)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										219
									
								
								vendor/xorm.io/xorm/engine_group.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								vendor/xorm.io/xorm/engine_group.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,219 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"context"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// EngineGroup defines an engine group
 | 
			
		||||
type EngineGroup struct {
 | 
			
		||||
	*Engine
 | 
			
		||||
	slaves []*Engine
 | 
			
		||||
	policy GroupPolicy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewEngineGroup creates a new engine group
 | 
			
		||||
func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) {
 | 
			
		||||
	var eg EngineGroup
 | 
			
		||||
	if len(policies) > 0 {
 | 
			
		||||
		eg.policy = policies[0]
 | 
			
		||||
	} else {
 | 
			
		||||
		eg.policy = RoundRobinPolicy()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	driverName, ok1 := args1.(string)
 | 
			
		||||
	conns, ok2 := args2.([]string)
 | 
			
		||||
	if ok1 && ok2 {
 | 
			
		||||
		engines := make([]*Engine, len(conns))
 | 
			
		||||
		for i, conn := range conns {
 | 
			
		||||
			engine, err := NewEngine(driverName, conn)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			engine.engineGroup = &eg
 | 
			
		||||
			engines[i] = engine
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		eg.Engine = engines[0]
 | 
			
		||||
		eg.slaves = engines[1:]
 | 
			
		||||
		return &eg, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	master, ok3 := args1.(*Engine)
 | 
			
		||||
	slaves, ok4 := args2.([]*Engine)
 | 
			
		||||
	if ok3 && ok4 {
 | 
			
		||||
		master.engineGroup = &eg
 | 
			
		||||
		for i := 0; i < len(slaves); i++ {
 | 
			
		||||
			slaves[i].engineGroup = &eg
 | 
			
		||||
		}
 | 
			
		||||
		eg.Engine = master
 | 
			
		||||
		eg.slaves = slaves
 | 
			
		||||
		return &eg, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, ErrParamsType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close the engine
 | 
			
		||||
func (eg *EngineGroup) Close() error {
 | 
			
		||||
	err := eg.Engine.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		err := eg.slaves[i].Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Context returned a group session
 | 
			
		||||
func (eg *EngineGroup) Context(ctx context.Context) *Session {
 | 
			
		||||
	sess := eg.NewSession()
 | 
			
		||||
	sess.isAutoClose = true
 | 
			
		||||
	return sess.Context(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSession returned a group session
 | 
			
		||||
func (eg *EngineGroup) NewSession() *Session {
 | 
			
		||||
	sess := eg.Engine.NewSession()
 | 
			
		||||
	sess.sessionType = groupSession
 | 
			
		||||
	return sess
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Master returns the master engine
 | 
			
		||||
func (eg *EngineGroup) Master() *Engine {
 | 
			
		||||
	return eg.Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ping tests if database is alive
 | 
			
		||||
func (eg *EngineGroup) Ping() error {
 | 
			
		||||
	if err := eg.Engine.Ping(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, slave := range eg.slaves {
 | 
			
		||||
		if err := slave.Ping(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetColumnMapper set the column name mapping rule
 | 
			
		||||
func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) {
 | 
			
		||||
	eg.Engine.ColumnMapper = mapper
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].ColumnMapper = mapper
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
 | 
			
		||||
func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
 | 
			
		||||
	eg.Engine.SetConnMaxLifetime(d)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].SetConnMaxLifetime(d)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDefaultCacher set the default cacher
 | 
			
		||||
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
 | 
			
		||||
	eg.Engine.SetDefaultCacher(cacher)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].SetDefaultCacher(cacher)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetLogger set the new logger
 | 
			
		||||
func (eg *EngineGroup) SetLogger(logger core.ILogger) {
 | 
			
		||||
	eg.Engine.SetLogger(logger)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].SetLogger(logger)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetLogLevel sets the logger level
 | 
			
		||||
func (eg *EngineGroup) SetLogLevel(level core.LogLevel) {
 | 
			
		||||
	eg.Engine.SetLogLevel(level)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].SetLogLevel(level)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetMapper set the name mapping rules
 | 
			
		||||
func (eg *EngineGroup) SetMapper(mapper core.IMapper) {
 | 
			
		||||
	eg.Engine.SetMapper(mapper)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].SetMapper(mapper)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetMaxIdleConns set the max idle connections on pool, default is 2
 | 
			
		||||
func (eg *EngineGroup) SetMaxIdleConns(conns int) {
 | 
			
		||||
	eg.Engine.db.SetMaxIdleConns(conns)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].db.SetMaxIdleConns(conns)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetMaxOpenConns is only available for go 1.2+
 | 
			
		||||
func (eg *EngineGroup) SetMaxOpenConns(conns int) {
 | 
			
		||||
	eg.Engine.db.SetMaxOpenConns(conns)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].db.SetMaxOpenConns(conns)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetPolicy set the group policy
 | 
			
		||||
func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
 | 
			
		||||
	eg.policy = policy
 | 
			
		||||
	return eg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetTableMapper set the table name mapping rule
 | 
			
		||||
func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) {
 | 
			
		||||
	eg.Engine.TableMapper = mapper
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].TableMapper = mapper
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
 | 
			
		||||
func (eg *EngineGroup) ShowExecTime(show ...bool) {
 | 
			
		||||
	eg.Engine.ShowExecTime(show...)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].ShowExecTime(show...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ShowSQL show SQL statement or not on logger if log level is great than INFO
 | 
			
		||||
func (eg *EngineGroup) ShowSQL(show ...bool) {
 | 
			
		||||
	eg.Engine.ShowSQL(show...)
 | 
			
		||||
	for i := 0; i < len(eg.slaves); i++ {
 | 
			
		||||
		eg.slaves[i].ShowSQL(show...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slave returns one of the physical databases which is a slave according the policy
 | 
			
		||||
func (eg *EngineGroup) Slave() *Engine {
 | 
			
		||||
	switch len(eg.slaves) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return eg.Engine
 | 
			
		||||
	case 1:
 | 
			
		||||
		return eg.slaves[0]
 | 
			
		||||
	}
 | 
			
		||||
	return eg.policy.Slave(eg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slaves returns all the slaves
 | 
			
		||||
func (eg *EngineGroup) Slaves() []*Engine {
 | 
			
		||||
	return eg.slaves
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								vendor/xorm.io/xorm/engine_group_policy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								vendor/xorm.io/xorm/engine_group_policy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GroupPolicy is be used by chosing the current slave from slaves
 | 
			
		||||
type GroupPolicy interface {
 | 
			
		||||
	Slave(*EngineGroup) *Engine
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GroupPolicyHandler should be used when a function is a GroupPolicy
 | 
			
		||||
type GroupPolicyHandler func(*EngineGroup) *Engine
 | 
			
		||||
 | 
			
		||||
// Slave implements the chosen of slaves
 | 
			
		||||
func (h GroupPolicyHandler) Slave(eg *EngineGroup) *Engine {
 | 
			
		||||
	return h(eg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RandomPolicy implmentes randomly chose the slave of slaves
 | 
			
		||||
func RandomPolicy() GroupPolicyHandler {
 | 
			
		||||
	var r = rand.New(rand.NewSource(time.Now().UnixNano()))
 | 
			
		||||
	return func(g *EngineGroup) *Engine {
 | 
			
		||||
		return g.Slaves()[r.Intn(len(g.Slaves()))]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WeightRandomPolicy implmentes randomly chose the slave of slaves
 | 
			
		||||
func WeightRandomPolicy(weights []int) GroupPolicyHandler {
 | 
			
		||||
	var rands = make([]int, 0, len(weights))
 | 
			
		||||
	for i := 0; i < len(weights); i++ {
 | 
			
		||||
		for n := 0; n < weights[i]; n++ {
 | 
			
		||||
			rands = append(rands, i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var r = rand.New(rand.NewSource(time.Now().UnixNano()))
 | 
			
		||||
 | 
			
		||||
	return func(g *EngineGroup) *Engine {
 | 
			
		||||
		var slaves = g.Slaves()
 | 
			
		||||
		idx := rands[r.Intn(len(rands))]
 | 
			
		||||
		if idx >= len(slaves) {
 | 
			
		||||
			idx = len(slaves) - 1
 | 
			
		||||
		}
 | 
			
		||||
		return slaves[idx]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RoundRobinPolicy() GroupPolicyHandler {
 | 
			
		||||
	var pos = -1
 | 
			
		||||
	var lock sync.Mutex
 | 
			
		||||
	return func(g *EngineGroup) *Engine {
 | 
			
		||||
		var slaves = g.Slaves()
 | 
			
		||||
 | 
			
		||||
		lock.Lock()
 | 
			
		||||
		defer lock.Unlock()
 | 
			
		||||
		pos++
 | 
			
		||||
		if pos >= len(slaves) {
 | 
			
		||||
			pos = 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return slaves[pos]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
 | 
			
		||||
	var rands = make([]int, 0, len(weights))
 | 
			
		||||
	for i := 0; i < len(weights); i++ {
 | 
			
		||||
		for n := 0; n < weights[i]; n++ {
 | 
			
		||||
			rands = append(rands, i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var pos = -1
 | 
			
		||||
	var lock sync.Mutex
 | 
			
		||||
 | 
			
		||||
	return func(g *EngineGroup) *Engine {
 | 
			
		||||
		var slaves = g.Slaves()
 | 
			
		||||
		lock.Lock()
 | 
			
		||||
		defer lock.Unlock()
 | 
			
		||||
		pos++
 | 
			
		||||
		if pos >= len(rands) {
 | 
			
		||||
			pos = 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		idx := rands[pos]
 | 
			
		||||
		if idx >= len(slaves) {
 | 
			
		||||
			idx = len(slaves) - 1
 | 
			
		||||
		}
 | 
			
		||||
		return slaves[idx]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave
 | 
			
		||||
func LeastConnPolicy() GroupPolicyHandler {
 | 
			
		||||
	return func(g *EngineGroup) *Engine {
 | 
			
		||||
		var slaves = g.Slaves()
 | 
			
		||||
		connections := 0
 | 
			
		||||
		idx := 0
 | 
			
		||||
		for i := 0; i < len(slaves); i++ {
 | 
			
		||||
			openConnections := slaves[i].DB().Stats().OpenConnections
 | 
			
		||||
			if i == 0 {
 | 
			
		||||
				connections = openConnections
 | 
			
		||||
				idx = i
 | 
			
		||||
			} else if openConnections <= connections {
 | 
			
		||||
				connections = openConnections
 | 
			
		||||
				idx = i
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return slaves[idx]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										113
									
								
								vendor/xorm.io/xorm/engine_table.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								vendor/xorm.io/xorm/engine_table.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
// Copyright 2018 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"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// tbNameWithSchema will automatically add schema prefix on table name
 | 
			
		||||
func (engine *Engine) tbNameWithSchema(v string) string {
 | 
			
		||||
	// Add schema name as prefix of table name.
 | 
			
		||||
	// Only for postgres database.
 | 
			
		||||
	if engine.dialect.DBType() == core.POSTGRES &&
 | 
			
		||||
		engine.dialect.URI().Schema != "" &&
 | 
			
		||||
		engine.dialect.URI().Schema != postgresPublicSchema &&
 | 
			
		||||
		strings.Index(v, ".") == -1 {
 | 
			
		||||
		return engine.dialect.URI().Schema + "." + v
 | 
			
		||||
	}
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TableName returns table name with schema prefix if has
 | 
			
		||||
func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
 | 
			
		||||
	tbName := engine.tbNameNoSchema(bean)
 | 
			
		||||
	if len(includeSchema) > 0 && includeSchema[0] {
 | 
			
		||||
		tbName = engine.tbNameWithSchema(tbName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tbName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tbName get some table's table name
 | 
			
		||||
func (session *Session) tbNameNoSchema(table *core.Table) string {
 | 
			
		||||
	if len(session.statement.AltTableName) > 0 {
 | 
			
		||||
		return session.statement.AltTableName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return table.Name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (engine *Engine) tbNameForMap(v reflect.Value) string {
 | 
			
		||||
	if v.Type().Implements(tpTableName) {
 | 
			
		||||
		return v.Interface().(TableName).TableName()
 | 
			
		||||
	}
 | 
			
		||||
	if v.Kind() == reflect.Ptr {
 | 
			
		||||
		v = v.Elem()
 | 
			
		||||
		if v.Type().Implements(tpTableName) {
 | 
			
		||||
			return v.Interface().(TableName).TableName()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return engine.TableMapper.Obj2Table(v.Type().Name())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
 | 
			
		||||
	switch tablename.(type) {
 | 
			
		||||
	case []string:
 | 
			
		||||
		t := tablename.([]string)
 | 
			
		||||
		if len(t) > 1 {
 | 
			
		||||
			return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
 | 
			
		||||
		} else if len(t) == 1 {
 | 
			
		||||
			return engine.Quote(t[0])
 | 
			
		||||
		}
 | 
			
		||||
	case []interface{}:
 | 
			
		||||
		t := tablename.([]interface{})
 | 
			
		||||
		l := len(t)
 | 
			
		||||
		var table string
 | 
			
		||||
		if l > 0 {
 | 
			
		||||
			f := t[0]
 | 
			
		||||
			switch f.(type) {
 | 
			
		||||
			case string:
 | 
			
		||||
				table = f.(string)
 | 
			
		||||
			case TableName:
 | 
			
		||||
				table = f.(TableName).TableName()
 | 
			
		||||
			default:
 | 
			
		||||
				v := rValue(f)
 | 
			
		||||
				t := v.Type()
 | 
			
		||||
				if t.Kind() == reflect.Struct {
 | 
			
		||||
					table = engine.tbNameForMap(v)
 | 
			
		||||
				} else {
 | 
			
		||||
					table = engine.Quote(fmt.Sprintf("%v", f))
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if l > 1 {
 | 
			
		||||
			return fmt.Sprintf("%v AS %v", engine.Quote(table),
 | 
			
		||||
				engine.Quote(fmt.Sprintf("%v", t[1])))
 | 
			
		||||
		} else if l == 1 {
 | 
			
		||||
			return engine.Quote(table)
 | 
			
		||||
		}
 | 
			
		||||
	case TableName:
 | 
			
		||||
		return tablename.(TableName).TableName()
 | 
			
		||||
	case string:
 | 
			
		||||
		return tablename.(string)
 | 
			
		||||
	case reflect.Value:
 | 
			
		||||
		v := tablename.(reflect.Value)
 | 
			
		||||
		return engine.tbNameForMap(v)
 | 
			
		||||
	default:
 | 
			
		||||
		v := rValue(tablename)
 | 
			
		||||
		t := v.Type()
 | 
			
		||||
		if t.Kind() == reflect.Struct {
 | 
			
		||||
			return engine.tbNameForMap(v)
 | 
			
		||||
		}
 | 
			
		||||
		return engine.Quote(fmt.Sprintf("%v", tablename))
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								vendor/xorm.io/xorm/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/xorm.io/xorm/error.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// ErrParamsType params error
 | 
			
		||||
	ErrParamsType = errors.New("Params type error")
 | 
			
		||||
	// ErrTableNotFound table not found error
 | 
			
		||||
	ErrTableNotFound = errors.New("Table not found")
 | 
			
		||||
	// ErrUnSupportedType unsupported error
 | 
			
		||||
	ErrUnSupportedType = errors.New("Unsupported type error")
 | 
			
		||||
	// ErrNotExist record does not exist error
 | 
			
		||||
	ErrNotExist = errors.New("Record does not exist")
 | 
			
		||||
	// ErrCacheFailed cache failed error
 | 
			
		||||
	ErrCacheFailed = errors.New("Cache failed")
 | 
			
		||||
	// ErrNeedDeletedCond delete needs less one condition error
 | 
			
		||||
	ErrNeedDeletedCond = errors.New("Delete action needs at least one condition")
 | 
			
		||||
	// ErrNotImplemented not implemented
 | 
			
		||||
	ErrNotImplemented = errors.New("Not implemented")
 | 
			
		||||
	// ErrConditionType condition type unsupported
 | 
			
		||||
	ErrConditionType = errors.New("Unsupported condition type")
 | 
			
		||||
	// ErrUnSupportedSQLType parameter of SQL is not supported
 | 
			
		||||
	ErrUnSupportedSQLType = errors.New("unsupported sql type")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrFieldIsNotExist columns does not exist
 | 
			
		||||
type ErrFieldIsNotExist struct {
 | 
			
		||||
	FieldName string
 | 
			
		||||
	TableName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e ErrFieldIsNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrFieldIsNotValid is not valid
 | 
			
		||||
type ErrFieldIsNotValid struct {
 | 
			
		||||
	FieldName string
 | 
			
		||||
	TableName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e ErrFieldIsNotValid) Error() string {
 | 
			
		||||
	return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/xorm.io/xorm/gen_reserved.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/xorm.io/xorm/gen_reserved.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
if [ -f $1 ];then
 | 
			
		||||
    cat $1| awk '{printf("\""$1"\":true,\n")}' 
 | 
			
		||||
else
 | 
			
		||||
    echo "argument $1 if not a file!"
 | 
			
		||||
fi
 | 
			
		||||
							
								
								
									
										15
									
								
								vendor/xorm.io/xorm/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/xorm.io/xorm/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
module xorm.io/xorm
 | 
			
		||||
 | 
			
		||||
go 1.11
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4
 | 
			
		||||
	github.com/go-sql-driver/mysql v1.4.1
 | 
			
		||||
	github.com/kr/pretty v0.1.0 // indirect
 | 
			
		||||
	github.com/lib/pq v1.0.0
 | 
			
		||||
	github.com/mattn/go-sqlite3 v1.10.0
 | 
			
		||||
	github.com/stretchr/testify v1.4.0
 | 
			
		||||
	github.com/ziutek/mymysql v1.5.4
 | 
			
		||||
	xorm.io/builder v0.3.6
 | 
			
		||||
	xorm.io/core v0.7.2
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										149
									
								
								vendor/xorm.io/xorm/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								vendor/xorm.io/xorm/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
cloud.google.com/go v0.26.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/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
 | 
			
		||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 | 
			
		||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 | 
			
		||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
 | 
			
		||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 | 
			
		||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 | 
			
		||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 | 
			
		||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 | 
			
		||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 | 
			
		||||
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=
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
 | 
			
		||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 | 
			
		||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 | 
			
		||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
 | 
			
		||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
			
		||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
			
		||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 | 
			
		||||
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-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/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/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=
 | 
			
		||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 | 
			
		||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 | 
			
		||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 | 
			
		||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 | 
			
		||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
 | 
			
		||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 | 
			
		||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 | 
			
		||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
			
		||||
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=
 | 
			
		||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 | 
			
		||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 | 
			
		||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 | 
			
		||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
			
		||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
			
		||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 | 
			
		||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
 | 
			
		||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 | 
			
		||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 | 
			
		||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
 | 
			
		||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 | 
			
		||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 | 
			
		||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 | 
			
		||||
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/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 | 
			
		||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
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=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
			
		||||
golang.org/x/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=
 | 
			
		||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 | 
			
		||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
			
		||||
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/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/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/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-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=
 | 
			
		||||
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/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=
 | 
			
		||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 | 
			
		||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 | 
			
		||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 | 
			
		||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
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.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
 | 
			
		||||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
 | 
			
		||||
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
 | 
			
		||||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
 | 
			
		||||
							
								
								
									
										332
									
								
								vendor/xorm.io/xorm/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								vendor/xorm.io/xorm/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,332 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// str2PK convert string value to primary key value according to tp
 | 
			
		||||
func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var result interface{}
 | 
			
		||||
	var defReturn = reflect.Zero(tp)
 | 
			
		||||
 | 
			
		||||
	switch tp.Kind() {
 | 
			
		||||
	case reflect.Int:
 | 
			
		||||
		result, err = strconv.Atoi(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Int8:
 | 
			
		||||
		x, err := strconv.Atoi(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		result = int8(x)
 | 
			
		||||
	case reflect.Int16:
 | 
			
		||||
		x, err := strconv.Atoi(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		result = int16(x)
 | 
			
		||||
	case reflect.Int32:
 | 
			
		||||
		x, err := strconv.Atoi(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		result = int32(x)
 | 
			
		||||
	case reflect.Int64:
 | 
			
		||||
		result, err = strconv.ParseInt(s, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Uint:
 | 
			
		||||
		x, err := strconv.ParseUint(s, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		result = uint(x)
 | 
			
		||||
	case reflect.Uint8:
 | 
			
		||||
		x, err := strconv.ParseUint(s, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		result = uint8(x)
 | 
			
		||||
	case reflect.Uint16:
 | 
			
		||||
		x, err := strconv.ParseUint(s, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		result = uint16(x)
 | 
			
		||||
	case reflect.Uint32:
 | 
			
		||||
		x, err := strconv.ParseUint(s, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		result = uint32(x)
 | 
			
		||||
	case reflect.Uint64:
 | 
			
		||||
		result, err = strconv.ParseUint(s, 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		result = s
 | 
			
		||||
	default:
 | 
			
		||||
		return defReturn, errors.New("unsupported convert type")
 | 
			
		||||
	}
 | 
			
		||||
	return reflect.ValueOf(result).Convert(tp), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func str2PK(s string, tp reflect.Type) (interface{}, error) {
 | 
			
		||||
	v, err := str2PKValue(s, tp)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return v.Interface(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func splitTag(tag string) (tags []string) {
 | 
			
		||||
	tag = strings.TrimSpace(tag)
 | 
			
		||||
	var hasQuote = false
 | 
			
		||||
	var lastIdx = 0
 | 
			
		||||
	for i, t := range tag {
 | 
			
		||||
		if t == '\'' {
 | 
			
		||||
			hasQuote = !hasQuote
 | 
			
		||||
		} else if t == ' ' {
 | 
			
		||||
			if lastIdx < i && !hasQuote {
 | 
			
		||||
				tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
 | 
			
		||||
				lastIdx = i + 1
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if lastIdx < len(tag) {
 | 
			
		||||
		tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type zeroable interface {
 | 
			
		||||
	IsZero() bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isZero(k interface{}) bool {
 | 
			
		||||
	switch k.(type) {
 | 
			
		||||
	case int:
 | 
			
		||||
		return k.(int) == 0
 | 
			
		||||
	case int8:
 | 
			
		||||
		return k.(int8) == 0
 | 
			
		||||
	case int16:
 | 
			
		||||
		return k.(int16) == 0
 | 
			
		||||
	case int32:
 | 
			
		||||
		return k.(int32) == 0
 | 
			
		||||
	case int64:
 | 
			
		||||
		return k.(int64) == 0
 | 
			
		||||
	case uint:
 | 
			
		||||
		return k.(uint) == 0
 | 
			
		||||
	case uint8:
 | 
			
		||||
		return k.(uint8) == 0
 | 
			
		||||
	case uint16:
 | 
			
		||||
		return k.(uint16) == 0
 | 
			
		||||
	case uint32:
 | 
			
		||||
		return k.(uint32) == 0
 | 
			
		||||
	case uint64:
 | 
			
		||||
		return k.(uint64) == 0
 | 
			
		||||
	case float32:
 | 
			
		||||
		return k.(float32) == 0
 | 
			
		||||
	case float64:
 | 
			
		||||
		return k.(float64) == 0
 | 
			
		||||
	case bool:
 | 
			
		||||
		return k.(bool) == false
 | 
			
		||||
	case string:
 | 
			
		||||
		return k.(string) == ""
 | 
			
		||||
	case zeroable:
 | 
			
		||||
		return k.(zeroable).IsZero()
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isStructZero(v reflect.Value) bool {
 | 
			
		||||
	if !v.IsValid() {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < v.NumField(); i++ {
 | 
			
		||||
		field := v.Field(i)
 | 
			
		||||
		switch field.Kind() {
 | 
			
		||||
		case reflect.Ptr:
 | 
			
		||||
			field = field.Elem()
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			if !isStructZero(field) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			if field.CanInterface() && !isZero(field.Interface()) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isArrayValueZero(v reflect.Value) bool {
 | 
			
		||||
	if !v.IsValid() || v.Len() == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < v.Len(); i++ {
 | 
			
		||||
		if !isZero(v.Index(i).Interface()) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
 | 
			
		||||
	var v interface{}
 | 
			
		||||
	kind := tp.Kind()
 | 
			
		||||
 | 
			
		||||
	if kind == reflect.Ptr {
 | 
			
		||||
		kind = tp.Elem().Kind()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch kind {
 | 
			
		||||
	case reflect.Int16:
 | 
			
		||||
		temp := int16(id)
 | 
			
		||||
		v = &temp
 | 
			
		||||
	case reflect.Int32:
 | 
			
		||||
		temp := int32(id)
 | 
			
		||||
		v = &temp
 | 
			
		||||
	case reflect.Int:
 | 
			
		||||
		temp := int(id)
 | 
			
		||||
		v = &temp
 | 
			
		||||
	case reflect.Int64:
 | 
			
		||||
		temp := id
 | 
			
		||||
		v = &temp
 | 
			
		||||
	case reflect.Uint16:
 | 
			
		||||
		temp := uint16(id)
 | 
			
		||||
		v = &temp
 | 
			
		||||
	case reflect.Uint32:
 | 
			
		||||
		temp := uint32(id)
 | 
			
		||||
		v = &temp
 | 
			
		||||
	case reflect.Uint64:
 | 
			
		||||
		temp := uint64(id)
 | 
			
		||||
		v = &temp
 | 
			
		||||
	case reflect.Uint:
 | 
			
		||||
		temp := uint(id)
 | 
			
		||||
		v = &temp
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if tp.Kind() == reflect.Ptr {
 | 
			
		||||
		return reflect.ValueOf(v).Convert(tp)
 | 
			
		||||
	}
 | 
			
		||||
	return reflect.ValueOf(v).Elem().Convert(tp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func int64ToInt(id int64, tp reflect.Type) interface{} {
 | 
			
		||||
	return int64ToIntValue(id, tp).Interface()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isPKZero(pk core.PK) bool {
 | 
			
		||||
	for _, k := range pk {
 | 
			
		||||
		if isZero(k) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func indexNoCase(s, sep string) int {
 | 
			
		||||
	return strings.Index(strings.ToLower(s), strings.ToLower(sep))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func splitNoCase(s, sep string) []string {
 | 
			
		||||
	idx := indexNoCase(s, sep)
 | 
			
		||||
	if idx < 0 {
 | 
			
		||||
		return []string{s}
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Split(s, s[idx:idx+len(sep)])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func splitNNoCase(s, sep string, n int) []string {
 | 
			
		||||
	idx := indexNoCase(s, sep)
 | 
			
		||||
	if idx < 0 {
 | 
			
		||||
		return []string{s}
 | 
			
		||||
	}
 | 
			
		||||
	return strings.SplitN(s, s[idx:idx+len(sep)], n)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeArray(elem string, count int) []string {
 | 
			
		||||
	res := make([]string, count)
 | 
			
		||||
	for i := 0; i < count; i++ {
 | 
			
		||||
		res[i] = elem
 | 
			
		||||
	}
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rValue(bean interface{}) reflect.Value {
 | 
			
		||||
	return reflect.Indirect(reflect.ValueOf(bean))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rType(bean interface{}) reflect.Type {
 | 
			
		||||
	sliceValue := reflect.Indirect(reflect.ValueOf(bean))
 | 
			
		||||
	// return reflect.TypeOf(sliceValue.Interface())
 | 
			
		||||
	return sliceValue.Type()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func structName(v reflect.Type) string {
 | 
			
		||||
	for v.Kind() == reflect.Ptr {
 | 
			
		||||
		v = v.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	return v.Name()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sliceEq(left, right []string) bool {
 | 
			
		||||
	if len(left) != len(right) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	sort.Sort(sort.StringSlice(left))
 | 
			
		||||
	sort.Sort(sort.StringSlice(right))
 | 
			
		||||
	for i := 0; i < len(left); i++ {
 | 
			
		||||
		if left[i] != right[i] {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func indexName(tableName, idxName string) string {
 | 
			
		||||
	return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func eraseAny(value string, strToErase ...string) string {
 | 
			
		||||
	if len(strToErase) == 0 {
 | 
			
		||||
		return value
 | 
			
		||||
	}
 | 
			
		||||
	var replaceSeq []string
 | 
			
		||||
	for _, s := range strToErase {
 | 
			
		||||
		replaceSeq = append(replaceSeq, s, "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	replacer := strings.NewReplacer(replaceSeq...)
 | 
			
		||||
 | 
			
		||||
	return replacer.Replace(value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func quoteColumns(cols []string, quoteFunc func(string) string, sep string) string {
 | 
			
		||||
	for i := range cols {
 | 
			
		||||
		cols[i] = quoteFunc(cols[i])
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(cols, sep+" ")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/xorm.io/xorm/helpler_time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/xorm.io/xorm/helpler_time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
// Copyright 2017 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 "time"
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	zeroTime0 = "0000-00-00 00:00:00"
 | 
			
		||||
	zeroTime1 = "0001-01-01 00:00:00"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func formatTime(t time.Time) string {
 | 
			
		||||
	return t.Format("2006-01-02 15:04:05")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isTimeZero(t time.Time) bool {
 | 
			
		||||
	return t.IsZero() || formatTime(t) == zeroTime0 ||
 | 
			
		||||
		formatTime(t) == zeroTime1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										118
									
								
								vendor/xorm.io/xorm/interface.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								vendor/xorm.io/xorm/interface.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"context"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Interface defines the interface which Engine, EngineGroup and Session will implementate.
 | 
			
		||||
type Interface interface {
 | 
			
		||||
	AllCols() *Session
 | 
			
		||||
	Alias(alias string) *Session
 | 
			
		||||
	Asc(colNames ...string) *Session
 | 
			
		||||
	BufferSize(size int) *Session
 | 
			
		||||
	Cols(columns ...string) *Session
 | 
			
		||||
	Count(...interface{}) (int64, error)
 | 
			
		||||
	CreateIndexes(bean interface{}) error
 | 
			
		||||
	CreateUniques(bean interface{}) error
 | 
			
		||||
	Decr(column string, arg ...interface{}) *Session
 | 
			
		||||
	Desc(...string) *Session
 | 
			
		||||
	Delete(interface{}) (int64, error)
 | 
			
		||||
	Distinct(columns ...string) *Session
 | 
			
		||||
	DropIndexes(bean interface{}) error
 | 
			
		||||
	Exec(sqlOrArgs ...interface{}) (sql.Result, error)
 | 
			
		||||
	Exist(bean ...interface{}) (bool, error)
 | 
			
		||||
	Find(interface{}, ...interface{}) error
 | 
			
		||||
	FindAndCount(interface{}, ...interface{}) (int64, error)
 | 
			
		||||
	Get(interface{}) (bool, error)
 | 
			
		||||
	GroupBy(keys string) *Session
 | 
			
		||||
	ID(interface{}) *Session
 | 
			
		||||
	In(string, ...interface{}) *Session
 | 
			
		||||
	Incr(column string, arg ...interface{}) *Session
 | 
			
		||||
	Insert(...interface{}) (int64, error)
 | 
			
		||||
	InsertOne(interface{}) (int64, error)
 | 
			
		||||
	IsTableEmpty(bean interface{}) (bool, error)
 | 
			
		||||
	IsTableExist(beanOrTableName interface{}) (bool, error)
 | 
			
		||||
	Iterate(interface{}, IterFunc) error
 | 
			
		||||
	Limit(int, ...int) *Session
 | 
			
		||||
	MustCols(columns ...string) *Session
 | 
			
		||||
	NoAutoCondition(...bool) *Session
 | 
			
		||||
	NotIn(string, ...interface{}) *Session
 | 
			
		||||
	Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session
 | 
			
		||||
	Omit(columns ...string) *Session
 | 
			
		||||
	OrderBy(order string) *Session
 | 
			
		||||
	Ping() error
 | 
			
		||||
	Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error)
 | 
			
		||||
	QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error)
 | 
			
		||||
	QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error)
 | 
			
		||||
	Rows(bean interface{}) (*Rows, error)
 | 
			
		||||
	SetExpr(string, interface{}) *Session
 | 
			
		||||
	SQL(interface{}, ...interface{}) *Session
 | 
			
		||||
	Sum(bean interface{}, colName string) (float64, error)
 | 
			
		||||
	SumInt(bean interface{}, colName string) (int64, error)
 | 
			
		||||
	Sums(bean interface{}, colNames ...string) ([]float64, error)
 | 
			
		||||
	SumsInt(bean interface{}, colNames ...string) ([]int64, error)
 | 
			
		||||
	Table(tableNameOrBean interface{}) *Session
 | 
			
		||||
	Unscoped() *Session
 | 
			
		||||
	Update(bean interface{}, condiBeans ...interface{}) (int64, error)
 | 
			
		||||
	UseBool(...string) *Session
 | 
			
		||||
	Where(interface{}, ...interface{}) *Session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EngineInterface defines the interface which Engine, EngineGroup will implementate.
 | 
			
		||||
type EngineInterface interface {
 | 
			
		||||
	Interface
 | 
			
		||||
 | 
			
		||||
	Before(func(interface{})) *Session
 | 
			
		||||
	Charset(charset string) *Session
 | 
			
		||||
	ClearCache(...interface{}) error
 | 
			
		||||
	Context(context.Context) *Session
 | 
			
		||||
	CreateTables(...interface{}) error
 | 
			
		||||
	DBMetas() ([]*core.Table, error)
 | 
			
		||||
	Dialect() core.Dialect
 | 
			
		||||
	DropTables(...interface{}) error
 | 
			
		||||
	DumpAllToFile(fp string, tp ...core.DbType) error
 | 
			
		||||
	GetCacher(string) core.Cacher
 | 
			
		||||
	GetColumnMapper() core.IMapper
 | 
			
		||||
	GetDefaultCacher() core.Cacher
 | 
			
		||||
	GetTableMapper() core.IMapper
 | 
			
		||||
	GetTZDatabase() *time.Location
 | 
			
		||||
	GetTZLocation() *time.Location
 | 
			
		||||
	MapCacher(interface{}, core.Cacher) error
 | 
			
		||||
	NewSession() *Session
 | 
			
		||||
	NoAutoTime() *Session
 | 
			
		||||
	Quote(string) string
 | 
			
		||||
	SetCacher(string, core.Cacher)
 | 
			
		||||
	SetConnMaxLifetime(time.Duration)
 | 
			
		||||
	SetDefaultCacher(core.Cacher)
 | 
			
		||||
	SetLogger(logger core.ILogger)
 | 
			
		||||
	SetLogLevel(core.LogLevel)
 | 
			
		||||
	SetMapper(core.IMapper)
 | 
			
		||||
	SetMaxOpenConns(int)
 | 
			
		||||
	SetMaxIdleConns(int)
 | 
			
		||||
	SetSchema(string)
 | 
			
		||||
	SetTZDatabase(tz *time.Location)
 | 
			
		||||
	SetTZLocation(tz *time.Location)
 | 
			
		||||
	ShowExecTime(...bool)
 | 
			
		||||
	ShowSQL(show ...bool)
 | 
			
		||||
	Sync(...interface{}) error
 | 
			
		||||
	Sync2(...interface{}) error
 | 
			
		||||
	StoreEngine(storeEngine string) *Session
 | 
			
		||||
	TableInfo(bean interface{}) *Table
 | 
			
		||||
	TableName(interface{}, ...bool) string
 | 
			
		||||
	UnMapType(reflect.Type)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	_ Interface       = &Session{}
 | 
			
		||||
	_ EngineInterface = &Engine{}
 | 
			
		||||
	_ EngineInterface = &EngineGroup{}
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/xorm.io/xorm/json.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/xorm.io/xorm/json.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
// 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 "encoding/json"
 | 
			
		||||
 | 
			
		||||
// JSONInterface represents an interface to handle json data
 | 
			
		||||
type JSONInterface interface {
 | 
			
		||||
	Marshal(v interface{}) ([]byte, error)
 | 
			
		||||
	Unmarshal(data []byte, v interface{}) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// DefaultJSONHandler default json handler
 | 
			
		||||
	DefaultJSONHandler JSONInterface = StdJSON{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StdJSON implements JSONInterface via encoding/json
 | 
			
		||||
type StdJSON struct{}
 | 
			
		||||
 | 
			
		||||
// Marshal implements JSONInterface
 | 
			
		||||
func (StdJSON) Marshal(v interface{}) ([]byte, error) {
 | 
			
		||||
	return json.Marshal(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unmarshal implements JSONInterface
 | 
			
		||||
func (StdJSON) Unmarshal(data []byte, v interface{}) error {
 | 
			
		||||
	return json.Unmarshal(data, v)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										187
									
								
								vendor/xorm.io/xorm/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								vendor/xorm.io/xorm/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,187 @@
 | 
			
		||||
// Copyright 2015 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"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// default log options
 | 
			
		||||
const (
 | 
			
		||||
	DEFAULT_LOG_PREFIX = "[xorm]"
 | 
			
		||||
	DEFAULT_LOG_FLAG   = log.Ldate | log.Lmicroseconds
 | 
			
		||||
	DEFAULT_LOG_LEVEL  = core.LOG_DEBUG
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ core.ILogger = DiscardLogger{}
 | 
			
		||||
 | 
			
		||||
// DiscardLogger don't log implementation for core.ILogger
 | 
			
		||||
type DiscardLogger struct{}
 | 
			
		||||
 | 
			
		||||
// Debug empty implementation
 | 
			
		||||
func (DiscardLogger) Debug(v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Debugf empty implementation
 | 
			
		||||
func (DiscardLogger) Debugf(format string, v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Error empty implementation
 | 
			
		||||
func (DiscardLogger) Error(v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Errorf empty implementation
 | 
			
		||||
func (DiscardLogger) Errorf(format string, v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Info empty implementation
 | 
			
		||||
func (DiscardLogger) Info(v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Infof empty implementation
 | 
			
		||||
func (DiscardLogger) Infof(format string, v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Warn empty implementation
 | 
			
		||||
func (DiscardLogger) Warn(v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Warnf empty implementation
 | 
			
		||||
func (DiscardLogger) Warnf(format string, v ...interface{}) {}
 | 
			
		||||
 | 
			
		||||
// Level empty implementation
 | 
			
		||||
func (DiscardLogger) Level() core.LogLevel {
 | 
			
		||||
	return core.LOG_UNKNOWN
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetLevel empty implementation
 | 
			
		||||
func (DiscardLogger) SetLevel(l core.LogLevel) {}
 | 
			
		||||
 | 
			
		||||
// ShowSQL empty implementation
 | 
			
		||||
func (DiscardLogger) ShowSQL(show ...bool) {}
 | 
			
		||||
 | 
			
		||||
// IsShowSQL empty implementation
 | 
			
		||||
func (DiscardLogger) IsShowSQL() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SimpleLogger is the default implment of core.ILogger
 | 
			
		||||
type SimpleLogger struct {
 | 
			
		||||
	DEBUG   *log.Logger
 | 
			
		||||
	ERR     *log.Logger
 | 
			
		||||
	INFO    *log.Logger
 | 
			
		||||
	WARN    *log.Logger
 | 
			
		||||
	level   core.LogLevel
 | 
			
		||||
	showSQL bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ core.ILogger = &SimpleLogger{}
 | 
			
		||||
 | 
			
		||||
// NewSimpleLogger use a special io.Writer as logger output
 | 
			
		||||
func NewSimpleLogger(out io.Writer) *SimpleLogger {
 | 
			
		||||
	return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSimpleLogger2 let you customrize your logger prefix and flag
 | 
			
		||||
func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger {
 | 
			
		||||
	return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSimpleLogger3 let you customrize your logger prefix and flag and logLevel
 | 
			
		||||
func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger {
 | 
			
		||||
	return &SimpleLogger{
 | 
			
		||||
		DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag),
 | 
			
		||||
		ERR:   log.New(out, fmt.Sprintf("%s [error] ", prefix), flag),
 | 
			
		||||
		INFO:  log.New(out, fmt.Sprintf("%s [info]  ", prefix), flag),
 | 
			
		||||
		WARN:  log.New(out, fmt.Sprintf("%s [warn]  ", prefix), flag),
 | 
			
		||||
		level: l,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Error(v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_ERR {
 | 
			
		||||
		s.ERR.Output(2, fmt.Sprint(v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Errorf implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_ERR {
 | 
			
		||||
		s.ERR.Output(2, fmt.Sprintf(format, v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debug implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Debug(v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_DEBUG {
 | 
			
		||||
		s.DEBUG.Output(2, fmt.Sprint(v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debugf implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_DEBUG {
 | 
			
		||||
		s.DEBUG.Output(2, fmt.Sprintf(format, v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Info(v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_INFO {
 | 
			
		||||
		s.INFO.Output(2, fmt.Sprint(v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Infof implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Infof(format string, v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_INFO {
 | 
			
		||||
		s.INFO.Output(2, fmt.Sprintf(format, v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warn implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Warn(v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_WARNING {
 | 
			
		||||
		s.WARN.Output(2, fmt.Sprint(v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warnf implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
 | 
			
		||||
	if s.level <= core.LOG_WARNING {
 | 
			
		||||
		s.WARN.Output(2, fmt.Sprintf(format, v...))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Level implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) Level() core.LogLevel {
 | 
			
		||||
	return s.level
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetLevel implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) SetLevel(l core.LogLevel) {
 | 
			
		||||
	s.level = l
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ShowSQL implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) ShowSQL(show ...bool) {
 | 
			
		||||
	if len(show) == 0 {
 | 
			
		||||
		s.showSQL = true
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	s.showSQL = show[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsShowSQL implement core.ILogger
 | 
			
		||||
func (s *SimpleLogger) IsShowSQL() bool {
 | 
			
		||||
	return s.showSQL
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										746
									
								
								vendor/xorm.io/xorm/pg_reserved.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										746
									
								
								vendor/xorm.io/xorm/pg_reserved.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,746 @@
 | 
			
		||||
A	 	non-reserved	non-reserved	 
 | 
			
		||||
ABORT	non-reserved	 	 	 
 | 
			
		||||
ABS	 	reserved	reserved	 
 | 
			
		||||
ABSENT	 	non-reserved	non-reserved	 
 | 
			
		||||
ABSOLUTE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
ACCESS	non-reserved	 	 	 
 | 
			
		||||
ACCORDING	 	non-reserved	non-reserved	 
 | 
			
		||||
ACTION	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
ADA	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
ADD	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
ADMIN	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
AFTER	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
AGGREGATE	non-reserved	 	 	 
 | 
			
		||||
ALL	reserved	reserved	reserved	reserved
 | 
			
		||||
ALLOCATE	 	reserved	reserved	reserved
 | 
			
		||||
ALSO	non-reserved	 	 	 
 | 
			
		||||
ALTER	non-reserved	reserved	reserved	reserved
 | 
			
		||||
ALWAYS	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
ANALYSE	reserved	 	 	 
 | 
			
		||||
ANALYZE	reserved	 	 	 
 | 
			
		||||
AND	reserved	reserved	reserved	reserved
 | 
			
		||||
ANY	reserved	reserved	reserved	reserved
 | 
			
		||||
ARE	 	reserved	reserved	reserved
 | 
			
		||||
ARRAY	reserved	reserved	reserved	 
 | 
			
		||||
ARRAY_AGG	 	reserved	reserved	 
 | 
			
		||||
ARRAY_MAX_CARDINALITY	 	reserved	 	 
 | 
			
		||||
AS	reserved	reserved	reserved	reserved
 | 
			
		||||
ASC	reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
ASENSITIVE	 	reserved	reserved	 
 | 
			
		||||
ASSERTION	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
ASSIGNMENT	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
ASYMMETRIC	reserved	reserved	reserved	 
 | 
			
		||||
AT	non-reserved	reserved	reserved	reserved
 | 
			
		||||
ATOMIC	 	reserved	reserved	 
 | 
			
		||||
ATTRIBUTE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
ATTRIBUTES	 	non-reserved	non-reserved	 
 | 
			
		||||
AUTHORIZATION	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
AVG	 	reserved	reserved	reserved
 | 
			
		||||
BACKWARD	non-reserved	 	 	 
 | 
			
		||||
BASE64	 	non-reserved	non-reserved	 
 | 
			
		||||
BEFORE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
BEGIN	non-reserved	reserved	reserved	reserved
 | 
			
		||||
BEGIN_FRAME	 	reserved	 	 
 | 
			
		||||
BEGIN_PARTITION	 	reserved	 	 
 | 
			
		||||
BERNOULLI	 	non-reserved	non-reserved	 
 | 
			
		||||
BETWEEN	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
BIGINT	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
BINARY	reserved (can be function or type)	reserved	reserved	 
 | 
			
		||||
BIT	non-reserved (cannot be function or type)	 	 	reserved
 | 
			
		||||
BIT_LENGTH	 	 	 	reserved
 | 
			
		||||
BLOB	 	reserved	reserved	 
 | 
			
		||||
BLOCKED	 	non-reserved	non-reserved	 
 | 
			
		||||
BOM	 	non-reserved	non-reserved	 
 | 
			
		||||
BOOLEAN	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
BOTH	reserved	reserved	reserved	reserved
 | 
			
		||||
BREADTH	 	non-reserved	non-reserved	 
 | 
			
		||||
BY	non-reserved	reserved	reserved	reserved
 | 
			
		||||
C	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CACHE	non-reserved	 	 	 
 | 
			
		||||
CALL	 	reserved	reserved	 
 | 
			
		||||
CALLED	non-reserved	reserved	reserved	 
 | 
			
		||||
CARDINALITY	 	reserved	reserved	 
 | 
			
		||||
CASCADE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
CASCADED	non-reserved	reserved	reserved	reserved
 | 
			
		||||
CASE	reserved	reserved	reserved	reserved
 | 
			
		||||
CAST	reserved	reserved	reserved	reserved
 | 
			
		||||
CATALOG	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
CATALOG_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CEIL	 	reserved	reserved	 
 | 
			
		||||
CEILING	 	reserved	reserved	 
 | 
			
		||||
CHAIN	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
CHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
CHARACTER	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
CHARACTERISTICS	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
CHARACTERS	 	non-reserved	non-reserved	 
 | 
			
		||||
CHARACTER_LENGTH	 	reserved	reserved	reserved
 | 
			
		||||
CHARACTER_SET_CATALOG	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CHARACTER_SET_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CHARACTER_SET_SCHEMA	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CHAR_LENGTH	 	reserved	reserved	reserved
 | 
			
		||||
CHECK	reserved	reserved	reserved	reserved
 | 
			
		||||
CHECKPOINT	non-reserved	 	 	 
 | 
			
		||||
CLASS	non-reserved	 	 	 
 | 
			
		||||
CLASS_ORIGIN	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CLOB	 	reserved	reserved	 
 | 
			
		||||
CLOSE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
CLUSTER	non-reserved	 	 	 
 | 
			
		||||
COALESCE	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
COBOL	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
COLLATE	reserved	reserved	reserved	reserved
 | 
			
		||||
COLLATION	reserved (can be function or type)	non-reserved	non-reserved	reserved
 | 
			
		||||
COLLATION_CATALOG	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
COLLATION_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
COLLATION_SCHEMA	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
COLLECT	 	reserved	reserved	 
 | 
			
		||||
COLUMN	reserved	reserved	reserved	reserved
 | 
			
		||||
COLUMNS	 	non-reserved	non-reserved	 
 | 
			
		||||
COLUMN_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
COMMAND_FUNCTION	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
COMMAND_FUNCTION_CODE	 	non-reserved	non-reserved	 
 | 
			
		||||
COMMENT	non-reserved	 	 	 
 | 
			
		||||
COMMENTS	non-reserved	 	 	 
 | 
			
		||||
COMMIT	non-reserved	reserved	reserved	reserved
 | 
			
		||||
COMMITTED	non-reserved	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CONCURRENTLY	reserved (can be function or type)	 	 	 
 | 
			
		||||
CONDITION	 	reserved	reserved	 
 | 
			
		||||
CONDITION_NUMBER	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CONFIGURATION	non-reserved	 	 	 
 | 
			
		||||
CONNECT	 	reserved	reserved	reserved
 | 
			
		||||
CONNECTION	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
CONNECTION_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CONSTRAINT	reserved	reserved	reserved	reserved
 | 
			
		||||
CONSTRAINTS	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
CONSTRAINT_CATALOG	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CONSTRAINT_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CONSTRAINT_SCHEMA	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CONSTRUCTOR	 	non-reserved	non-reserved	 
 | 
			
		||||
CONTAINS	 	reserved	non-reserved	 
 | 
			
		||||
CONTENT	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
CONTINUE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
CONTROL	 	non-reserved	non-reserved	 
 | 
			
		||||
CONVERSION	non-reserved	 	 	 
 | 
			
		||||
CONVERT	 	reserved	reserved	reserved
 | 
			
		||||
COPY	non-reserved	 	 	 
 | 
			
		||||
CORR	 	reserved	reserved	 
 | 
			
		||||
CORRESPONDING	 	reserved	reserved	reserved
 | 
			
		||||
COST	non-reserved	 	 	 
 | 
			
		||||
COUNT	 	reserved	reserved	reserved
 | 
			
		||||
COVAR_POP	 	reserved	reserved	 
 | 
			
		||||
COVAR_SAMP	 	reserved	reserved	 
 | 
			
		||||
CREATE	reserved	reserved	reserved	reserved
 | 
			
		||||
CROSS	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
CSV	non-reserved	 	 	 
 | 
			
		||||
CUBE	 	reserved	reserved	 
 | 
			
		||||
CUME_DIST	 	reserved	reserved	 
 | 
			
		||||
CURRENT	non-reserved	reserved	reserved	reserved
 | 
			
		||||
CURRENT_CATALOG	reserved	reserved	reserved	 
 | 
			
		||||
CURRENT_DATE	reserved	reserved	reserved	reserved
 | 
			
		||||
CURRENT_DEFAULT_TRANSFORM_GROUP	 	reserved	reserved	 
 | 
			
		||||
CURRENT_PATH	 	reserved	reserved	 
 | 
			
		||||
CURRENT_ROLE	reserved	reserved	reserved	 
 | 
			
		||||
CURRENT_ROW	 	reserved	 	 
 | 
			
		||||
CURRENT_SCHEMA	reserved (can be function or type)	reserved	reserved	 
 | 
			
		||||
CURRENT_TIME	reserved	reserved	reserved	reserved
 | 
			
		||||
CURRENT_TIMESTAMP	reserved	reserved	reserved	reserved
 | 
			
		||||
CURRENT_TRANSFORM_GROUP_FOR_TYPE	 	reserved	reserved	 
 | 
			
		||||
CURRENT_USER	reserved	reserved	reserved	reserved
 | 
			
		||||
CURSOR	non-reserved	reserved	reserved	reserved
 | 
			
		||||
CURSOR_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
CYCLE	non-reserved	reserved	reserved	 
 | 
			
		||||
DATA	non-reserved	non-reserved	non-reserved	non-reserved
 | 
			
		||||
DATABASE	non-reserved	 	 	 
 | 
			
		||||
DATALINK	 	reserved	reserved	 
 | 
			
		||||
DATE	 	reserved	reserved	reserved
 | 
			
		||||
DATETIME_INTERVAL_CODE	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
DATETIME_INTERVAL_PRECISION	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
DAY	non-reserved	reserved	reserved	reserved
 | 
			
		||||
DB	 	non-reserved	non-reserved	 
 | 
			
		||||
DEALLOCATE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
DEC	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
DECIMAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
DECLARE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
DEFAULT	reserved	reserved	reserved	reserved
 | 
			
		||||
DEFAULTS	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
DEFERRABLE	reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
DEFERRED	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
DEFINED	 	non-reserved	non-reserved	 
 | 
			
		||||
DEFINER	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
DEGREE	 	non-reserved	non-reserved	 
 | 
			
		||||
DELETE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
DELIMITER	non-reserved	 	 	 
 | 
			
		||||
DELIMITERS	non-reserved	 	 	 
 | 
			
		||||
DENSE_RANK	 	reserved	reserved	 
 | 
			
		||||
DEPTH	 	non-reserved	non-reserved	 
 | 
			
		||||
DEREF	 	reserved	reserved	 
 | 
			
		||||
DERIVED	 	non-reserved	non-reserved	 
 | 
			
		||||
DESC	reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
DESCRIBE	 	reserved	reserved	reserved
 | 
			
		||||
DESCRIPTOR	 	non-reserved	non-reserved	reserved
 | 
			
		||||
DETERMINISTIC	 	reserved	reserved	 
 | 
			
		||||
DIAGNOSTICS	 	non-reserved	non-reserved	reserved
 | 
			
		||||
DICTIONARY	non-reserved	 	 	 
 | 
			
		||||
DISABLE	non-reserved	 	 	 
 | 
			
		||||
DISCARD	non-reserved	 	 	 
 | 
			
		||||
DISCONNECT	 	reserved	reserved	reserved
 | 
			
		||||
DISPATCH	 	non-reserved	non-reserved	 
 | 
			
		||||
DISTINCT	reserved	reserved	reserved	reserved
 | 
			
		||||
DLNEWCOPY	 	reserved	reserved	 
 | 
			
		||||
DLPREVIOUSCOPY	 	reserved	reserved	 
 | 
			
		||||
DLURLCOMPLETE	 	reserved	reserved	 
 | 
			
		||||
DLURLCOMPLETEONLY	 	reserved	reserved	 
 | 
			
		||||
DLURLCOMPLETEWRITE	 	reserved	reserved	 
 | 
			
		||||
DLURLPATH	 	reserved	reserved	 
 | 
			
		||||
DLURLPATHONLY	 	reserved	reserved	 
 | 
			
		||||
DLURLPATHWRITE	 	reserved	reserved	 
 | 
			
		||||
DLURLSCHEME	 	reserved	reserved	 
 | 
			
		||||
DLURLSERVER	 	reserved	reserved	 
 | 
			
		||||
DLVALUE	 	reserved	reserved	 
 | 
			
		||||
DO	reserved	 	 	 
 | 
			
		||||
DOCUMENT	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
DOMAIN	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
DOUBLE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
DROP	non-reserved	reserved	reserved	reserved
 | 
			
		||||
DYNAMIC	 	reserved	reserved	 
 | 
			
		||||
DYNAMIC_FUNCTION	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
DYNAMIC_FUNCTION_CODE	 	non-reserved	non-reserved	 
 | 
			
		||||
EACH	non-reserved	reserved	reserved	 
 | 
			
		||||
ELEMENT	 	reserved	reserved	 
 | 
			
		||||
ELSE	reserved	reserved	reserved	reserved
 | 
			
		||||
EMPTY	 	non-reserved	non-reserved	 
 | 
			
		||||
ENABLE	non-reserved	 	 	 
 | 
			
		||||
ENCODING	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
ENCRYPTED	non-reserved	 	 	 
 | 
			
		||||
END	reserved	reserved	reserved	reserved
 | 
			
		||||
END-EXEC	 	reserved	reserved	reserved
 | 
			
		||||
END_FRAME	 	reserved	 	 
 | 
			
		||||
END_PARTITION	 	reserved	 	 
 | 
			
		||||
ENFORCED	 	non-reserved	 	 
 | 
			
		||||
ENUM	non-reserved	 	 	 
 | 
			
		||||
EQUALS	 	reserved	non-reserved	 
 | 
			
		||||
ESCAPE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
EVENT	non-reserved	 	 	 
 | 
			
		||||
EVERY	 	reserved	reserved	 
 | 
			
		||||
EXCEPT	reserved	reserved	reserved	reserved
 | 
			
		||||
EXCEPTION	 	 	 	reserved
 | 
			
		||||
EXCLUDE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
EXCLUDING	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
EXCLUSIVE	non-reserved	 	 	 
 | 
			
		||||
EXEC	 	reserved	reserved	reserved
 | 
			
		||||
EXECUTE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
EXISTS	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
EXP	 	reserved	reserved	 
 | 
			
		||||
EXPLAIN	non-reserved	 	 	 
 | 
			
		||||
EXPRESSION	 	non-reserved	 	 
 | 
			
		||||
EXTENSION	non-reserved	 	 	 
 | 
			
		||||
EXTERNAL	non-reserved	reserved	reserved	reserved
 | 
			
		||||
EXTRACT	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
FALSE	reserved	reserved	reserved	reserved
 | 
			
		||||
FAMILY	non-reserved	 	 	 
 | 
			
		||||
FETCH	reserved	reserved	reserved	reserved
 | 
			
		||||
FILE	 	non-reserved	non-reserved	 
 | 
			
		||||
FILTER	 	reserved	reserved	 
 | 
			
		||||
FINAL	 	non-reserved	non-reserved	 
 | 
			
		||||
FIRST	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
FIRST_VALUE	 	reserved	reserved	 
 | 
			
		||||
FLAG	 	non-reserved	non-reserved	 
 | 
			
		||||
FLOAT	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
FLOOR	 	reserved	reserved	 
 | 
			
		||||
FOLLOWING	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
FOR	reserved	reserved	reserved	reserved
 | 
			
		||||
FORCE	non-reserved	 	 	 
 | 
			
		||||
FOREIGN	reserved	reserved	reserved	reserved
 | 
			
		||||
FORTRAN	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
FORWARD	non-reserved	 	 	 
 | 
			
		||||
FOUND	 	non-reserved	non-reserved	reserved
 | 
			
		||||
FRAME_ROW	 	reserved	 	 
 | 
			
		||||
FREE	 	reserved	reserved	 
 | 
			
		||||
FREEZE	reserved (can be function or type)	 	 	 
 | 
			
		||||
FROM	reserved	reserved	reserved	reserved
 | 
			
		||||
FS	 	non-reserved	non-reserved	 
 | 
			
		||||
FULL	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
FUNCTION	non-reserved	reserved	reserved	 
 | 
			
		||||
FUNCTIONS	non-reserved	 	 	 
 | 
			
		||||
FUSION	 	reserved	reserved	 
 | 
			
		||||
G	 	non-reserved	non-reserved	 
 | 
			
		||||
GENERAL	 	non-reserved	non-reserved	 
 | 
			
		||||
GENERATED	 	non-reserved	non-reserved	 
 | 
			
		||||
GET	 	reserved	reserved	reserved
 | 
			
		||||
GLOBAL	non-reserved	reserved	reserved	reserved
 | 
			
		||||
GO	 	non-reserved	non-reserved	reserved
 | 
			
		||||
GOTO	 	non-reserved	non-reserved	reserved
 | 
			
		||||
GRANT	reserved	reserved	reserved	reserved
 | 
			
		||||
GRANTED	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
GREATEST	non-reserved (cannot be function or type)	 	 	 
 | 
			
		||||
GROUP	reserved	reserved	reserved	reserved
 | 
			
		||||
GROUPING	 	reserved	reserved	 
 | 
			
		||||
GROUPS	 	reserved	 	 
 | 
			
		||||
HANDLER	non-reserved	 	 	 
 | 
			
		||||
HAVING	reserved	reserved	reserved	reserved
 | 
			
		||||
HEADER	non-reserved	 	 	 
 | 
			
		||||
HEX	 	non-reserved	non-reserved	 
 | 
			
		||||
HIERARCHY	 	non-reserved	non-reserved	 
 | 
			
		||||
HOLD	non-reserved	reserved	reserved	 
 | 
			
		||||
HOUR	non-reserved	reserved	reserved	reserved
 | 
			
		||||
ID	 	non-reserved	non-reserved	 
 | 
			
		||||
IDENTITY	non-reserved	reserved	reserved	reserved
 | 
			
		||||
IF	non-reserved	 	 	 
 | 
			
		||||
IGNORE	 	non-reserved	non-reserved	 
 | 
			
		||||
ILIKE	reserved (can be function or type)	 	 	 
 | 
			
		||||
IMMEDIATE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
IMMEDIATELY	 	non-reserved	 	 
 | 
			
		||||
IMMUTABLE	non-reserved	 	 	 
 | 
			
		||||
IMPLEMENTATION	 	non-reserved	non-reserved	 
 | 
			
		||||
IMPLICIT	non-reserved	 	 	 
 | 
			
		||||
IMPORT	 	reserved	reserved	 
 | 
			
		||||
IN	reserved	reserved	reserved	reserved
 | 
			
		||||
INCLUDING	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
INCREMENT	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
INDENT	 	non-reserved	non-reserved	 
 | 
			
		||||
INDEX	non-reserved	 	 	 
 | 
			
		||||
INDEXES	non-reserved	 	 	 
 | 
			
		||||
INDICATOR	 	reserved	reserved	reserved
 | 
			
		||||
INHERIT	non-reserved	 	 	 
 | 
			
		||||
INHERITS	non-reserved	 	 	 
 | 
			
		||||
INITIALLY	reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
INLINE	non-reserved	 	 	 
 | 
			
		||||
INNER	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
INOUT	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
INPUT	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
INSENSITIVE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
INSERT	non-reserved	reserved	reserved	reserved
 | 
			
		||||
INSTANCE	 	non-reserved	non-reserved	 
 | 
			
		||||
INSTANTIABLE	 	non-reserved	non-reserved	 
 | 
			
		||||
INSTEAD	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
INT	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
INTEGER	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
INTEGRITY	 	non-reserved	non-reserved	 
 | 
			
		||||
INTERSECT	reserved	reserved	reserved	reserved
 | 
			
		||||
INTERSECTION	 	reserved	reserved	 
 | 
			
		||||
INTERVAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
INTO	reserved	reserved	reserved	reserved
 | 
			
		||||
INVOKER	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
IS	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
ISNULL	reserved (can be function or type)	 	 	 
 | 
			
		||||
ISOLATION	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
JOIN	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
K	 	non-reserved	non-reserved	 
 | 
			
		||||
KEY	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
KEY_MEMBER	 	non-reserved	non-reserved	 
 | 
			
		||||
KEY_TYPE	 	non-reserved	non-reserved	 
 | 
			
		||||
LABEL	non-reserved	 	 	 
 | 
			
		||||
LAG	 	reserved	reserved	 
 | 
			
		||||
LANGUAGE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
LARGE	non-reserved	reserved	reserved	 
 | 
			
		||||
LAST	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
LAST_VALUE	 	reserved	reserved	 
 | 
			
		||||
LATERAL	reserved	reserved	reserved	 
 | 
			
		||||
LC_COLLATE	non-reserved	 	 	 
 | 
			
		||||
LC_CTYPE	non-reserved	 	 	 
 | 
			
		||||
LEAD	 	reserved	reserved	 
 | 
			
		||||
LEADING	reserved	reserved	reserved	reserved
 | 
			
		||||
LEAKPROOF	non-reserved	 	 	 
 | 
			
		||||
LEAST	non-reserved (cannot be function or type)	 	 	 
 | 
			
		||||
LEFT	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
LENGTH	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
LEVEL	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
LIBRARY	 	non-reserved	non-reserved	 
 | 
			
		||||
LIKE	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
LIKE_REGEX	 	reserved	reserved	 
 | 
			
		||||
LIMIT	reserved	non-reserved	non-reserved	 
 | 
			
		||||
LINK	 	non-reserved	non-reserved	 
 | 
			
		||||
LISTEN	non-reserved	 	 	 
 | 
			
		||||
LN	 	reserved	reserved	 
 | 
			
		||||
LOAD	non-reserved	 	 	 
 | 
			
		||||
LOCAL	non-reserved	reserved	reserved	reserved
 | 
			
		||||
LOCALTIME	reserved	reserved	reserved	 
 | 
			
		||||
LOCALTIMESTAMP	reserved	reserved	reserved	 
 | 
			
		||||
LOCATION	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
LOCATOR	 	non-reserved	non-reserved	 
 | 
			
		||||
LOCK	non-reserved	 	 	 
 | 
			
		||||
LOWER	 	reserved	reserved	reserved
 | 
			
		||||
M	 	non-reserved	non-reserved	 
 | 
			
		||||
MAP	 	non-reserved	non-reserved	 
 | 
			
		||||
MAPPING	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
MATCH	non-reserved	reserved	reserved	reserved
 | 
			
		||||
MATCHED	 	non-reserved	non-reserved	 
 | 
			
		||||
MATERIALIZED	non-reserved	 	 	 
 | 
			
		||||
MAX	 	reserved	reserved	reserved
 | 
			
		||||
MAXVALUE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
MAX_CARDINALITY	 	 	reserved	 
 | 
			
		||||
MEMBER	 	reserved	reserved	 
 | 
			
		||||
MERGE	 	reserved	reserved	 
 | 
			
		||||
MESSAGE_LENGTH	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
MESSAGE_OCTET_LENGTH	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
MESSAGE_TEXT	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
METHOD	 	reserved	reserved	 
 | 
			
		||||
MIN	 	reserved	reserved	reserved
 | 
			
		||||
MINUTE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
MINVALUE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
MOD	 	reserved	reserved	 
 | 
			
		||||
MODE	non-reserved	 	 	 
 | 
			
		||||
MODIFIES	 	reserved	reserved	 
 | 
			
		||||
MODULE	 	reserved	reserved	reserved
 | 
			
		||||
MONTH	non-reserved	reserved	reserved	reserved
 | 
			
		||||
MORE	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
MOVE	non-reserved	 	 	 
 | 
			
		||||
MULTISET	 	reserved	reserved	 
 | 
			
		||||
MUMPS	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
NAME	non-reserved	non-reserved	non-reserved	non-reserved
 | 
			
		||||
NAMES	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
NAMESPACE	 	non-reserved	non-reserved	 
 | 
			
		||||
NATIONAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
NATURAL	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
NCHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
NCLOB	 	reserved	reserved	 
 | 
			
		||||
NESTING	 	non-reserved	non-reserved	 
 | 
			
		||||
NEW	 	reserved	reserved	 
 | 
			
		||||
NEXT	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
NFC	 	non-reserved	non-reserved	 
 | 
			
		||||
NFD	 	non-reserved	non-reserved	 
 | 
			
		||||
NFKC	 	non-reserved	non-reserved	 
 | 
			
		||||
NFKD	 	non-reserved	non-reserved	 
 | 
			
		||||
NIL	 	non-reserved	non-reserved	 
 | 
			
		||||
NO	non-reserved	reserved	reserved	reserved
 | 
			
		||||
NONE	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
NORMALIZE	 	reserved	reserved	 
 | 
			
		||||
NORMALIZED	 	non-reserved	non-reserved	 
 | 
			
		||||
NOT	reserved	reserved	reserved	reserved
 | 
			
		||||
NOTHING	non-reserved	 	 	 
 | 
			
		||||
NOTIFY	non-reserved	 	 	 
 | 
			
		||||
NOTNULL	reserved (can be function or type)	 	 	 
 | 
			
		||||
NOWAIT	non-reserved	 	 	 
 | 
			
		||||
NTH_VALUE	 	reserved	reserved	 
 | 
			
		||||
NTILE	 	reserved	reserved	 
 | 
			
		||||
NULL	reserved	reserved	reserved	reserved
 | 
			
		||||
NULLABLE	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
NULLIF	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
NULLS	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
NUMBER	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
NUMERIC	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
OBJECT	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
OCCURRENCES_REGEX	 	reserved	reserved	 
 | 
			
		||||
OCTETS	 	non-reserved	non-reserved	 
 | 
			
		||||
OCTET_LENGTH	 	reserved	reserved	reserved
 | 
			
		||||
OF	non-reserved	reserved	reserved	reserved
 | 
			
		||||
OFF	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
OFFSET	reserved	reserved	reserved	 
 | 
			
		||||
OIDS	non-reserved	 	 	 
 | 
			
		||||
OLD	 	reserved	reserved	 
 | 
			
		||||
ON	reserved	reserved	reserved	reserved
 | 
			
		||||
ONLY	reserved	reserved	reserved	reserved
 | 
			
		||||
OPEN	 	reserved	reserved	reserved
 | 
			
		||||
OPERATOR	non-reserved	 	 	 
 | 
			
		||||
OPTION	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
OPTIONS	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
OR	reserved	reserved	reserved	reserved
 | 
			
		||||
ORDER	reserved	reserved	reserved	reserved
 | 
			
		||||
ORDERING	 	non-reserved	non-reserved	 
 | 
			
		||||
ORDINALITY	 	non-reserved	non-reserved	 
 | 
			
		||||
OTHERS	 	non-reserved	non-reserved	 
 | 
			
		||||
OUT	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
OUTER	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
OUTPUT	 	non-reserved	non-reserved	reserved
 | 
			
		||||
OVER	reserved (can be function or type)	reserved	reserved	 
 | 
			
		||||
OVERLAPS	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
OVERLAY	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
OVERRIDING	 	non-reserved	non-reserved	 
 | 
			
		||||
OWNED	non-reserved	 	 	 
 | 
			
		||||
OWNER	non-reserved	 	 	 
 | 
			
		||||
P	 	non-reserved	non-reserved	 
 | 
			
		||||
PAD	 	non-reserved	non-reserved	reserved
 | 
			
		||||
PARAMETER	 	reserved	reserved	 
 | 
			
		||||
PARAMETER_MODE	 	non-reserved	non-reserved	 
 | 
			
		||||
PARAMETER_NAME	 	non-reserved	non-reserved	 
 | 
			
		||||
PARAMETER_ORDINAL_POSITION	 	non-reserved	non-reserved	 
 | 
			
		||||
PARAMETER_SPECIFIC_CATALOG	 	non-reserved	non-reserved	 
 | 
			
		||||
PARAMETER_SPECIFIC_NAME	 	non-reserved	non-reserved	 
 | 
			
		||||
PARAMETER_SPECIFIC_SCHEMA	 	non-reserved	non-reserved	 
 | 
			
		||||
PARSER	non-reserved	 	 	 
 | 
			
		||||
PARTIAL	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
PARTITION	non-reserved	reserved	reserved	 
 | 
			
		||||
PASCAL	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
PASSING	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
PASSTHROUGH	 	non-reserved	non-reserved	 
 | 
			
		||||
PASSWORD	non-reserved	 	 	 
 | 
			
		||||
PATH	 	non-reserved	non-reserved	 
 | 
			
		||||
PERCENT	 	reserved	 	 
 | 
			
		||||
PERCENTILE_CONT	 	reserved	reserved	 
 | 
			
		||||
PERCENTILE_DISC	 	reserved	reserved	 
 | 
			
		||||
PERCENT_RANK	 	reserved	reserved	 
 | 
			
		||||
PERIOD	 	reserved	 	 
 | 
			
		||||
PERMISSION	 	non-reserved	non-reserved	 
 | 
			
		||||
PLACING	reserved	non-reserved	non-reserved	 
 | 
			
		||||
PLANS	non-reserved	 	 	 
 | 
			
		||||
PLI	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
PORTION	 	reserved	 	 
 | 
			
		||||
POSITION	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
POSITION_REGEX	 	reserved	reserved	 
 | 
			
		||||
POWER	 	reserved	reserved	 
 | 
			
		||||
PRECEDES	 	reserved	 	 
 | 
			
		||||
PRECEDING	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
PRECISION	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
PREPARE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
PREPARED	non-reserved	 	 	 
 | 
			
		||||
PRESERVE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
PRIMARY	reserved	reserved	reserved	reserved
 | 
			
		||||
PRIOR	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
PRIVILEGES	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
PROCEDURAL	non-reserved	 	 	 
 | 
			
		||||
PROCEDURE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
PROGRAM	non-reserved	 	 	 
 | 
			
		||||
PUBLIC	 	non-reserved	non-reserved	reserved
 | 
			
		||||
QUOTE	non-reserved	 	 	 
 | 
			
		||||
RANGE	non-reserved	reserved	reserved	 
 | 
			
		||||
RANK	 	reserved	reserved	 
 | 
			
		||||
READ	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
READS	 	reserved	reserved	 
 | 
			
		||||
REAL	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
REASSIGN	non-reserved	 	 	 
 | 
			
		||||
RECHECK	non-reserved	 	 	 
 | 
			
		||||
RECOVERY	 	non-reserved	non-reserved	 
 | 
			
		||||
RECURSIVE	non-reserved	reserved	reserved	 
 | 
			
		||||
REF	non-reserved	reserved	reserved	 
 | 
			
		||||
REFERENCES	reserved	reserved	reserved	reserved
 | 
			
		||||
REFERENCING	 	reserved	reserved	 
 | 
			
		||||
REFRESH	non-reserved	 	 	 
 | 
			
		||||
REGR_AVGX	 	reserved	reserved	 
 | 
			
		||||
REGR_AVGY	 	reserved	reserved	 
 | 
			
		||||
REGR_COUNT	 	reserved	reserved	 
 | 
			
		||||
REGR_INTERCEPT	 	reserved	reserved	 
 | 
			
		||||
REGR_R2	 	reserved	reserved	 
 | 
			
		||||
REGR_SLOPE	 	reserved	reserved	 
 | 
			
		||||
REGR_SXX	 	reserved	reserved	 
 | 
			
		||||
REGR_SXY	 	reserved	reserved	 
 | 
			
		||||
REGR_SYY	 	reserved	reserved	 
 | 
			
		||||
REINDEX	non-reserved	 	 	 
 | 
			
		||||
RELATIVE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
RELEASE	non-reserved	reserved	reserved	 
 | 
			
		||||
RENAME	non-reserved	 	 	 
 | 
			
		||||
REPEATABLE	non-reserved	non-reserved	non-reserved	non-reserved
 | 
			
		||||
REPLACE	non-reserved	 	 	 
 | 
			
		||||
REPLICA	non-reserved	 	 	 
 | 
			
		||||
REQUIRING	 	non-reserved	non-reserved	 
 | 
			
		||||
RESET	non-reserved	 	 	 
 | 
			
		||||
RESPECT	 	non-reserved	non-reserved	 
 | 
			
		||||
RESTART	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
RESTORE	 	non-reserved	non-reserved	 
 | 
			
		||||
RESTRICT	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
RESULT	 	reserved	reserved	 
 | 
			
		||||
RETURN	 	reserved	reserved	 
 | 
			
		||||
RETURNED_CARDINALITY	 	non-reserved	non-reserved	 
 | 
			
		||||
RETURNED_LENGTH	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
RETURNED_OCTET_LENGTH	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
RETURNED_SQLSTATE	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
RETURNING	reserved	non-reserved	non-reserved	 
 | 
			
		||||
RETURNS	non-reserved	reserved	reserved	 
 | 
			
		||||
REVOKE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
RIGHT	reserved (can be function or type)	reserved	reserved	reserved
 | 
			
		||||
ROLE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
ROLLBACK	non-reserved	reserved	reserved	reserved
 | 
			
		||||
ROLLUP	 	reserved	reserved	 
 | 
			
		||||
ROUTINE	 	non-reserved	non-reserved	 
 | 
			
		||||
ROUTINE_CATALOG	 	non-reserved	non-reserved	 
 | 
			
		||||
ROUTINE_NAME	 	non-reserved	non-reserved	 
 | 
			
		||||
ROUTINE_SCHEMA	 	non-reserved	non-reserved	 
 | 
			
		||||
ROW	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
ROWS	non-reserved	reserved	reserved	reserved
 | 
			
		||||
ROW_COUNT	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
ROW_NUMBER	 	reserved	reserved	 
 | 
			
		||||
RULE	non-reserved	 	 	 
 | 
			
		||||
SAVEPOINT	non-reserved	reserved	reserved	 
 | 
			
		||||
SCALE	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
SCHEMA	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
SCHEMA_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
SCOPE	 	reserved	reserved	 
 | 
			
		||||
SCOPE_CATALOG	 	non-reserved	non-reserved	 
 | 
			
		||||
SCOPE_NAME	 	non-reserved	non-reserved	 
 | 
			
		||||
SCOPE_SCHEMA	 	non-reserved	non-reserved	 
 | 
			
		||||
SCROLL	non-reserved	reserved	reserved	reserved
 | 
			
		||||
SEARCH	non-reserved	reserved	reserved	 
 | 
			
		||||
SECOND	non-reserved	reserved	reserved	reserved
 | 
			
		||||
SECTION	 	non-reserved	non-reserved	reserved
 | 
			
		||||
SECURITY	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
SELECT	reserved	reserved	reserved	reserved
 | 
			
		||||
SELECTIVE	 	non-reserved	non-reserved	 
 | 
			
		||||
SELF	 	non-reserved	non-reserved	 
 | 
			
		||||
SENSITIVE	 	reserved	reserved	 
 | 
			
		||||
SEQUENCE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
SEQUENCES	non-reserved	 	 	 
 | 
			
		||||
SERIALIZABLE	non-reserved	non-reserved	non-reserved	non-reserved
 | 
			
		||||
SERVER	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
SERVER_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
SESSION	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
SESSION_USER	reserved	reserved	reserved	reserved
 | 
			
		||||
SET	non-reserved	reserved	reserved	reserved
 | 
			
		||||
SETOF	non-reserved (cannot be function or type)	 	 	 
 | 
			
		||||
SETS	 	non-reserved	non-reserved	 
 | 
			
		||||
SHARE	non-reserved	 	 	 
 | 
			
		||||
SHOW	non-reserved	 	 	 
 | 
			
		||||
SIMILAR	reserved (can be function or type)	reserved	reserved	 
 | 
			
		||||
SIMPLE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
SIZE	 	non-reserved	non-reserved	reserved
 | 
			
		||||
SMALLINT	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
SNAPSHOT	non-reserved	 	 	 
 | 
			
		||||
SOME	reserved	reserved	reserved	reserved
 | 
			
		||||
SOURCE	 	non-reserved	non-reserved	 
 | 
			
		||||
SPACE	 	non-reserved	non-reserved	reserved
 | 
			
		||||
SPECIFIC	 	reserved	reserved	 
 | 
			
		||||
SPECIFICTYPE	 	reserved	reserved	 
 | 
			
		||||
SPECIFIC_NAME	 	non-reserved	non-reserved	 
 | 
			
		||||
SQL	 	reserved	reserved	reserved
 | 
			
		||||
SQLCODE	 	 	 	reserved
 | 
			
		||||
SQLERROR	 	 	 	reserved
 | 
			
		||||
SQLEXCEPTION	 	reserved	reserved	 
 | 
			
		||||
SQLSTATE	 	reserved	reserved	reserved
 | 
			
		||||
SQLWARNING	 	reserved	reserved	 
 | 
			
		||||
SQRT	 	reserved	reserved	 
 | 
			
		||||
STABLE	non-reserved	 	 	 
 | 
			
		||||
STANDALONE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
START	non-reserved	reserved	reserved	 
 | 
			
		||||
STATE	 	non-reserved	non-reserved	 
 | 
			
		||||
STATEMENT	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
STATIC	 	reserved	reserved	 
 | 
			
		||||
STATISTICS	non-reserved	 	 	 
 | 
			
		||||
STDDEV_POP	 	reserved	reserved	 
 | 
			
		||||
STDDEV_SAMP	 	reserved	reserved	 
 | 
			
		||||
STDIN	non-reserved	 	 	 
 | 
			
		||||
STDOUT	non-reserved	 	 	 
 | 
			
		||||
STORAGE	non-reserved	 	 	 
 | 
			
		||||
STRICT	non-reserved	 	 	 
 | 
			
		||||
STRIP	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
STRUCTURE	 	non-reserved	non-reserved	 
 | 
			
		||||
STYLE	 	non-reserved	non-reserved	 
 | 
			
		||||
SUBCLASS_ORIGIN	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
SUBMULTISET	 	reserved	reserved	 
 | 
			
		||||
SUBSTRING	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
SUBSTRING_REGEX	 	reserved	reserved	 
 | 
			
		||||
SUCCEEDS	 	reserved	 	 
 | 
			
		||||
SUM	 	reserved	reserved	reserved
 | 
			
		||||
SYMMETRIC	reserved	reserved	reserved	 
 | 
			
		||||
SYSID	non-reserved	 	 	 
 | 
			
		||||
SYSTEM	non-reserved	reserved	reserved	 
 | 
			
		||||
SYSTEM_TIME	 	reserved	 	 
 | 
			
		||||
SYSTEM_USER	 	reserved	reserved	reserved
 | 
			
		||||
T	 	non-reserved	non-reserved	 
 | 
			
		||||
TABLE	reserved	reserved	reserved	reserved
 | 
			
		||||
TABLES	non-reserved	 	 	 
 | 
			
		||||
TABLESAMPLE	 	reserved	reserved	 
 | 
			
		||||
TABLESPACE	non-reserved	 	 	 
 | 
			
		||||
TABLE_NAME	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
TEMP	non-reserved	 	 	 
 | 
			
		||||
TEMPLATE	non-reserved	 	 	 
 | 
			
		||||
TEMPORARY	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
TEXT	non-reserved	 	 	 
 | 
			
		||||
THEN	reserved	reserved	reserved	reserved
 | 
			
		||||
TIES	 	non-reserved	non-reserved	 
 | 
			
		||||
TIME	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
TIMESTAMP	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
TIMEZONE_HOUR	 	reserved	reserved	reserved
 | 
			
		||||
TIMEZONE_MINUTE	 	reserved	reserved	reserved
 | 
			
		||||
TO	reserved	reserved	reserved	reserved
 | 
			
		||||
TOKEN	 	non-reserved	non-reserved	 
 | 
			
		||||
TOP_LEVEL_COUNT	 	non-reserved	non-reserved	 
 | 
			
		||||
TRAILING	reserved	reserved	reserved	reserved
 | 
			
		||||
TRANSACTION	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
TRANSACTIONS_COMMITTED	 	non-reserved	non-reserved	 
 | 
			
		||||
TRANSACTIONS_ROLLED_BACK	 	non-reserved	non-reserved	 
 | 
			
		||||
TRANSACTION_ACTIVE	 	non-reserved	non-reserved	 
 | 
			
		||||
TRANSFORM	 	non-reserved	non-reserved	 
 | 
			
		||||
TRANSFORMS	 	non-reserved	non-reserved	 
 | 
			
		||||
TRANSLATE	 	reserved	reserved	reserved
 | 
			
		||||
TRANSLATE_REGEX	 	reserved	reserved	 
 | 
			
		||||
TRANSLATION	 	reserved	reserved	reserved
 | 
			
		||||
TREAT	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
TRIGGER	non-reserved	reserved	reserved	 
 | 
			
		||||
TRIGGER_CATALOG	 	non-reserved	non-reserved	 
 | 
			
		||||
TRIGGER_NAME	 	non-reserved	non-reserved	 
 | 
			
		||||
TRIGGER_SCHEMA	 	non-reserved	non-reserved	 
 | 
			
		||||
TRIM	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
TRIM_ARRAY	 	reserved	reserved	 
 | 
			
		||||
TRUE	reserved	reserved	reserved	reserved
 | 
			
		||||
TRUNCATE	non-reserved	reserved	reserved	 
 | 
			
		||||
TRUSTED	non-reserved	 	 	 
 | 
			
		||||
TYPE	non-reserved	non-reserved	non-reserved	non-reserved
 | 
			
		||||
TYPES	non-reserved	 	 	 
 | 
			
		||||
UESCAPE	 	reserved	reserved	 
 | 
			
		||||
UNBOUNDED	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
UNCOMMITTED	non-reserved	non-reserved	non-reserved	non-reserved
 | 
			
		||||
UNDER	 	non-reserved	non-reserved	 
 | 
			
		||||
UNENCRYPTED	non-reserved	 	 	 
 | 
			
		||||
UNION	reserved	reserved	reserved	reserved
 | 
			
		||||
UNIQUE	reserved	reserved	reserved	reserved
 | 
			
		||||
UNKNOWN	non-reserved	reserved	reserved	reserved
 | 
			
		||||
UNLINK	 	non-reserved	non-reserved	 
 | 
			
		||||
UNLISTEN	non-reserved	 	 	 
 | 
			
		||||
UNLOGGED	non-reserved	 	 	 
 | 
			
		||||
UNNAMED	 	non-reserved	non-reserved	non-reserved
 | 
			
		||||
UNNEST	 	reserved	reserved	 
 | 
			
		||||
UNTIL	non-reserved	 	 	 
 | 
			
		||||
UNTYPED	 	non-reserved	non-reserved	 
 | 
			
		||||
UPDATE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
UPPER	 	reserved	reserved	reserved
 | 
			
		||||
URI	 	non-reserved	non-reserved	 
 | 
			
		||||
USAGE	 	non-reserved	non-reserved	reserved
 | 
			
		||||
USER	reserved	reserved	reserved	reserved
 | 
			
		||||
USER_DEFINED_TYPE_CATALOG	 	non-reserved	non-reserved	 
 | 
			
		||||
USER_DEFINED_TYPE_CODE	 	non-reserved	non-reserved	 
 | 
			
		||||
USER_DEFINED_TYPE_NAME	 	non-reserved	non-reserved	 
 | 
			
		||||
USER_DEFINED_TYPE_SCHEMA	 	non-reserved	non-reserved	 
 | 
			
		||||
USING	reserved	reserved	reserved	reserved
 | 
			
		||||
VACUUM	non-reserved	 	 	 
 | 
			
		||||
VALID	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
VALIDATE	non-reserved	 	 	 
 | 
			
		||||
VALIDATOR	non-reserved	 	 	 
 | 
			
		||||
VALUE	non-reserved	reserved	reserved	reserved
 | 
			
		||||
VALUES	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
VALUE_OF	 	reserved	 	 
 | 
			
		||||
VARBINARY	 	reserved	reserved	 
 | 
			
		||||
VARCHAR	non-reserved (cannot be function or type)	reserved	reserved	reserved
 | 
			
		||||
VARIADIC	reserved	 	 	 
 | 
			
		||||
VARYING	non-reserved	reserved	reserved	reserved
 | 
			
		||||
VAR_POP	 	reserved	reserved	 
 | 
			
		||||
VAR_SAMP	 	reserved	reserved	 
 | 
			
		||||
VERBOSE	reserved (can be function or type)	 	 	 
 | 
			
		||||
VERSION	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
VERSIONING	 	reserved	 	 
 | 
			
		||||
VIEW	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
VOLATILE	non-reserved	 	 	 
 | 
			
		||||
WHEN	reserved	reserved	reserved	reserved
 | 
			
		||||
WHENEVER	 	reserved	reserved	reserved
 | 
			
		||||
WHERE	reserved	reserved	reserved	reserved
 | 
			
		||||
WHITESPACE	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
WIDTH_BUCKET	 	reserved	reserved	 
 | 
			
		||||
WINDOW	reserved	reserved	reserved	 
 | 
			
		||||
WITH	reserved	reserved	reserved	reserved
 | 
			
		||||
WITHIN	 	reserved	reserved	 
 | 
			
		||||
WITHOUT	non-reserved	reserved	reserved	 
 | 
			
		||||
WORK	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
WRAPPER	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
WRITE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
XML	non-reserved	reserved	reserved	 
 | 
			
		||||
XMLAGG	 	reserved	reserved	 
 | 
			
		||||
XMLATTRIBUTES	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLBINARY	 	reserved	reserved	 
 | 
			
		||||
XMLCAST	 	reserved	reserved	 
 | 
			
		||||
XMLCOMMENT	 	reserved	reserved	 
 | 
			
		||||
XMLCONCAT	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLDECLARATION	 	non-reserved	non-reserved	 
 | 
			
		||||
XMLDOCUMENT	 	reserved	reserved	 
 | 
			
		||||
XMLELEMENT	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLEXISTS	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLFOREST	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLITERATE	 	reserved	reserved	 
 | 
			
		||||
XMLNAMESPACES	 	reserved	reserved	 
 | 
			
		||||
XMLPARSE	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLPI	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLQUERY	 	reserved	reserved	 
 | 
			
		||||
XMLROOT	non-reserved (cannot be function or type)	 	 	 
 | 
			
		||||
XMLSCHEMA	 	non-reserved	non-reserved	 
 | 
			
		||||
XMLSERIALIZE	non-reserved (cannot be function or type)	reserved	reserved	 
 | 
			
		||||
XMLTABLE	 	reserved	reserved	 
 | 
			
		||||
XMLTEXT	 	reserved	reserved	 
 | 
			
		||||
XMLVALIDATE	 	reserved	reserved	 
 | 
			
		||||
YEAR	non-reserved	reserved	reserved	reserved
 | 
			
		||||
YES	non-reserved	non-reserved	non-reserved	 
 | 
			
		||||
ZONE	non-reserved	non-reserved	non-reserved	reserved
 | 
			
		||||
							
								
								
									
										78
									
								
								vendor/xorm.io/xorm/processors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								vendor/xorm.io/xorm/processors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
// Copyright 2015 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
 | 
			
		||||
 | 
			
		||||
// BeforeInsertProcessor executed before an object is initially persisted to the database
 | 
			
		||||
type BeforeInsertProcessor interface {
 | 
			
		||||
	BeforeInsert()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BeforeUpdateProcessor executed before an object is updated
 | 
			
		||||
type BeforeUpdateProcessor interface {
 | 
			
		||||
	BeforeUpdate()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BeforeDeleteProcessor executed before an object is deleted
 | 
			
		||||
type BeforeDeleteProcessor interface {
 | 
			
		||||
	BeforeDelete()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BeforeSetProcessor executed before data set to the struct fields
 | 
			
		||||
type BeforeSetProcessor interface {
 | 
			
		||||
	BeforeSet(string, Cell)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AfterSetProcessor executed after data set to the struct fields
 | 
			
		||||
type AfterSetProcessor interface {
 | 
			
		||||
	AfterSet(string, Cell)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AfterInsertProcessor executed after an object is persisted to the database
 | 
			
		||||
type AfterInsertProcessor interface {
 | 
			
		||||
	AfterInsert()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AfterUpdateProcessor executed after an object has been updated
 | 
			
		||||
type AfterUpdateProcessor interface {
 | 
			
		||||
	AfterUpdate()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AfterDeleteProcessor executed after an object has been deleted
 | 
			
		||||
type AfterDeleteProcessor interface {
 | 
			
		||||
	AfterDelete()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AfterLoadProcessor executed after an ojbect has been loaded from database
 | 
			
		||||
type AfterLoadProcessor interface {
 | 
			
		||||
	AfterLoad()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AfterLoadSessionProcessor executed after an ojbect has been loaded from database with session parameter
 | 
			
		||||
type AfterLoadSessionProcessor interface {
 | 
			
		||||
	AfterLoad(*Session)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type executedProcessorFunc func(*Session, interface{}) error
 | 
			
		||||
 | 
			
		||||
type executedProcessor struct {
 | 
			
		||||
	fun     executedProcessorFunc
 | 
			
		||||
	session *Session
 | 
			
		||||
	bean    interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (executor *executedProcessor) execute() error {
 | 
			
		||||
	return executor.fun(executor.session, executor.bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) executeProcessors() error {
 | 
			
		||||
	processors := session.afterProcessors
 | 
			
		||||
	session.afterProcessors = make([]executedProcessor, 0)
 | 
			
		||||
	for _, processor := range processors {
 | 
			
		||||
		if err := processor.execute(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										121
									
								
								vendor/xorm.io/xorm/rows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/xorm.io/xorm/rows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Rows rows wrapper a rows to
 | 
			
		||||
type Rows struct {
 | 
			
		||||
	session   *Session
 | 
			
		||||
	rows      *core.Rows
 | 
			
		||||
	beanType  reflect.Type
 | 
			
		||||
	lastError error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newRows(session *Session, bean interface{}) (*Rows, error) {
 | 
			
		||||
	rows := new(Rows)
 | 
			
		||||
	rows.session = session
 | 
			
		||||
	rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
 | 
			
		||||
 | 
			
		||||
	var sqlStr string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if err = rows.session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(session.statement.TableName()) <= 0 {
 | 
			
		||||
		return nil, ErrTableNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rows.session.statement.RawSQL == "" {
 | 
			
		||||
		sqlStr, args, err = rows.session.statement.genGetSQL(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		sqlStr = rows.session.statement.RawSQL
 | 
			
		||||
		args = rows.session.statement.RawParams
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rows.rows, err = rows.session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		rows.lastError = err
 | 
			
		||||
		rows.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rows, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Next move cursor to next record, return false if end has reached
 | 
			
		||||
func (rows *Rows) Next() bool {
 | 
			
		||||
	if rows.lastError == nil && rows.rows != nil {
 | 
			
		||||
		hasNext := rows.rows.Next()
 | 
			
		||||
		if !hasNext {
 | 
			
		||||
			rows.lastError = sql.ErrNoRows
 | 
			
		||||
		}
 | 
			
		||||
		return hasNext
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
 | 
			
		||||
func (rows *Rows) Err() error {
 | 
			
		||||
	return rows.lastError
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Scan row record to bean properties
 | 
			
		||||
func (rows *Rows) Scan(bean interface{}) error {
 | 
			
		||||
	if rows.lastError != nil {
 | 
			
		||||
		return rows.lastError
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
 | 
			
		||||
		return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := rows.session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fields, err := rows.rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scanResults, err := rows.session.row2Slice(rows.rows, fields, bean)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dataStruct := rValue(bean)
 | 
			
		||||
	_, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rows.session.executeProcessors()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close session if session.IsAutoClose is true, and claimed any opened resources
 | 
			
		||||
func (rows *Rows) Close() error {
 | 
			
		||||
	if rows.session.isAutoClose {
 | 
			
		||||
		defer rows.session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rows.rows != nil {
 | 
			
		||||
		return rows.rows.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rows.lastError
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										866
									
								
								vendor/xorm.io/xorm/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										866
									
								
								vendor/xorm.io/xorm/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,866 @@
 | 
			
		||||
// Copyright 2015 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 (
 | 
			
		||||
	"context"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"hash/crc32"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type sessionType int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	engineSession sessionType = iota
 | 
			
		||||
	groupSession
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Session keep a pointer to sql.DB and provides all execution of all
 | 
			
		||||
// kind of database operations.
 | 
			
		||||
type Session struct {
 | 
			
		||||
	db                     *core.DB
 | 
			
		||||
	engine                 *Engine
 | 
			
		||||
	tx                     *core.Tx
 | 
			
		||||
	statement              Statement
 | 
			
		||||
	isAutoCommit           bool
 | 
			
		||||
	isCommitedOrRollbacked bool
 | 
			
		||||
	isAutoClose            bool
 | 
			
		||||
 | 
			
		||||
	// Automatically reset the statement after operations that execute a SQL
 | 
			
		||||
	// query such as Count(), Find(), Get(), ...
 | 
			
		||||
	autoResetStatement bool
 | 
			
		||||
 | 
			
		||||
	// !nashtsai! storing these beans due to yet committed tx
 | 
			
		||||
	afterInsertBeans map[interface{}]*[]func(interface{})
 | 
			
		||||
	afterUpdateBeans map[interface{}]*[]func(interface{})
 | 
			
		||||
	afterDeleteBeans map[interface{}]*[]func(interface{})
 | 
			
		||||
	// --
 | 
			
		||||
 | 
			
		||||
	beforeClosures []func(interface{})
 | 
			
		||||
	afterClosures  []func(interface{})
 | 
			
		||||
 | 
			
		||||
	afterProcessors []executedProcessor
 | 
			
		||||
 | 
			
		||||
	prepareStmt bool
 | 
			
		||||
	stmtCache   map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
 | 
			
		||||
 | 
			
		||||
	// !evalphobia! stored the last executed query on this session
 | 
			
		||||
	//beforeSQLExec func(string, ...interface{})
 | 
			
		||||
	lastSQL     string
 | 
			
		||||
	lastSQLArgs []interface{}
 | 
			
		||||
 | 
			
		||||
	ctx         context.Context
 | 
			
		||||
	sessionType sessionType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clone copy all the session's content and return a new session
 | 
			
		||||
func (session *Session) Clone() *Session {
 | 
			
		||||
	var sess = *session
 | 
			
		||||
	return &sess
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Init reset the session as the init status.
 | 
			
		||||
func (session *Session) Init() {
 | 
			
		||||
	session.statement.Init()
 | 
			
		||||
	session.statement.Engine = session.engine
 | 
			
		||||
	session.isAutoCommit = true
 | 
			
		||||
	session.isCommitedOrRollbacked = false
 | 
			
		||||
	session.isAutoClose = false
 | 
			
		||||
	session.autoResetStatement = true
 | 
			
		||||
	session.prepareStmt = false
 | 
			
		||||
 | 
			
		||||
	// !nashtsai! is lazy init better?
 | 
			
		||||
	session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0)
 | 
			
		||||
	session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0)
 | 
			
		||||
	session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
 | 
			
		||||
	session.beforeClosures = make([]func(interface{}), 0)
 | 
			
		||||
	session.afterClosures = make([]func(interface{}), 0)
 | 
			
		||||
	session.stmtCache = make(map[uint32]*core.Stmt)
 | 
			
		||||
 | 
			
		||||
	session.afterProcessors = make([]executedProcessor, 0)
 | 
			
		||||
 | 
			
		||||
	session.lastSQL = ""
 | 
			
		||||
	session.lastSQLArgs = []interface{}{}
 | 
			
		||||
 | 
			
		||||
	session.ctx = session.engine.defaultContext
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close release the connection from pool
 | 
			
		||||
func (session *Session) Close() {
 | 
			
		||||
	for _, v := range session.stmtCache {
 | 
			
		||||
		v.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.db != nil {
 | 
			
		||||
		// When Close be called, if session is a transaction and do not call
 | 
			
		||||
		// Commit or Rollback, then call Rollback.
 | 
			
		||||
		if session.tx != nil && !session.isCommitedOrRollbacked {
 | 
			
		||||
			session.Rollback()
 | 
			
		||||
		}
 | 
			
		||||
		session.tx = nil
 | 
			
		||||
		session.stmtCache = nil
 | 
			
		||||
		session.db = nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContextCache enable context cache or not
 | 
			
		||||
func (session *Session) ContextCache(context ContextCache) *Session {
 | 
			
		||||
	session.statement.context = context
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsClosed returns if session is closed
 | 
			
		||||
func (session *Session) IsClosed() bool {
 | 
			
		||||
	return session.db == nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) resetStatement() {
 | 
			
		||||
	if session.autoResetStatement {
 | 
			
		||||
		session.statement.Init()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Prepare set a flag to session that should be prepare statement before execute query
 | 
			
		||||
func (session *Session) Prepare() *Session {
 | 
			
		||||
	session.prepareStmt = true
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Before Apply before Processor, affected bean is passed to closure arg
 | 
			
		||||
func (session *Session) Before(closures func(interface{})) *Session {
 | 
			
		||||
	if closures != nil {
 | 
			
		||||
		session.beforeClosures = append(session.beforeClosures, closures)
 | 
			
		||||
	}
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// After Apply after Processor, affected bean is passed to closure arg
 | 
			
		||||
func (session *Session) After(closures func(interface{})) *Session {
 | 
			
		||||
	if closures != nil {
 | 
			
		||||
		session.afterClosures = append(session.afterClosures, closures)
 | 
			
		||||
	}
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Table can input a string or pointer to struct for special a table to operate.
 | 
			
		||||
func (session *Session) Table(tableNameOrBean interface{}) *Session {
 | 
			
		||||
	session.statement.Table(tableNameOrBean)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Alias set the table alias
 | 
			
		||||
func (session *Session) Alias(alias string) *Session {
 | 
			
		||||
	session.statement.Alias(alias)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NoCascade indicate that no cascade load child object
 | 
			
		||||
func (session *Session) NoCascade() *Session {
 | 
			
		||||
	session.statement.UseCascade = false
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ForUpdate Set Read/Write locking for UPDATE
 | 
			
		||||
func (session *Session) ForUpdate() *Session {
 | 
			
		||||
	session.statement.IsForUpdate = true
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NoAutoCondition disable generate SQL condition from beans
 | 
			
		||||
func (session *Session) NoAutoCondition(no ...bool) *Session {
 | 
			
		||||
	session.statement.NoAutoCondition(no...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Limit provide limit and offset query condition
 | 
			
		||||
func (session *Session) Limit(limit int, start ...int) *Session {
 | 
			
		||||
	session.statement.Limit(limit, start...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OrderBy provide order by query condition, the input parameter is the content
 | 
			
		||||
// after order by on a sql statement.
 | 
			
		||||
func (session *Session) OrderBy(order string) *Session {
 | 
			
		||||
	session.statement.OrderBy(order)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Desc provide desc order by query condition, the input parameters are columns.
 | 
			
		||||
func (session *Session) Desc(colNames ...string) *Session {
 | 
			
		||||
	session.statement.Desc(colNames...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Asc provide asc order by query condition, the input parameters are columns.
 | 
			
		||||
func (session *Session) Asc(colNames ...string) *Session {
 | 
			
		||||
	session.statement.Asc(colNames...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StoreEngine is only avialble mysql dialect currently
 | 
			
		||||
func (session *Session) StoreEngine(storeEngine string) *Session {
 | 
			
		||||
	session.statement.StoreEngine = storeEngine
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Charset is only avialble mysql dialect currently
 | 
			
		||||
func (session *Session) Charset(charset string) *Session {
 | 
			
		||||
	session.statement.Charset = charset
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Cascade indicates if loading sub Struct
 | 
			
		||||
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
 | 
			
		||||
	if len(trueOrFalse) >= 1 {
 | 
			
		||||
		session.statement.UseCascade = trueOrFalse[0]
 | 
			
		||||
	}
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NoCache ask this session do not retrieve data from cache system and
 | 
			
		||||
// get data from database directly.
 | 
			
		||||
func (session *Session) NoCache() *Session {
 | 
			
		||||
	session.statement.UseCache = false
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
 | 
			
		||||
func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
 | 
			
		||||
	session.statement.Join(joinOperator, tablename, condition, args...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GroupBy Generate Group By statement
 | 
			
		||||
func (session *Session) GroupBy(keys string) *Session {
 | 
			
		||||
	session.statement.GroupBy(keys)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Having Generate Having statement
 | 
			
		||||
func (session *Session) Having(conditions string) *Session {
 | 
			
		||||
	session.statement.Having(conditions)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DB db return the wrapper of sql.DB
 | 
			
		||||
func (session *Session) DB() *core.DB {
 | 
			
		||||
	if session.db == nil {
 | 
			
		||||
		session.db = session.engine.db
 | 
			
		||||
		session.stmtCache = make(map[uint32]*core.Stmt, 0)
 | 
			
		||||
	}
 | 
			
		||||
	return session.db
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cleanupProcessorsClosures(slices *[]func(interface{})) {
 | 
			
		||||
	if len(*slices) > 0 {
 | 
			
		||||
		*slices = make([]func(interface{}), 0)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) canCache() bool {
 | 
			
		||||
	if session.statement.RefTable == nil ||
 | 
			
		||||
		session.statement.JoinStr != "" ||
 | 
			
		||||
		session.statement.RawSQL != "" ||
 | 
			
		||||
		!session.statement.UseCache ||
 | 
			
		||||
		session.statement.IsForUpdate ||
 | 
			
		||||
		session.tx != nil ||
 | 
			
		||||
		len(session.statement.selectStr) > 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) {
 | 
			
		||||
	crc := crc32.ChecksumIEEE([]byte(sqlStr))
 | 
			
		||||
	// TODO try hash(sqlStr+len(sqlStr))
 | 
			
		||||
	var has bool
 | 
			
		||||
	stmt, has = session.stmtCache[crc]
 | 
			
		||||
	if !has {
 | 
			
		||||
		stmt, err = db.PrepareContext(session.ctx, sqlStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		session.stmtCache[crc] = stmt
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) (*reflect.Value, error) {
 | 
			
		||||
	var col *core.Column
 | 
			
		||||
	if col = table.GetColumnIdx(key, idx); col == nil {
 | 
			
		||||
		return nil, ErrFieldIsNotExist{key, table.Name}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fieldValue, err := col.ValueOfV(dataStruct)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !fieldValue.IsValid() || !fieldValue.CanSet() {
 | 
			
		||||
		return nil, ErrFieldIsNotValid{key, table.Name}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fieldValue, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Cell cell is a result of one column field
 | 
			
		||||
type Cell *interface{}
 | 
			
		||||
 | 
			
		||||
func (session *Session) rows2Beans(rows *core.Rows, fields []string,
 | 
			
		||||
	table *core.Table, newElemFunc func([]string) reflect.Value,
 | 
			
		||||
	sliceValueSetFunc func(*reflect.Value, core.PK) error) error {
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var newValue = newElemFunc(fields)
 | 
			
		||||
		bean := newValue.Interface()
 | 
			
		||||
		dataStruct := newValue.Elem()
 | 
			
		||||
 | 
			
		||||
		// handle beforeClosures
 | 
			
		||||
		scanResults, err := session.row2Slice(rows, fields, bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		pk, err := session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		session.afterProcessors = append(session.afterProcessors, executedProcessor{
 | 
			
		||||
			fun: func(*Session, interface{}) error {
 | 
			
		||||
				return sliceValueSetFunc(&newValue, pk)
 | 
			
		||||
			},
 | 
			
		||||
			session: session,
 | 
			
		||||
			bean:    bean,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) row2Slice(rows *core.Rows, fields []string, bean interface{}) ([]interface{}, error) {
 | 
			
		||||
	for _, closure := range session.beforeClosures {
 | 
			
		||||
		closure(bean)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scanResults := make([]interface{}, len(fields))
 | 
			
		||||
	for i := 0; i < len(fields); i++ {
 | 
			
		||||
		var cell interface{}
 | 
			
		||||
		scanResults[i] = &cell
 | 
			
		||||
	}
 | 
			
		||||
	if err := rows.Scan(scanResults...); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
 | 
			
		||||
		for ii, key := range fields {
 | 
			
		||||
			b.BeforeSet(key, Cell(scanResults[ii].(*interface{})))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return scanResults, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) slice2Bean(scanResults []interface{}, fields []string, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet {
 | 
			
		||||
			for ii, key := range fields {
 | 
			
		||||
				b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// handle afterClosures
 | 
			
		||||
	for _, closure := range session.afterClosures {
 | 
			
		||||
		session.afterProcessors = append(session.afterProcessors, executedProcessor{
 | 
			
		||||
			fun: func(sess *Session, bean interface{}) error {
 | 
			
		||||
				closure(bean)
 | 
			
		||||
				return nil
 | 
			
		||||
			},
 | 
			
		||||
			session: session,
 | 
			
		||||
			bean:    bean,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if a, has := bean.(AfterLoadProcessor); has {
 | 
			
		||||
		session.afterProcessors = append(session.afterProcessors, executedProcessor{
 | 
			
		||||
			fun: func(sess *Session, bean interface{}) error {
 | 
			
		||||
				a.AfterLoad()
 | 
			
		||||
				return nil
 | 
			
		||||
			},
 | 
			
		||||
			session: session,
 | 
			
		||||
			bean:    bean,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if a, has := bean.(AfterLoadSessionProcessor); has {
 | 
			
		||||
		session.afterProcessors = append(session.afterProcessors, executedProcessor{
 | 
			
		||||
			fun: func(sess *Session, bean interface{}) error {
 | 
			
		||||
				a.AfterLoad(sess)
 | 
			
		||||
				return nil
 | 
			
		||||
			},
 | 
			
		||||
			session: session,
 | 
			
		||||
			bean:    bean,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var tempMap = make(map[string]int)
 | 
			
		||||
	var pk core.PK
 | 
			
		||||
	for ii, key := range fields {
 | 
			
		||||
		var idx int
 | 
			
		||||
		var ok bool
 | 
			
		||||
		var lKey = strings.ToLower(key)
 | 
			
		||||
		if idx, ok = tempMap[lKey]; !ok {
 | 
			
		||||
			idx = 0
 | 
			
		||||
		} else {
 | 
			
		||||
			idx = idx + 1
 | 
			
		||||
		}
 | 
			
		||||
		tempMap[lKey] = idx
 | 
			
		||||
 | 
			
		||||
		fieldValue, err := session.getField(dataStruct, key, table, idx)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if !strings.Contains(err.Error(), "is not valid") {
 | 
			
		||||
				session.engine.logger.Warn(err)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if fieldValue == nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
 | 
			
		||||
 | 
			
		||||
		// if row is null then ignore
 | 
			
		||||
		if rawValue.Interface() == nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if fieldValue.CanAddr() {
 | 
			
		||||
			if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 | 
			
		||||
				if data, err := value2Bytes(&rawValue); err == nil {
 | 
			
		||||
					if err := structConvert.FromDB(data); err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, ok := fieldValue.Interface().(core.Conversion); ok {
 | 
			
		||||
			if data, err := value2Bytes(&rawValue); err == nil {
 | 
			
		||||
				if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
 | 
			
		||||
					fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
 | 
			
		||||
				}
 | 
			
		||||
				fieldValue.Interface().(core.Conversion).FromDB(data)
 | 
			
		||||
			} else {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rawValueType := reflect.TypeOf(rawValue.Interface())
 | 
			
		||||
		vv := reflect.ValueOf(rawValue.Interface())
 | 
			
		||||
		col := table.GetColumnIdx(key, idx)
 | 
			
		||||
		if col.IsPrimaryKey {
 | 
			
		||||
			pk = append(pk, rawValue.Interface())
 | 
			
		||||
		}
 | 
			
		||||
		fieldType := fieldValue.Type()
 | 
			
		||||
		hasAssigned := false
 | 
			
		||||
 | 
			
		||||
		if col.SQLType.IsJson() {
 | 
			
		||||
			var bs []byte
 | 
			
		||||
			if rawValueType.Kind() == reflect.String {
 | 
			
		||||
				bs = []byte(vv.String())
 | 
			
		||||
			} else if rawValueType.ConvertibleTo(core.BytesType) {
 | 
			
		||||
				bs = vv.Bytes()
 | 
			
		||||
			} else {
 | 
			
		||||
				return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			hasAssigned = true
 | 
			
		||||
 | 
			
		||||
			if len(bs) > 0 {
 | 
			
		||||
				if fieldType.Kind() == reflect.String {
 | 
			
		||||
					fieldValue.SetString(string(bs))
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if fieldValue.CanAddr() {
 | 
			
		||||
					err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					x := reflect.New(fieldType)
 | 
			
		||||
					err := DefaultJSONHandler.Unmarshal(bs, x.Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
					fieldValue.Set(x.Elem())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch fieldType.Kind() {
 | 
			
		||||
		case reflect.Complex64, reflect.Complex128:
 | 
			
		||||
			// TODO: reimplement this
 | 
			
		||||
			var bs []byte
 | 
			
		||||
			if rawValueType.Kind() == reflect.String {
 | 
			
		||||
				bs = []byte(vv.String())
 | 
			
		||||
			} else if rawValueType.ConvertibleTo(core.BytesType) {
 | 
			
		||||
				bs = vv.Bytes()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			hasAssigned = true
 | 
			
		||||
			if len(bs) > 0 {
 | 
			
		||||
				if fieldValue.CanAddr() {
 | 
			
		||||
					err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					x := reflect.New(fieldType)
 | 
			
		||||
					err := DefaultJSONHandler.Unmarshal(bs, x.Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
					fieldValue.Set(x.Elem())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Slice, reflect.Array:
 | 
			
		||||
			switch rawValueType.Kind() {
 | 
			
		||||
			case reflect.Slice, reflect.Array:
 | 
			
		||||
				switch rawValueType.Elem().Kind() {
 | 
			
		||||
				case reflect.Uint8:
 | 
			
		||||
					if fieldType.Elem().Kind() == reflect.Uint8 {
 | 
			
		||||
						hasAssigned = true
 | 
			
		||||
						if col.SQLType.IsText() {
 | 
			
		||||
							x := reflect.New(fieldType)
 | 
			
		||||
							err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface())
 | 
			
		||||
							if err != nil {
 | 
			
		||||
								return nil, err
 | 
			
		||||
							}
 | 
			
		||||
							fieldValue.Set(x.Elem())
 | 
			
		||||
						} else {
 | 
			
		||||
							if fieldValue.Len() > 0 {
 | 
			
		||||
								for i := 0; i < fieldValue.Len(); i++ {
 | 
			
		||||
									if i < vv.Len() {
 | 
			
		||||
										fieldValue.Index(i).Set(vv.Index(i))
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
							} else {
 | 
			
		||||
								for i := 0; i < vv.Len(); i++ {
 | 
			
		||||
									fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.String:
 | 
			
		||||
			if rawValueType.Kind() == reflect.String {
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				fieldValue.SetString(vv.String())
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Bool:
 | 
			
		||||
			if rawValueType.Kind() == reflect.Bool {
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				fieldValue.SetBool(vv.Bool())
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
			switch rawValueType.Kind() {
 | 
			
		||||
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				fieldValue.SetInt(vv.Int())
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Float32, reflect.Float64:
 | 
			
		||||
			switch rawValueType.Kind() {
 | 
			
		||||
			case reflect.Float32, reflect.Float64:
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				fieldValue.SetFloat(vv.Float())
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
 | 
			
		||||
			switch rawValueType.Kind() {
 | 
			
		||||
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				fieldValue.SetUint(vv.Uint())
 | 
			
		||||
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				fieldValue.SetUint(uint64(vv.Int()))
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			if fieldType.ConvertibleTo(core.TimeType) {
 | 
			
		||||
				dbTZ := session.engine.DatabaseTZ
 | 
			
		||||
				if col.TimeZone != nil {
 | 
			
		||||
					dbTZ = col.TimeZone
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if rawValueType == core.TimeType {
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
 | 
			
		||||
					t := vv.Convert(core.TimeType).Interface().(time.Time)
 | 
			
		||||
 | 
			
		||||
					z, _ := t.Zone()
 | 
			
		||||
					// set new location if database don't save timezone or give an incorrect timezone
 | 
			
		||||
					if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
 | 
			
		||||
						session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
 | 
			
		||||
						t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
 | 
			
		||||
							t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					t = t.In(session.engine.TZLocation)
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 | 
			
		||||
				} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
 | 
			
		||||
					rawValueType == core.Int32Type {
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
 | 
			
		||||
					t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 | 
			
		||||
				} else {
 | 
			
		||||
					if d, ok := vv.Interface().([]uint8); ok {
 | 
			
		||||
						hasAssigned = true
 | 
			
		||||
						t, err := session.byte2Time(col, d)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							session.engine.logger.Error("byte2Time error:", err.Error())
 | 
			
		||||
							hasAssigned = false
 | 
			
		||||
						} else {
 | 
			
		||||
							fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 | 
			
		||||
						}
 | 
			
		||||
					} else if d, ok := vv.Interface().(string); ok {
 | 
			
		||||
						hasAssigned = true
 | 
			
		||||
						t, err := session.str2Time(col, d)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							session.engine.logger.Error("byte2Time error:", err.Error())
 | 
			
		||||
							hasAssigned = false
 | 
			
		||||
						} else {
 | 
			
		||||
							fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
 | 
			
		||||
				// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				if err := nulVal.Scan(vv.Interface()); err != nil {
 | 
			
		||||
					session.engine.logger.Error("sql.Sanner error:", err.Error())
 | 
			
		||||
					hasAssigned = false
 | 
			
		||||
				}
 | 
			
		||||
			} else if col.SQLType.IsJson() {
 | 
			
		||||
				if rawValueType.Kind() == reflect.String {
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					x := reflect.New(fieldType)
 | 
			
		||||
					if len([]byte(vv.String())) > 0 {
 | 
			
		||||
						err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), x.Interface())
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return nil, err
 | 
			
		||||
						}
 | 
			
		||||
						fieldValue.Set(x.Elem())
 | 
			
		||||
					}
 | 
			
		||||
				} else if rawValueType.Kind() == reflect.Slice {
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					x := reflect.New(fieldType)
 | 
			
		||||
					if len(vv.Bytes()) > 0 {
 | 
			
		||||
						err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface())
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return nil, err
 | 
			
		||||
						}
 | 
			
		||||
						fieldValue.Set(x.Elem())
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if session.statement.UseCascade {
 | 
			
		||||
				table, err := session.engine.autoMapType(*fieldValue)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
				if len(table.PrimaryKeys) != 1 {
 | 
			
		||||
					return nil, errors.New("unsupported non or composited primary key cascade")
 | 
			
		||||
				}
 | 
			
		||||
				var pk = make(core.PK, len(table.PrimaryKeys))
 | 
			
		||||
				pk[0], err = asKind(vv, rawValueType)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if !isPKZero(pk) {
 | 
			
		||||
					// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
 | 
			
		||||
					// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
 | 
			
		||||
					// property to be fetched lazily
 | 
			
		||||
					structInter := reflect.New(fieldValue.Type())
 | 
			
		||||
					has, err := session.ID(pk).NoCascade().get(structInter.Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
					if has {
 | 
			
		||||
						fieldValue.Set(structInter.Elem())
 | 
			
		||||
					} else {
 | 
			
		||||
						return nil, errors.New("cascade obj is not exist")
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Ptr:
 | 
			
		||||
			// !nashtsai! TODO merge duplicated codes above
 | 
			
		||||
			switch fieldType {
 | 
			
		||||
			// following types case matching ptr's native type, therefore assign ptr directly
 | 
			
		||||
			case core.PtrStringType:
 | 
			
		||||
				if rawValueType.Kind() == reflect.String {
 | 
			
		||||
					x := vv.String()
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrBoolType:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Bool {
 | 
			
		||||
					x := vv.Bool()
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrTimeType:
 | 
			
		||||
				if rawValueType == core.PtrTimeType {
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					var x = rawValue.Interface().(time.Time)
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrFloat64Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Float64 {
 | 
			
		||||
					x := vv.Float()
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrUint64Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = uint64(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrInt64Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					x := vv.Int()
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrFloat32Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Float64 {
 | 
			
		||||
					var x = float32(vv.Float())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrIntType:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = int(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrInt32Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = int32(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrInt8Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = int8(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrInt16Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = int16(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrUintType:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = uint(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.PtrUint32Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = uint32(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.Uint8Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = uint8(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.Uint16Type:
 | 
			
		||||
				if rawValueType.Kind() == reflect.Int64 {
 | 
			
		||||
					var x = uint16(vv.Int())
 | 
			
		||||
					hasAssigned = true
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
			case core.Complex64Type:
 | 
			
		||||
				var x complex64
 | 
			
		||||
				if len([]byte(vv.String())) > 0 {
 | 
			
		||||
					err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
			case core.Complex128Type:
 | 
			
		||||
				var x complex128
 | 
			
		||||
				if len([]byte(vv.String())) > 0 {
 | 
			
		||||
					err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return nil, err
 | 
			
		||||
					}
 | 
			
		||||
					fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
				}
 | 
			
		||||
				hasAssigned = true
 | 
			
		||||
			} // switch fieldType
 | 
			
		||||
		} // switch fieldType.Kind()
 | 
			
		||||
 | 
			
		||||
		// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
 | 
			
		||||
		if !hasAssigned {
 | 
			
		||||
			data, err := value2Bytes(&rawValue)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err = session.bytes2Value(col, fieldValue, data); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return pk, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// saveLastSQL stores executed query information
 | 
			
		||||
func (session *Session) saveLastSQL(sql string, args ...interface{}) {
 | 
			
		||||
	session.lastSQL = sql
 | 
			
		||||
	session.lastSQLArgs = args
 | 
			
		||||
	session.engine.logSQL(sql, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LastSQL returns last query information
 | 
			
		||||
func (session *Session) LastSQL() (string, []interface{}) {
 | 
			
		||||
	return session.lastSQL, session.lastSQLArgs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unscoped always disable struct tag "deleted"
 | 
			
		||||
func (session *Session) Unscoped() *Session {
 | 
			
		||||
	session.statement.Unscoped()
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) {
 | 
			
		||||
	switch fieldValue.Kind() {
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		fieldValue.SetInt(fieldValue.Int() + 1)
 | 
			
		||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
		fieldValue.SetUint(fieldValue.Uint() + 1)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										156
									
								
								vendor/xorm.io/xorm/session_cols.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								vendor/xorm.io/xorm/session_cols.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func setColumnInt(bean interface{}, col *core.Column, t int64) {
 | 
			
		||||
	v, err := col.ValueOf(bean)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if v.CanSet() {
 | 
			
		||||
		switch v.Type().Kind() {
 | 
			
		||||
		case reflect.Int, reflect.Int64, reflect.Int32:
 | 
			
		||||
			v.SetInt(t)
 | 
			
		||||
		case reflect.Uint, reflect.Uint64, reflect.Uint32:
 | 
			
		||||
			v.SetUint(uint64(t))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
 | 
			
		||||
	v, err := col.ValueOf(bean)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if v.CanSet() {
 | 
			
		||||
		switch v.Type().Kind() {
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			v.Set(reflect.ValueOf(t).Convert(v.Type()))
 | 
			
		||||
		case reflect.Int, reflect.Int64, reflect.Int32:
 | 
			
		||||
			v.SetInt(t.Unix())
 | 
			
		||||
		case reflect.Uint, reflect.Uint64, reflect.Uint32:
 | 
			
		||||
			v.SetUint(uint64(t.Unix()))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
 | 
			
		||||
	if len(m) == 0 {
 | 
			
		||||
		return false, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n := len(col.Name)
 | 
			
		||||
 | 
			
		||||
	for mk := range m {
 | 
			
		||||
		if len(mk) != n {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.EqualFold(mk, col.Name) {
 | 
			
		||||
			return m[mk], true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func col2NewCols(columns ...string) []string {
 | 
			
		||||
	newColumns := make([]string, 0, len(columns))
 | 
			
		||||
	for _, col := range columns {
 | 
			
		||||
		col = strings.Replace(col, "`", "", -1)
 | 
			
		||||
		col = strings.Replace(col, `"`, "", -1)
 | 
			
		||||
		ccols := strings.Split(col, ",")
 | 
			
		||||
		for _, c := range ccols {
 | 
			
		||||
			newColumns = append(newColumns, strings.TrimSpace(c))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return newColumns
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Incr provides a query string like "count = count + 1"
 | 
			
		||||
func (session *Session) Incr(column string, arg ...interface{}) *Session {
 | 
			
		||||
	session.statement.Incr(column, arg...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Decr provides a query string like "count = count - 1"
 | 
			
		||||
func (session *Session) Decr(column string, arg ...interface{}) *Session {
 | 
			
		||||
	session.statement.Decr(column, arg...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetExpr provides a query string like "column = {expression}"
 | 
			
		||||
func (session *Session) SetExpr(column string, expression interface{}) *Session {
 | 
			
		||||
	session.statement.SetExpr(column, expression)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Select provides some columns to special
 | 
			
		||||
func (session *Session) Select(str string) *Session {
 | 
			
		||||
	session.statement.Select(str)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Cols provides some columns to special
 | 
			
		||||
func (session *Session) Cols(columns ...string) *Session {
 | 
			
		||||
	session.statement.Cols(columns...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AllCols ask all columns
 | 
			
		||||
func (session *Session) AllCols() *Session {
 | 
			
		||||
	session.statement.AllCols()
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MustCols specify some columns must use even if they are empty
 | 
			
		||||
func (session *Session) MustCols(columns ...string) *Session {
 | 
			
		||||
	session.statement.MustCols(columns...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UseBool automatically retrieve condition according struct, but
 | 
			
		||||
// if struct has bool field, it will ignore them. So use UseBool
 | 
			
		||||
// to tell system to do not ignore them.
 | 
			
		||||
// If no parameters, it will use all the bool field of struct, or
 | 
			
		||||
// it will use parameters's columns
 | 
			
		||||
func (session *Session) UseBool(columns ...string) *Session {
 | 
			
		||||
	session.statement.UseBool(columns...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Distinct use for distinct columns. Caution: when you are using cache,
 | 
			
		||||
// distinct will not be cached because cache system need id,
 | 
			
		||||
// but distinct will not provide id
 | 
			
		||||
func (session *Session) Distinct(columns ...string) *Session {
 | 
			
		||||
	session.statement.Distinct(columns...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Omit Only not use the parameters as select or update columns
 | 
			
		||||
func (session *Session) Omit(columns ...string) *Session {
 | 
			
		||||
	session.statement.Omit(columns...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Nullable Set null when column is zero-value and nullable for update
 | 
			
		||||
func (session *Session) Nullable(columns ...string) *Session {
 | 
			
		||||
	session.statement.Nullable(columns...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NoAutoTime means do not automatically give created field and updated field
 | 
			
		||||
// the current time on the current session temporarily
 | 
			
		||||
func (session *Session) NoAutoTime() *Session {
 | 
			
		||||
	session.statement.UseAutoTime = false
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								vendor/xorm.io/xorm/session_cond.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								vendor/xorm.io/xorm/session_cond.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
// Copyright 2017 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 "xorm.io/builder"
 | 
			
		||||
 | 
			
		||||
// Sql provides raw sql input parameter. When you have a complex SQL statement
 | 
			
		||||
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use SQL instead.
 | 
			
		||||
func (session *Session) Sql(query string, args ...interface{}) *Session {
 | 
			
		||||
	return session.SQL(query, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SQL provides raw sql input parameter. When you have a complex SQL statement
 | 
			
		||||
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL.
 | 
			
		||||
func (session *Session) SQL(query interface{}, args ...interface{}) *Session {
 | 
			
		||||
	session.statement.SQL(query, args...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Where provides custom query condition.
 | 
			
		||||
func (session *Session) Where(query interface{}, args ...interface{}) *Session {
 | 
			
		||||
	session.statement.Where(query, args...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// And provides custom query condition.
 | 
			
		||||
func (session *Session) And(query interface{}, args ...interface{}) *Session {
 | 
			
		||||
	session.statement.And(query, args...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Or provides custom query condition.
 | 
			
		||||
func (session *Session) Or(query interface{}, args ...interface{}) *Session {
 | 
			
		||||
	session.statement.Or(query, args...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Id provides converting id as a query condition
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use ID instead
 | 
			
		||||
func (session *Session) Id(id interface{}) *Session {
 | 
			
		||||
	return session.ID(id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ID provides converting id as a query condition
 | 
			
		||||
func (session *Session) ID(id interface{}) *Session {
 | 
			
		||||
	session.statement.ID(id)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// In provides a query string like "id in (1, 2, 3)"
 | 
			
		||||
func (session *Session) In(column string, args ...interface{}) *Session {
 | 
			
		||||
	session.statement.In(column, args...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NotIn provides a query string like "id in (1, 2, 3)"
 | 
			
		||||
func (session *Session) NotIn(column string, args ...interface{}) *Session {
 | 
			
		||||
	session.statement.NotIn(column, args...)
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Conds returns session query conditions except auto bean conditions
 | 
			
		||||
func (session *Session) Conds() builder.Cond {
 | 
			
		||||
	return session.statement.cond
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/xorm.io/xorm/session_context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/xorm.io/xorm/session_context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
// 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 "context"
 | 
			
		||||
 | 
			
		||||
// Context sets the context on this session
 | 
			
		||||
func (session *Session) Context(ctx context.Context) *Session {
 | 
			
		||||
	session.ctx = ctx
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PingContext test if database is ok
 | 
			
		||||
func (session *Session) PingContext(ctx context.Context) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
 | 
			
		||||
	return session.DB().PingContext(ctx)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										671
									
								
								vendor/xorm.io/xorm/session_convert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										671
									
								
								vendor/xorm.io/xorm/session_convert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,671 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"database/sql/driver"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) {
 | 
			
		||||
	sdata := strings.TrimSpace(data)
 | 
			
		||||
	var x time.Time
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	var parseLoc = session.engine.DatabaseTZ
 | 
			
		||||
	if col.TimeZone != nil {
 | 
			
		||||
		parseLoc = col.TimeZone
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sdata == zeroTime0 || sdata == zeroTime1 {
 | 
			
		||||
	} else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
 | 
			
		||||
		// time stamp
 | 
			
		||||
		sd, err := strconv.ParseInt(sdata, 10, 64)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			x = time.Unix(sd, 0)
 | 
			
		||||
			//session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
		} else {
 | 
			
		||||
			//session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
		}
 | 
			
		||||
	} else if len(sdata) > 19 && strings.Contains(sdata, "-") {
 | 
			
		||||
		x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc)
 | 
			
		||||
		session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc)
 | 
			
		||||
			//session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc)
 | 
			
		||||
			//session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
		}
 | 
			
		||||
	} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
 | 
			
		||||
		x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc)
 | 
			
		||||
		//session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
	} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
 | 
			
		||||
		x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc)
 | 
			
		||||
		//session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
	} else if col.SQLType.Name == core.Time {
 | 
			
		||||
		if strings.Contains(sdata, " ") {
 | 
			
		||||
			ssd := strings.Split(sdata, " ")
 | 
			
		||||
			sdata = ssd[1]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sdata = strings.TrimSpace(sdata)
 | 
			
		||||
		if session.engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
 | 
			
		||||
			sdata = sdata[len(sdata)-8:]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		st := fmt.Sprintf("2006-01-02 %v", sdata)
 | 
			
		||||
		x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc)
 | 
			
		||||
		//session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
 | 
			
		||||
	} else {
 | 
			
		||||
		outErr = fmt.Errorf("unsupported time format %v", sdata)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	outTime = x.In(session.engine.TZLocation)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) {
 | 
			
		||||
	return session.str2Time(col, string(data))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	nullFloatType = reflect.TypeOf(sql.NullFloat64{})
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// convert a db data([]byte) to a field value
 | 
			
		||||
func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error {
 | 
			
		||||
	if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 | 
			
		||||
		return structConvert.FromDB(data)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
 | 
			
		||||
		return structConvert.FromDB(data)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var v interface{}
 | 
			
		||||
	key := col.Name
 | 
			
		||||
	fieldType := fieldValue.Type()
 | 
			
		||||
 | 
			
		||||
	switch fieldType.Kind() {
 | 
			
		||||
	case reflect.Complex64, reflect.Complex128:
 | 
			
		||||
		x := reflect.New(fieldType)
 | 
			
		||||
		if len(data) > 0 {
 | 
			
		||||
			err := DefaultJSONHandler.Unmarshal(data, x.Interface())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				session.engine.logger.Error(err)
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(x.Elem())
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Slice, reflect.Array, reflect.Map:
 | 
			
		||||
		v = data
 | 
			
		||||
		t := fieldType.Elem()
 | 
			
		||||
		k := t.Kind()
 | 
			
		||||
		if col.SQLType.IsText() {
 | 
			
		||||
			x := reflect.New(fieldType)
 | 
			
		||||
			if len(data) > 0 {
 | 
			
		||||
				err := DefaultJSONHandler.Unmarshal(data, x.Interface())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					session.engine.logger.Error(err)
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				fieldValue.Set(x.Elem())
 | 
			
		||||
			}
 | 
			
		||||
		} else if col.SQLType.IsBlob() {
 | 
			
		||||
			if k == reflect.Uint8 {
 | 
			
		||||
				fieldValue.Set(reflect.ValueOf(v))
 | 
			
		||||
			} else {
 | 
			
		||||
				x := reflect.New(fieldType)
 | 
			
		||||
				if len(data) > 0 {
 | 
			
		||||
					err := DefaultJSONHandler.Unmarshal(data, x.Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						session.engine.logger.Error(err)
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					fieldValue.Set(x.Elem())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return ErrUnSupportedType
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		fieldValue.SetString(string(data))
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		v, err := asBool(data)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("arg %v as bool: %s", key, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		fieldValue.Set(reflect.ValueOf(v))
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		sdata := string(data)
 | 
			
		||||
		var x int64
 | 
			
		||||
		var err error
 | 
			
		||||
		// for mysql, when use bit, it returned \x01
 | 
			
		||||
		if col.SQLType.Name == core.Bit &&
 | 
			
		||||
			session.engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
 | 
			
		||||
			if len(data) == 1 {
 | 
			
		||||
				x = int64(data[0])
 | 
			
		||||
			} else {
 | 
			
		||||
				x = 0
 | 
			
		||||
			}
 | 
			
		||||
		} else if strings.HasPrefix(sdata, "0x") {
 | 
			
		||||
			x, err = strconv.ParseInt(sdata, 16, 64)
 | 
			
		||||
		} else if strings.HasPrefix(sdata, "0") {
 | 
			
		||||
			x, err = strconv.ParseInt(sdata, 8, 64)
 | 
			
		||||
		} else if strings.EqualFold(sdata, "true") {
 | 
			
		||||
			x = 1
 | 
			
		||||
		} else if strings.EqualFold(sdata, "false") {
 | 
			
		||||
			x = 0
 | 
			
		||||
		} else {
 | 
			
		||||
			x, err = strconv.ParseInt(sdata, 10, 64)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		fieldValue.SetInt(x)
 | 
			
		||||
	case reflect.Float32, reflect.Float64:
 | 
			
		||||
		x, err := strconv.ParseFloat(string(data), 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("arg %v as float64: %s", key, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		fieldValue.SetFloat(x)
 | 
			
		||||
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
 | 
			
		||||
		x, err := strconv.ParseUint(string(data), 10, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		fieldValue.SetUint(x)
 | 
			
		||||
	//Currently only support Time type
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		// !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
 | 
			
		||||
		if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
 | 
			
		||||
			if err := nulVal.Scan(data); err != nil {
 | 
			
		||||
				return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if fieldType.ConvertibleTo(core.TimeType) {
 | 
			
		||||
				x, err := session.byte2Time(col, data)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				v = x
 | 
			
		||||
				fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
 | 
			
		||||
			} else if session.statement.UseCascade {
 | 
			
		||||
				table, err := session.engine.autoMapType(*fieldValue)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// TODO: current only support 1 primary key
 | 
			
		||||
				if len(table.PrimaryKeys) > 1 {
 | 
			
		||||
					return errors.New("unsupported composited primary key cascade")
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				var pk = make(core.PK, len(table.PrimaryKeys))
 | 
			
		||||
				rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
 | 
			
		||||
				pk[0], err = str2PK(string(data), rawValueType)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if !isPKZero(pk) {
 | 
			
		||||
					// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
 | 
			
		||||
					// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
 | 
			
		||||
					// property to be fetched lazily
 | 
			
		||||
					structInter := reflect.New(fieldValue.Type())
 | 
			
		||||
					has, err := session.ID(pk).NoCascade().get(structInter.Interface())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					if has {
 | 
			
		||||
						v = structInter.Elem().Interface()
 | 
			
		||||
						fieldValue.Set(reflect.ValueOf(v))
 | 
			
		||||
					} else {
 | 
			
		||||
						return errors.New("cascade obj is not exist")
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		// !nashtsai! TODO merge duplicated codes above
 | 
			
		||||
		//typeStr := fieldType.String()
 | 
			
		||||
		switch fieldType.Elem().Kind() {
 | 
			
		||||
		// case "*string":
 | 
			
		||||
		case core.StringType.Kind():
 | 
			
		||||
			x := string(data)
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*bool":
 | 
			
		||||
		case core.BoolType.Kind():
 | 
			
		||||
			d := string(data)
 | 
			
		||||
			v, err := strconv.ParseBool(d)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as bool: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
 | 
			
		||||
		// case "*complex64":
 | 
			
		||||
		case core.Complex64Type.Kind():
 | 
			
		||||
			var x complex64
 | 
			
		||||
			if len(data) > 0 {
 | 
			
		||||
				err := DefaultJSONHandler.Unmarshal(data, &x)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					session.engine.logger.Error(err)
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
			}
 | 
			
		||||
		// case "*complex128":
 | 
			
		||||
		case core.Complex128Type.Kind():
 | 
			
		||||
			var x complex128
 | 
			
		||||
			if len(data) > 0 {
 | 
			
		||||
				err := DefaultJSONHandler.Unmarshal(data, &x)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					session.engine.logger.Error(err)
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
			}
 | 
			
		||||
		// case "*float64":
 | 
			
		||||
		case core.Float64Type.Kind():
 | 
			
		||||
			x, err := strconv.ParseFloat(string(data), 64)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as float64: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*float32":
 | 
			
		||||
		case core.Float32Type.Kind():
 | 
			
		||||
			var x float32
 | 
			
		||||
			x1, err := strconv.ParseFloat(string(data), 32)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as float32: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			x = float32(x1)
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*uint64":
 | 
			
		||||
		case core.Uint64Type.Kind():
 | 
			
		||||
			var x uint64
 | 
			
		||||
			x, err := strconv.ParseUint(string(data), 10, 64)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*uint":
 | 
			
		||||
		case core.UintType.Kind():
 | 
			
		||||
			var x uint
 | 
			
		||||
			x1, err := strconv.ParseUint(string(data), 10, 64)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			x = uint(x1)
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*uint32":
 | 
			
		||||
		case core.Uint32Type.Kind():
 | 
			
		||||
			var x uint32
 | 
			
		||||
			x1, err := strconv.ParseUint(string(data), 10, 64)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			x = uint32(x1)
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*uint8":
 | 
			
		||||
		case core.Uint8Type.Kind():
 | 
			
		||||
			var x uint8
 | 
			
		||||
			x1, err := strconv.ParseUint(string(data), 10, 64)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			x = uint8(x1)
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*uint16":
 | 
			
		||||
		case core.Uint16Type.Kind():
 | 
			
		||||
			var x uint16
 | 
			
		||||
			x1, err := strconv.ParseUint(string(data), 10, 64)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			x = uint16(x1)
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*int64":
 | 
			
		||||
		case core.Int64Type.Kind():
 | 
			
		||||
			sdata := string(data)
 | 
			
		||||
			var x int64
 | 
			
		||||
			var err error
 | 
			
		||||
			// for mysql, when use bit, it returned \x01
 | 
			
		||||
			if col.SQLType.Name == core.Bit &&
 | 
			
		||||
				strings.Contains(session.engine.DriverName(), "mysql") {
 | 
			
		||||
				if len(data) == 1 {
 | 
			
		||||
					x = int64(data[0])
 | 
			
		||||
				} else {
 | 
			
		||||
					x = 0
 | 
			
		||||
				}
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0x") {
 | 
			
		||||
				x, err = strconv.ParseInt(sdata, 16, 64)
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0") {
 | 
			
		||||
				x, err = strconv.ParseInt(sdata, 8, 64)
 | 
			
		||||
			} else {
 | 
			
		||||
				x, err = strconv.ParseInt(sdata, 10, 64)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*int":
 | 
			
		||||
		case core.IntType.Kind():
 | 
			
		||||
			sdata := string(data)
 | 
			
		||||
			var x int
 | 
			
		||||
			var x1 int64
 | 
			
		||||
			var err error
 | 
			
		||||
			// for mysql, when use bit, it returned \x01
 | 
			
		||||
			if col.SQLType.Name == core.Bit &&
 | 
			
		||||
				strings.Contains(session.engine.DriverName(), "mysql") {
 | 
			
		||||
				if len(data) == 1 {
 | 
			
		||||
					x = int(data[0])
 | 
			
		||||
				} else {
 | 
			
		||||
					x = 0
 | 
			
		||||
				}
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0x") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 16, 64)
 | 
			
		||||
				x = int(x1)
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 8, 64)
 | 
			
		||||
				x = int(x1)
 | 
			
		||||
			} else {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 10, 64)
 | 
			
		||||
				x = int(x1)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*int32":
 | 
			
		||||
		case core.Int32Type.Kind():
 | 
			
		||||
			sdata := string(data)
 | 
			
		||||
			var x int32
 | 
			
		||||
			var x1 int64
 | 
			
		||||
			var err error
 | 
			
		||||
			// for mysql, when use bit, it returned \x01
 | 
			
		||||
			if col.SQLType.Name == core.Bit &&
 | 
			
		||||
				session.engine.dialect.DBType() == core.MYSQL {
 | 
			
		||||
				if len(data) == 1 {
 | 
			
		||||
					x = int32(data[0])
 | 
			
		||||
				} else {
 | 
			
		||||
					x = 0
 | 
			
		||||
				}
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0x") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 16, 64)
 | 
			
		||||
				x = int32(x1)
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 8, 64)
 | 
			
		||||
				x = int32(x1)
 | 
			
		||||
			} else {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 10, 64)
 | 
			
		||||
				x = int32(x1)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*int8":
 | 
			
		||||
		case core.Int8Type.Kind():
 | 
			
		||||
			sdata := string(data)
 | 
			
		||||
			var x int8
 | 
			
		||||
			var x1 int64
 | 
			
		||||
			var err error
 | 
			
		||||
			// for mysql, when use bit, it returned \x01
 | 
			
		||||
			if col.SQLType.Name == core.Bit &&
 | 
			
		||||
				strings.Contains(session.engine.DriverName(), "mysql") {
 | 
			
		||||
				if len(data) == 1 {
 | 
			
		||||
					x = int8(data[0])
 | 
			
		||||
				} else {
 | 
			
		||||
					x = 0
 | 
			
		||||
				}
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0x") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 16, 64)
 | 
			
		||||
				x = int8(x1)
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 8, 64)
 | 
			
		||||
				x = int8(x1)
 | 
			
		||||
			} else {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 10, 64)
 | 
			
		||||
				x = int8(x1)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*int16":
 | 
			
		||||
		case core.Int16Type.Kind():
 | 
			
		||||
			sdata := string(data)
 | 
			
		||||
			var x int16
 | 
			
		||||
			var x1 int64
 | 
			
		||||
			var err error
 | 
			
		||||
			// for mysql, when use bit, it returned \x01
 | 
			
		||||
			if col.SQLType.Name == core.Bit &&
 | 
			
		||||
				strings.Contains(session.engine.DriverName(), "mysql") {
 | 
			
		||||
				if len(data) == 1 {
 | 
			
		||||
					x = int16(data[0])
 | 
			
		||||
				} else {
 | 
			
		||||
					x = 0
 | 
			
		||||
				}
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0x") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 16, 64)
 | 
			
		||||
				x = int16(x1)
 | 
			
		||||
			} else if strings.HasPrefix(sdata, "0") {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 8, 64)
 | 
			
		||||
				x = int16(x1)
 | 
			
		||||
			} else {
 | 
			
		||||
				x1, err = strconv.ParseInt(sdata, 10, 64)
 | 
			
		||||
				x = int16(x1)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("arg %v as int: %s", key, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
 | 
			
		||||
		// case "*SomeStruct":
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			switch fieldType {
 | 
			
		||||
			// case "*.time.Time":
 | 
			
		||||
			case core.PtrTimeType:
 | 
			
		||||
				x, err := session.byte2Time(col, data)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				v = x
 | 
			
		||||
				fieldValue.Set(reflect.ValueOf(&x))
 | 
			
		||||
			default:
 | 
			
		||||
				if session.statement.UseCascade {
 | 
			
		||||
					structInter := reflect.New(fieldType.Elem())
 | 
			
		||||
					table, err := session.engine.autoMapType(structInter.Elem())
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if len(table.PrimaryKeys) > 1 {
 | 
			
		||||
						return errors.New("unsupported composited primary key cascade")
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					var pk = make(core.PK, len(table.PrimaryKeys))
 | 
			
		||||
					rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
 | 
			
		||||
					pk[0], err = str2PK(string(data), rawValueType)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if !isPKZero(pk) {
 | 
			
		||||
						// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
 | 
			
		||||
						// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
 | 
			
		||||
						// property to be fetched lazily
 | 
			
		||||
						has, err := session.ID(pk).NoCascade().get(structInter.Interface())
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return err
 | 
			
		||||
						}
 | 
			
		||||
						if has {
 | 
			
		||||
							v = structInter.Interface()
 | 
			
		||||
							fieldValue.Set(reflect.ValueOf(v))
 | 
			
		||||
						} else {
 | 
			
		||||
							return errors.New("cascade obj is not exist")
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// convert a field value of a struct to interface for put into db
 | 
			
		||||
func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
 | 
			
		||||
	if fieldValue.CanAddr() {
 | 
			
		||||
		if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
 | 
			
		||||
			data, err := fieldConvert.ToDB()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			if col.SQLType.IsBlob() {
 | 
			
		||||
				return data, nil
 | 
			
		||||
			}
 | 
			
		||||
			return string(data), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
 | 
			
		||||
		data, err := fieldConvert.ToDB()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		if col.SQLType.IsBlob() {
 | 
			
		||||
			return data, nil
 | 
			
		||||
		}
 | 
			
		||||
		return string(data), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fieldType := fieldValue.Type()
 | 
			
		||||
	k := fieldType.Kind()
 | 
			
		||||
	if k == reflect.Ptr {
 | 
			
		||||
		if fieldValue.IsNil() {
 | 
			
		||||
			return nil, nil
 | 
			
		||||
		} else if !fieldValue.IsValid() {
 | 
			
		||||
			session.engine.logger.Warn("the field[", col.FieldName, "] is invalid")
 | 
			
		||||
			return nil, nil
 | 
			
		||||
		} else {
 | 
			
		||||
			// !nashtsai! deference pointer type to instance type
 | 
			
		||||
			fieldValue = fieldValue.Elem()
 | 
			
		||||
			fieldType = fieldValue.Type()
 | 
			
		||||
			k = fieldType.Kind()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch k {
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		return fieldValue.Bool(), nil
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		return fieldValue.String(), nil
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		if fieldType.ConvertibleTo(core.TimeType) {
 | 
			
		||||
			t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
 | 
			
		||||
			tf := session.engine.formatColTime(col, t)
 | 
			
		||||
			return tf, nil
 | 
			
		||||
		} else if fieldType.ConvertibleTo(nullFloatType) {
 | 
			
		||||
			t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64)
 | 
			
		||||
			if !t.Valid {
 | 
			
		||||
				return nil, nil
 | 
			
		||||
			}
 | 
			
		||||
			return t.Float64, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !col.SQLType.IsJson() {
 | 
			
		||||
			// !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
 | 
			
		||||
			if v, ok := fieldValue.Interface().(driver.Valuer); ok {
 | 
			
		||||
				return v.Value()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			fieldTable, err := session.engine.autoMapType(fieldValue)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			if len(fieldTable.PrimaryKeys) == 1 {
 | 
			
		||||
				pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
 | 
			
		||||
				return pkField.Interface(), nil
 | 
			
		||||
			}
 | 
			
		||||
			return 0, fmt.Errorf("no primary key for col %v", col.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if col.SQLType.IsText() {
 | 
			
		||||
			bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				session.engine.logger.Error(err)
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			return string(bytes), nil
 | 
			
		||||
		} else if col.SQLType.IsBlob() {
 | 
			
		||||
			bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				session.engine.logger.Error(err)
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			return bytes, nil
 | 
			
		||||
		}
 | 
			
		||||
		return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
 | 
			
		||||
	case reflect.Complex64, reflect.Complex128:
 | 
			
		||||
		bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			session.engine.logger.Error(err)
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return string(bytes), nil
 | 
			
		||||
	case reflect.Array, reflect.Slice, reflect.Map:
 | 
			
		||||
		if !fieldValue.IsValid() {
 | 
			
		||||
			return fieldValue.Interface(), nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if col.SQLType.IsText() {
 | 
			
		||||
			bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				session.engine.logger.Error(err)
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			return string(bytes), nil
 | 
			
		||||
		} else if col.SQLType.IsBlob() {
 | 
			
		||||
			var bytes []byte
 | 
			
		||||
			var err error
 | 
			
		||||
			if (k == reflect.Slice) &&
 | 
			
		||||
				(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
 | 
			
		||||
				bytes = fieldValue.Bytes()
 | 
			
		||||
			} else {
 | 
			
		||||
				bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface())
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					session.engine.logger.Error(err)
 | 
			
		||||
					return 0, err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return bytes, nil
 | 
			
		||||
		}
 | 
			
		||||
		return nil, ErrUnSupportedType
 | 
			
		||||
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
 | 
			
		||||
		return int64(fieldValue.Uint()), nil
 | 
			
		||||
	default:
 | 
			
		||||
		return fieldValue.Interface(), nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										244
									
								
								vendor/xorm.io/xorm/session_delete.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								vendor/xorm.io/xorm/session_delete.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,244 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
 | 
			
		||||
	if table == nil ||
 | 
			
		||||
		session.tx != nil {
 | 
			
		||||
		return ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, filter := range session.engine.dialect.Filters() {
 | 
			
		||||
		sqlStr = filter.Do(sqlStr, session.engine.dialect, table)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newsql := session.statement.convertIDSQL(sqlStr)
 | 
			
		||||
	if newsql == "" {
 | 
			
		||||
		return ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cacher := session.engine.getCacher(tableName)
 | 
			
		||||
	pkColumns := table.PKColumns()
 | 
			
		||||
	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resultsSlice, err := session.queryBytes(newsql, args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		ids = make([]core.PK, 0)
 | 
			
		||||
		if len(resultsSlice) > 0 {
 | 
			
		||||
			for _, data := range resultsSlice {
 | 
			
		||||
				var id int64
 | 
			
		||||
				var pk core.PK = make([]interface{}, 0)
 | 
			
		||||
				for _, col := range pkColumns {
 | 
			
		||||
					if v, ok := data[col.Name]; !ok {
 | 
			
		||||
						return errors.New("no id")
 | 
			
		||||
					} else if col.SQLType.IsText() {
 | 
			
		||||
						pk = append(pk, string(v))
 | 
			
		||||
					} else if col.SQLType.IsNumeric() {
 | 
			
		||||
						id, err = strconv.ParseInt(string(v), 10, 64)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return err
 | 
			
		||||
						}
 | 
			
		||||
						pk = append(pk, id)
 | 
			
		||||
					} else {
 | 
			
		||||
						return errors.New("not supported primary key type")
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				ids = append(ids, pk)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		session.engine.logger.Debug("[cacheDelete] delete cache obj:", tableName, id)
 | 
			
		||||
		sid, err := id.ToString()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		cacher.DelBean(tableName, sid)
 | 
			
		||||
	}
 | 
			
		||||
	session.engine.logger.Debug("[cacheDelete] clear cache table:", tableName)
 | 
			
		||||
	cacher.ClearIds(tableName)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Delete records, bean's non-empty fields are conditions
 | 
			
		||||
func (session *Session) Delete(bean interface{}) (int64, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.statement.lastError != nil {
 | 
			
		||||
		return 0, session.statement.lastError
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// handle before delete processors
 | 
			
		||||
	for _, closure := range session.beforeClosures {
 | 
			
		||||
		closure(bean)
 | 
			
		||||
	}
 | 
			
		||||
	cleanupProcessorsClosures(&session.beforeClosures)
 | 
			
		||||
 | 
			
		||||
	if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
 | 
			
		||||
		processor.BeforeDelete()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	condSQL, condArgs, err := session.statement.genConds(bean)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if len(condSQL) == 0 && session.statement.LimitN == 0 {
 | 
			
		||||
		return 0, ErrNeedDeletedCond
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var tableNameNoQuote = session.statement.TableName()
 | 
			
		||||
	var tableName = session.engine.Quote(tableNameNoQuote)
 | 
			
		||||
	var table = session.statement.RefTable
 | 
			
		||||
	var deleteSQL string
 | 
			
		||||
	if len(condSQL) > 0 {
 | 
			
		||||
		deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
 | 
			
		||||
	} else {
 | 
			
		||||
		deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var orderSQL string
 | 
			
		||||
	if len(session.statement.OrderStr) > 0 {
 | 
			
		||||
		orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr)
 | 
			
		||||
	}
 | 
			
		||||
	if session.statement.LimitN > 0 {
 | 
			
		||||
		orderSQL += fmt.Sprintf(" LIMIT %d", session.statement.LimitN)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(orderSQL) > 0 {
 | 
			
		||||
		switch session.engine.dialect.DBType() {
 | 
			
		||||
		case core.POSTGRES:
 | 
			
		||||
			inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
 | 
			
		||||
			if len(condSQL) > 0 {
 | 
			
		||||
				deleteSQL += " AND " + inSQL
 | 
			
		||||
			} else {
 | 
			
		||||
				deleteSQL += " WHERE " + inSQL
 | 
			
		||||
			}
 | 
			
		||||
		case core.SQLITE:
 | 
			
		||||
			inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
 | 
			
		||||
			if len(condSQL) > 0 {
 | 
			
		||||
				deleteSQL += " AND " + inSQL
 | 
			
		||||
			} else {
 | 
			
		||||
				deleteSQL += " WHERE " + inSQL
 | 
			
		||||
			}
 | 
			
		||||
		// TODO: how to handle delete limit on mssql?
 | 
			
		||||
		case core.MSSQL:
 | 
			
		||||
			return 0, ErrNotImplemented
 | 
			
		||||
		default:
 | 
			
		||||
			deleteSQL += orderSQL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var realSQL string
 | 
			
		||||
	argsForCache := make([]interface{}, 0, len(condArgs)*2)
 | 
			
		||||
	if session.statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
 | 
			
		||||
		realSQL = deleteSQL
 | 
			
		||||
		copy(argsForCache, condArgs)
 | 
			
		||||
		argsForCache = append(condArgs, argsForCache...)
 | 
			
		||||
	} else {
 | 
			
		||||
		// !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache.
 | 
			
		||||
		copy(argsForCache, condArgs)
 | 
			
		||||
		argsForCache = append(condArgs, argsForCache...)
 | 
			
		||||
 | 
			
		||||
		deletedColumn := table.DeletedColumn()
 | 
			
		||||
		realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
 | 
			
		||||
			session.engine.Quote(session.statement.TableName()),
 | 
			
		||||
			session.engine.Quote(deletedColumn.Name),
 | 
			
		||||
			condSQL)
 | 
			
		||||
 | 
			
		||||
		if len(orderSQL) > 0 {
 | 
			
		||||
			switch session.engine.dialect.DBType() {
 | 
			
		||||
			case core.POSTGRES:
 | 
			
		||||
				inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
 | 
			
		||||
				if len(condSQL) > 0 {
 | 
			
		||||
					realSQL += " AND " + inSQL
 | 
			
		||||
				} else {
 | 
			
		||||
					realSQL += " WHERE " + inSQL
 | 
			
		||||
				}
 | 
			
		||||
			case core.SQLITE:
 | 
			
		||||
				inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
 | 
			
		||||
				if len(condSQL) > 0 {
 | 
			
		||||
					realSQL += " AND " + inSQL
 | 
			
		||||
				} else {
 | 
			
		||||
					realSQL += " WHERE " + inSQL
 | 
			
		||||
				}
 | 
			
		||||
			// TODO: how to handle delete limit on mssql?
 | 
			
		||||
			case core.MSSQL:
 | 
			
		||||
				return 0, ErrNotImplemented
 | 
			
		||||
			default:
 | 
			
		||||
				realSQL += orderSQL
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// !oinume! Insert nowTime to the head of session.statement.Params
 | 
			
		||||
		condArgs = append(condArgs, "")
 | 
			
		||||
		paramsLen := len(condArgs)
 | 
			
		||||
		copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
 | 
			
		||||
 | 
			
		||||
		val, t := session.engine.nowTime(deletedColumn)
 | 
			
		||||
		condArgs[0] = val
 | 
			
		||||
 | 
			
		||||
		var colName = deletedColumn.Name
 | 
			
		||||
		session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
			col := table.GetColumn(colName)
 | 
			
		||||
			setColumnTime(bean, col, t)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cacher := session.engine.getCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache {
 | 
			
		||||
		session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.statement.RefTable = table
 | 
			
		||||
	res, err := session.exec(realSQL, condArgs...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// handle after delete processors
 | 
			
		||||
	if session.isAutoCommit {
 | 
			
		||||
		for _, closure := range session.afterClosures {
 | 
			
		||||
			closure(bean)
 | 
			
		||||
		}
 | 
			
		||||
		if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
 | 
			
		||||
			processor.AfterDelete()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		lenAfterClosures := len(session.afterClosures)
 | 
			
		||||
		if lenAfterClosures > 0 {
 | 
			
		||||
			if value, has := session.afterDeleteBeans[bean]; has && value != nil {
 | 
			
		||||
				*value = append(*value, session.afterClosures...)
 | 
			
		||||
			} else {
 | 
			
		||||
				afterClosures := make([]func(interface{}), lenAfterClosures)
 | 
			
		||||
				copy(afterClosures, session.afterClosures)
 | 
			
		||||
				session.afterDeleteBeans[bean] = &afterClosures
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
 | 
			
		||||
				session.afterDeleteBeans[bean] = nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	cleanupProcessorsClosures(&session.afterClosures)
 | 
			
		||||
	// --
 | 
			
		||||
 | 
			
		||||
	return res.RowsAffected()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								vendor/xorm.io/xorm/session_exist.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								vendor/xorm.io/xorm/session_exist.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Exist returns true if the record exist otherwise return false
 | 
			
		||||
func (session *Session) Exist(bean ...interface{}) (bool, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.statement.lastError != nil {
 | 
			
		||||
		return false, session.statement.lastError
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sqlStr string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if session.statement.RawSQL == "" {
 | 
			
		||||
		if len(bean) == 0 {
 | 
			
		||||
			tableName := session.statement.TableName()
 | 
			
		||||
			if len(tableName) <= 0 {
 | 
			
		||||
				return false, ErrTableNotFound
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			tableName = session.statement.Engine.Quote(tableName)
 | 
			
		||||
 | 
			
		||||
			if session.statement.cond.IsValid() {
 | 
			
		||||
				condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return false, err
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if session.engine.dialect.DBType() == core.MSSQL {
 | 
			
		||||
					sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s WHERE %s", tableName, condSQL)
 | 
			
		||||
				} else if session.engine.dialect.DBType() == core.ORACLE {
 | 
			
		||||
					sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE (%s) AND ROWNUM=1", tableName, condSQL)
 | 
			
		||||
				} else {
 | 
			
		||||
					sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL)
 | 
			
		||||
				}
 | 
			
		||||
				args = condArgs
 | 
			
		||||
			} else {
 | 
			
		||||
				if session.engine.dialect.DBType() == core.MSSQL {
 | 
			
		||||
					sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s", tableName)
 | 
			
		||||
				} else if session.engine.dialect.DBType() == core.ORACLE {
 | 
			
		||||
					sqlStr = fmt.Sprintf("SELECT * FROM  %s WHERE ROWNUM=1", tableName)
 | 
			
		||||
				} else {
 | 
			
		||||
					sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName)
 | 
			
		||||
				}
 | 
			
		||||
				args = []interface{}{}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			beanValue := reflect.ValueOf(bean[0])
 | 
			
		||||
			if beanValue.Kind() != reflect.Ptr {
 | 
			
		||||
				return false, errors.New("needs a pointer")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if beanValue.Elem().Kind() == reflect.Struct {
 | 
			
		||||
				if err := session.statement.setRefBean(bean[0]); err != nil {
 | 
			
		||||
					return false, err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if len(session.statement.TableName()) <= 0 {
 | 
			
		||||
				return false, ErrTableNotFound
 | 
			
		||||
			}
 | 
			
		||||
			session.statement.Limit(1)
 | 
			
		||||
			sqlStr, args, err = session.statement.genGetSQL(bean[0])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return false, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		sqlStr = session.statement.RawSQL
 | 
			
		||||
		args = session.statement.RawParams
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rows, err := session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	return rows.Next(), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										505
									
								
								vendor/xorm.io/xorm/session_find.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										505
									
								
								vendor/xorm.io/xorm/session_find.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,505 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	tpStruct = iota
 | 
			
		||||
	tpNonStruct
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Find retrieve records from table, condiBeans's non-empty fields
 | 
			
		||||
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
 | 
			
		||||
// map[int64]*Struct
 | 
			
		||||
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
	return session.find(rowsSlicePtr, condiBean...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FindAndCount find the results and also return the counts
 | 
			
		||||
func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.autoResetStatement = false
 | 
			
		||||
	err := session.find(rowsSlicePtr, condiBean...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
 | 
			
		||||
	if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
 | 
			
		||||
		return 0, errors.New("needs a pointer to a slice or a map")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sliceElementType := sliceValue.Type().Elem()
 | 
			
		||||
	if sliceElementType.Kind() == reflect.Ptr {
 | 
			
		||||
		sliceElementType = sliceElementType.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	session.autoResetStatement = true
 | 
			
		||||
 | 
			
		||||
	if session.statement.selectStr != "" {
 | 
			
		||||
		session.statement.selectStr = ""
 | 
			
		||||
	}
 | 
			
		||||
	if session.statement.OrderStr != "" {
 | 
			
		||||
		session.statement.OrderStr = ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.Count(reflect.New(sliceElementType).Interface())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
 | 
			
		||||
	defer session.resetStatement()
 | 
			
		||||
 | 
			
		||||
	if session.statement.lastError != nil {
 | 
			
		||||
		return session.statement.lastError
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
 | 
			
		||||
	if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
 | 
			
		||||
		return errors.New("needs a pointer to a slice or a map")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sliceElementType := sliceValue.Type().Elem()
 | 
			
		||||
 | 
			
		||||
	var tp = tpStruct
 | 
			
		||||
	if session.statement.RefTable == nil {
 | 
			
		||||
		if sliceElementType.Kind() == reflect.Ptr {
 | 
			
		||||
			if sliceElementType.Elem().Kind() == reflect.Struct {
 | 
			
		||||
				pv := reflect.New(sliceElementType.Elem())
 | 
			
		||||
				if err := session.statement.setRefValue(pv); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				tp = tpNonStruct
 | 
			
		||||
			}
 | 
			
		||||
		} else if sliceElementType.Kind() == reflect.Struct {
 | 
			
		||||
			pv := reflect.New(sliceElementType)
 | 
			
		||||
			if err := session.statement.setRefValue(pv); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			tp = tpNonStruct
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var table = session.statement.RefTable
 | 
			
		||||
 | 
			
		||||
	var addedTableName = (len(session.statement.JoinStr) > 0)
 | 
			
		||||
	var autoCond builder.Cond
 | 
			
		||||
	if tp == tpStruct {
 | 
			
		||||
		if !session.statement.noAutoCondition && len(condiBean) > 0 {
 | 
			
		||||
			var err error
 | 
			
		||||
			autoCond, err = session.statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
 | 
			
		||||
			// See https://gitea.com/xorm/xorm/issues/179
 | 
			
		||||
			if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled
 | 
			
		||||
				var colName = session.engine.Quote(col.Name)
 | 
			
		||||
				if addedTableName {
 | 
			
		||||
					var nm = session.statement.TableName()
 | 
			
		||||
					if len(session.statement.TableAlias) > 0 {
 | 
			
		||||
						nm = session.statement.TableAlias
 | 
			
		||||
					}
 | 
			
		||||
					colName = session.engine.Quote(nm) + "." + colName
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				autoCond = session.engine.CondDeleted(colName)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sqlStr string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
	var err error
 | 
			
		||||
	if session.statement.RawSQL == "" {
 | 
			
		||||
		if len(session.statement.TableName()) <= 0 {
 | 
			
		||||
			return ErrTableNotFound
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var columnStr = session.statement.ColumnStr
 | 
			
		||||
		if len(session.statement.selectStr) > 0 {
 | 
			
		||||
			columnStr = session.statement.selectStr
 | 
			
		||||
		} else {
 | 
			
		||||
			if session.statement.JoinStr == "" {
 | 
			
		||||
				if columnStr == "" {
 | 
			
		||||
					if session.statement.GroupByStr != "" {
 | 
			
		||||
						columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
 | 
			
		||||
					} else {
 | 
			
		||||
						columnStr = session.statement.genColumnStr()
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if columnStr == "" {
 | 
			
		||||
					if session.statement.GroupByStr != "" {
 | 
			
		||||
						columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
 | 
			
		||||
					} else {
 | 
			
		||||
						columnStr = "*"
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if columnStr == "" {
 | 
			
		||||
				columnStr = "*"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		session.statement.cond = session.statement.cond.And(autoCond)
 | 
			
		||||
		condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		args = append(session.statement.joinArgs, condArgs...)
 | 
			
		||||
		sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true, true)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		// for mssql and use limit
 | 
			
		||||
		qs := strings.Count(sqlStr, "?")
 | 
			
		||||
		if len(args)*2 == qs {
 | 
			
		||||
			args = append(args, args...)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		sqlStr = session.statement.RawSQL
 | 
			
		||||
		args = session.statement.RawParams
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.canCache() {
 | 
			
		||||
		if cacher := session.engine.getCacher(session.statement.TableName()); cacher != nil &&
 | 
			
		||||
			!session.statement.IsDistinct &&
 | 
			
		||||
			!session.statement.unscoped {
 | 
			
		||||
			err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
 | 
			
		||||
			if err != ErrCacheFailed {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			err = nil // !nashtsai! reset err to nil for ErrCacheFailed
 | 
			
		||||
			session.engine.logger.Warn("Cache Find Failed")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.noCacheFind(table, sliceValue, sqlStr, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
 | 
			
		||||
	rows, err := session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	fields, err := rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var newElemFunc func(fields []string) reflect.Value
 | 
			
		||||
	elemType := containerValue.Type().Elem()
 | 
			
		||||
	var isPointer bool
 | 
			
		||||
	if elemType.Kind() == reflect.Ptr {
 | 
			
		||||
		isPointer = true
 | 
			
		||||
		elemType = elemType.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	if elemType.Kind() == reflect.Ptr {
 | 
			
		||||
		return errors.New("pointer to pointer is not supported")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newElemFunc = func(fields []string) reflect.Value {
 | 
			
		||||
		switch elemType.Kind() {
 | 
			
		||||
		case reflect.Slice:
 | 
			
		||||
			slice := reflect.MakeSlice(elemType, len(fields), len(fields))
 | 
			
		||||
			x := reflect.New(slice.Type())
 | 
			
		||||
			x.Elem().Set(slice)
 | 
			
		||||
			return x
 | 
			
		||||
		case reflect.Map:
 | 
			
		||||
			mp := reflect.MakeMap(elemType)
 | 
			
		||||
			x := reflect.New(mp.Type())
 | 
			
		||||
			x.Elem().Set(mp)
 | 
			
		||||
			return x
 | 
			
		||||
		}
 | 
			
		||||
		return reflect.New(elemType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var containerValueSetFunc func(*reflect.Value, core.PK) error
 | 
			
		||||
 | 
			
		||||
	if containerValue.Kind() == reflect.Slice {
 | 
			
		||||
		containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
 | 
			
		||||
			if isPointer {
 | 
			
		||||
				containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
 | 
			
		||||
			} else {
 | 
			
		||||
				containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
 | 
			
		||||
			}
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		keyType := containerValue.Type().Key()
 | 
			
		||||
		if len(table.PrimaryKeys) == 0 {
 | 
			
		||||
			return errors.New("don't support multiple primary key's map has non-slice key type")
 | 
			
		||||
		}
 | 
			
		||||
		if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice {
 | 
			
		||||
			return errors.New("don't support multiple primary key's map has non-slice key type")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
 | 
			
		||||
			keyValue := reflect.New(keyType)
 | 
			
		||||
			err := convertPKToValue(table, keyValue.Interface(), pk)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if isPointer {
 | 
			
		||||
				containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
 | 
			
		||||
			} else {
 | 
			
		||||
				containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
 | 
			
		||||
			}
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if elemType.Kind() == reflect.Struct {
 | 
			
		||||
		var newValue = newElemFunc(fields)
 | 
			
		||||
		dataStruct := rValue(newValue.Interface())
 | 
			
		||||
		tb, err := session.engine.autoMapType(dataStruct)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = session.rows2Beans(rows, fields, tb, newElemFunc, containerValueSetFunc)
 | 
			
		||||
		rows.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return session.executeProcessors()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		var newValue = newElemFunc(fields)
 | 
			
		||||
		bean := newValue.Interface()
 | 
			
		||||
 | 
			
		||||
		switch elemType.Kind() {
 | 
			
		||||
		case reflect.Slice:
 | 
			
		||||
			err = rows.ScanSlice(bean)
 | 
			
		||||
		case reflect.Map:
 | 
			
		||||
			err = rows.ScanMap(bean)
 | 
			
		||||
		default:
 | 
			
		||||
			err = rows.Scan(bean)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := containerValueSetFunc(&newValue, nil); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertPKToValue(table *core.Table, dst interface{}, pk core.PK) error {
 | 
			
		||||
	cols := table.PKColumns()
 | 
			
		||||
	if len(cols) == 1 {
 | 
			
		||||
		return convertAssign(dst, pk[0])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dst = pk
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
 | 
			
		||||
	if !session.canCache() ||
 | 
			
		||||
		indexNoCase(sqlStr, "having") != -1 ||
 | 
			
		||||
		indexNoCase(sqlStr, "group by") != -1 {
 | 
			
		||||
		return ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tableName := session.statement.TableName()
 | 
			
		||||
	cacher := session.engine.getCacher(tableName)
 | 
			
		||||
	if cacher == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, filter := range session.engine.dialect.Filters() {
 | 
			
		||||
		sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newsql := session.statement.convertIDSQL(sqlStr)
 | 
			
		||||
	if newsql == "" {
 | 
			
		||||
		return ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		rows, err := session.queryRows(newsql, args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		defer rows.Close()
 | 
			
		||||
 | 
			
		||||
		var i int
 | 
			
		||||
		ids = make([]core.PK, 0)
 | 
			
		||||
		for rows.Next() {
 | 
			
		||||
			i++
 | 
			
		||||
			if i > 500 {
 | 
			
		||||
				session.engine.logger.Debug("[cacheFind] ids length > 500, no cache")
 | 
			
		||||
				return ErrCacheFailed
 | 
			
		||||
			}
 | 
			
		||||
			var res = make([]string, len(table.PrimaryKeys))
 | 
			
		||||
			err = rows.ScanSlice(&res)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
 | 
			
		||||
			for i, col := range table.PKColumns() {
 | 
			
		||||
				pk[i], err = session.engine.idTypeAssertion(col, res[i])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ids = append(ids, pk)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, sqlStr, newsql, args)
 | 
			
		||||
		err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		session.engine.logger.Debug("[cacheFind] cache hit sql:", tableName, sqlStr, newsql, args)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
 | 
			
		||||
 | 
			
		||||
	ididxes := make(map[string]int)
 | 
			
		||||
	var ides []core.PK
 | 
			
		||||
	var temps = make([]interface{}, len(ids))
 | 
			
		||||
 | 
			
		||||
	for idx, id := range ids {
 | 
			
		||||
		sid, err := id.ToString()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		bean := cacher.GetBean(tableName, sid)
 | 
			
		||||
		if bean == nil || reflect.ValueOf(bean).Elem().Type() != t {
 | 
			
		||||
			ides = append(ides, id)
 | 
			
		||||
			ididxes[sid] = idx
 | 
			
		||||
		} else {
 | 
			
		||||
			session.engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean)
 | 
			
		||||
 | 
			
		||||
			pk := session.engine.IdOf(bean)
 | 
			
		||||
			xid, err := pk.ToString()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if sid != xid {
 | 
			
		||||
				session.engine.logger.Error("[cacheFind] error cache", xid, sid, bean)
 | 
			
		||||
				return ErrCacheFailed
 | 
			
		||||
			}
 | 
			
		||||
			temps[idx] = bean
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ides) > 0 {
 | 
			
		||||
		slices := reflect.New(reflect.SliceOf(t))
 | 
			
		||||
		beans := slices.Interface()
 | 
			
		||||
 | 
			
		||||
		if len(table.PrimaryKeys) == 1 {
 | 
			
		||||
			ff := make([]interface{}, 0, len(ides))
 | 
			
		||||
			for _, ie := range ides {
 | 
			
		||||
				ff = append(ff, ie[0])
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			session.In("`"+table.PrimaryKeys[0]+"`", ff...)
 | 
			
		||||
		} else {
 | 
			
		||||
			for _, ie := range ides {
 | 
			
		||||
				cond := builder.NewCond()
 | 
			
		||||
				for i, name := range table.PrimaryKeys {
 | 
			
		||||
					cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
 | 
			
		||||
				}
 | 
			
		||||
				session.Or(cond)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = session.NoCache().Table(tableName).find(beans)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		vs := reflect.Indirect(reflect.ValueOf(beans))
 | 
			
		||||
		for i := 0; i < vs.Len(); i++ {
 | 
			
		||||
			rv := vs.Index(i)
 | 
			
		||||
			if rv.Kind() != reflect.Ptr {
 | 
			
		||||
				rv = rv.Addr()
 | 
			
		||||
			}
 | 
			
		||||
			id, err := session.engine.idOfV(rv)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			sid, err := id.ToString()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bean := rv.Interface()
 | 
			
		||||
			temps[ididxes[sid]] = bean
 | 
			
		||||
			session.engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps)
 | 
			
		||||
			cacher.PutBean(tableName, sid, bean)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for j := 0; j < len(temps); j++ {
 | 
			
		||||
		bean := temps[j]
 | 
			
		||||
		if bean == nil {
 | 
			
		||||
			session.engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps)
 | 
			
		||||
			// return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if sliceValue.Kind() == reflect.Slice {
 | 
			
		||||
			if t.Kind() == reflect.Ptr {
 | 
			
		||||
				sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean)))
 | 
			
		||||
			} else {
 | 
			
		||||
				sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean))))
 | 
			
		||||
			}
 | 
			
		||||
		} else if sliceValue.Kind() == reflect.Map {
 | 
			
		||||
			var key = ids[j]
 | 
			
		||||
			keyType := sliceValue.Type().Key()
 | 
			
		||||
			var ikey interface{}
 | 
			
		||||
			if len(key) == 1 {
 | 
			
		||||
				ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if keyType.Kind() != reflect.Slice {
 | 
			
		||||
					return errors.New("table have multiple primary keys, key is not core.PK or slice")
 | 
			
		||||
				}
 | 
			
		||||
				ikey = key
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if t.Kind() == reflect.Ptr {
 | 
			
		||||
				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean))
 | 
			
		||||
			} else {
 | 
			
		||||
				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean)))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										356
									
								
								vendor/xorm.io/xorm/session_get.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								vendor/xorm.io/xorm/session_get.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,356 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Get retrieve one record from database, bean's non-empty fields
 | 
			
		||||
// will be as conditions
 | 
			
		||||
func (session *Session) Get(bean interface{}) (bool, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
	return session.get(bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) get(bean interface{}) (bool, error) {
 | 
			
		||||
	defer session.resetStatement()
 | 
			
		||||
 | 
			
		||||
	if session.statement.lastError != nil {
 | 
			
		||||
		return false, session.statement.lastError
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	beanValue := reflect.ValueOf(bean)
 | 
			
		||||
	if beanValue.Kind() != reflect.Ptr {
 | 
			
		||||
		return false, errors.New("needs a pointer to a value")
 | 
			
		||||
	} else if beanValue.Elem().Kind() == reflect.Ptr {
 | 
			
		||||
		return false, errors.New("a pointer to a pointer is not allowed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if beanValue.Elem().Kind() == reflect.Struct {
 | 
			
		||||
		if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sqlStr string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if session.statement.RawSQL == "" {
 | 
			
		||||
		if len(session.statement.TableName()) <= 0 {
 | 
			
		||||
			return false, ErrTableNotFound
 | 
			
		||||
		}
 | 
			
		||||
		session.statement.Limit(1)
 | 
			
		||||
		sqlStr, args, err = session.statement.genGetSQL(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		sqlStr = session.statement.RawSQL
 | 
			
		||||
		args = session.statement.RawParams
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
 | 
			
		||||
	if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
 | 
			
		||||
		if cacher := session.engine.getCacher(session.statement.TableName()); cacher != nil &&
 | 
			
		||||
			!session.statement.unscoped {
 | 
			
		||||
			has, err := session.cacheGet(bean, sqlStr, args...)
 | 
			
		||||
			if err != ErrCacheFailed {
 | 
			
		||||
				return has, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	context := session.statement.context
 | 
			
		||||
	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 = ""
 | 
			
		||||
			session.lastSQLArgs = nil
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
 | 
			
		||||
	if err != nil || !has {
 | 
			
		||||
		return has, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if context != nil {
 | 
			
		||||
		context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {
 | 
			
		||||
	rows, err := session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	if !rows.Next() {
 | 
			
		||||
		if rows.Err() != nil {
 | 
			
		||||
			return false, rows.Err()
 | 
			
		||||
		}
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch bean.(type) {
 | 
			
		||||
	case sql.NullInt64, sql.NullBool, sql.NullFloat64, sql.NullString:
 | 
			
		||||
		return true, rows.Scan(&bean)
 | 
			
		||||
	case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString:
 | 
			
		||||
		return true, rows.Scan(bean)
 | 
			
		||||
	case *string:
 | 
			
		||||
		var res sql.NullString
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*string)) = res.String
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *int:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*int)) = int(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *int8:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*int8)) = int8(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *int16:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*int16)) = int16(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *int32:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*int32)) = int32(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *int64:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*int64)) = int64(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *uint:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*uint)) = uint(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *uint8:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*uint8)) = uint8(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *uint16:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*uint16)) = uint16(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *uint32:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*uint32)) = uint32(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *uint64:
 | 
			
		||||
		var res sql.NullInt64
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*uint64)) = uint64(res.Int64)
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	case *bool:
 | 
			
		||||
		var res sql.NullBool
 | 
			
		||||
		if err := rows.Scan(&res); err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
		if res.Valid {
 | 
			
		||||
			*(bean.(*bool)) = res.Bool
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch beanKind {
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		fields, err := rows.Columns()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// WARN: Alougth rows return true, but get fields failed
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		scanResults, err := session.row2Slice(rows, fields, bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
		// close it before covert data
 | 
			
		||||
		rows.Close()
 | 
			
		||||
 | 
			
		||||
		dataStruct := rValue(bean)
 | 
			
		||||
		_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true, session.executeProcessors()
 | 
			
		||||
	case reflect.Slice:
 | 
			
		||||
		err = rows.ScanSlice(bean)
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		err = rows.ScanMap(bean)
 | 
			
		||||
	case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 | 
			
		||||
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
		err = rows.Scan(bean)
 | 
			
		||||
	default:
 | 
			
		||||
		err = rows.Scan(bean)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) {
 | 
			
		||||
	// if has no reftable, then don't use cache currently
 | 
			
		||||
	if !session.canCache() {
 | 
			
		||||
		return false, ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, filter := range session.engine.dialect.Filters() {
 | 
			
		||||
		sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
 | 
			
		||||
	}
 | 
			
		||||
	newsql := session.statement.convertIDSQL(sqlStr)
 | 
			
		||||
	if newsql == "" {
 | 
			
		||||
		return false, ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tableName := session.statement.TableName()
 | 
			
		||||
	cacher := session.engine.getCacher(tableName)
 | 
			
		||||
 | 
			
		||||
	session.engine.logger.Debug("[cacheGet] find sql:", newsql, args)
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
	ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		var res = make([]string, len(table.PrimaryKeys))
 | 
			
		||||
		rows, err := session.NoCache().queryRows(newsql, args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
		defer rows.Close()
 | 
			
		||||
 | 
			
		||||
		if rows.Next() {
 | 
			
		||||
			err = rows.ScanSlice(&res)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return false, err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return false, ErrCacheFailed
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
 | 
			
		||||
		for i, col := range table.PKColumns() {
 | 
			
		||||
			if col.SQLType.IsText() {
 | 
			
		||||
				pk[i] = res[i]
 | 
			
		||||
			} else if col.SQLType.IsNumeric() {
 | 
			
		||||
				n, err := strconv.ParseInt(res[i], 10, 64)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return false, err
 | 
			
		||||
				}
 | 
			
		||||
				pk[i] = n
 | 
			
		||||
			} else {
 | 
			
		||||
				return false, errors.New("unsupported")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ids = []core.PK{pk}
 | 
			
		||||
		session.engine.logger.Debug("[cacheGet] cache ids:", newsql, ids)
 | 
			
		||||
		err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		session.engine.logger.Debug("[cacheGet] cache hit sql:", newsql, ids)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(ids) > 0 {
 | 
			
		||||
		structValue := reflect.Indirect(reflect.ValueOf(bean))
 | 
			
		||||
		id := ids[0]
 | 
			
		||||
		session.engine.logger.Debug("[cacheGet] get bean:", tableName, id)
 | 
			
		||||
		sid, err := id.ToString()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
		cacheBean := cacher.GetBean(tableName, sid)
 | 
			
		||||
		if cacheBean == nil {
 | 
			
		||||
			cacheBean = bean
 | 
			
		||||
			has, err = session.nocacheGet(reflect.Struct, table, cacheBean, sqlStr, args...)
 | 
			
		||||
			if err != nil || !has {
 | 
			
		||||
				return has, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			session.engine.logger.Debug("[cacheGet] cache bean:", tableName, id, cacheBean)
 | 
			
		||||
			cacher.PutBean(tableName, sid, cacheBean)
 | 
			
		||||
		} else {
 | 
			
		||||
			session.engine.logger.Debug("[cacheGet] cache hit bean:", tableName, id, cacheBean)
 | 
			
		||||
			has = true
 | 
			
		||||
		}
 | 
			
		||||
		structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean)))
 | 
			
		||||
 | 
			
		||||
		return has, nil
 | 
			
		||||
	}
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										878
									
								
								vendor/xorm.io/xorm/session_insert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										878
									
								
								vendor/xorm.io/xorm/session_insert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,878 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Insert insert one or more beans
 | 
			
		||||
func (session *Session) Insert(beans ...interface{}) (int64, error) {
 | 
			
		||||
	var affected int64
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.autoResetStatement = false
 | 
			
		||||
	defer func() {
 | 
			
		||||
		session.autoResetStatement = true
 | 
			
		||||
		session.resetStatement()
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	for _, bean := range beans {
 | 
			
		||||
		switch bean.(type) {
 | 
			
		||||
		case map[string]interface{}:
 | 
			
		||||
			cnt, err := session.insertMapInterface(bean.(map[string]interface{}))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return affected, err
 | 
			
		||||
			}
 | 
			
		||||
			affected += cnt
 | 
			
		||||
		case []map[string]interface{}:
 | 
			
		||||
			s := bean.([]map[string]interface{})
 | 
			
		||||
			for i := 0; i < len(s); i++ {
 | 
			
		||||
				cnt, err := session.insertMapInterface(s[i])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return affected, err
 | 
			
		||||
				}
 | 
			
		||||
				affected += cnt
 | 
			
		||||
			}
 | 
			
		||||
		case map[string]string:
 | 
			
		||||
			cnt, err := session.insertMapString(bean.(map[string]string))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return affected, err
 | 
			
		||||
			}
 | 
			
		||||
			affected += cnt
 | 
			
		||||
		case []map[string]string:
 | 
			
		||||
			s := bean.([]map[string]string)
 | 
			
		||||
			for i := 0; i < len(s); i++ {
 | 
			
		||||
				cnt, err := session.insertMapString(s[i])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return affected, err
 | 
			
		||||
				}
 | 
			
		||||
				affected += cnt
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			sliceValue := reflect.Indirect(reflect.ValueOf(bean))
 | 
			
		||||
			if sliceValue.Kind() == reflect.Slice {
 | 
			
		||||
				size := sliceValue.Len()
 | 
			
		||||
				if size > 0 {
 | 
			
		||||
					if session.engine.SupportInsertMany() {
 | 
			
		||||
						cnt, err := session.innerInsertMulti(bean)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return affected, err
 | 
			
		||||
						}
 | 
			
		||||
						affected += cnt
 | 
			
		||||
					} else {
 | 
			
		||||
						for i := 0; i < size; i++ {
 | 
			
		||||
							cnt, err := session.innerInsert(sliceValue.Index(i).Interface())
 | 
			
		||||
							if err != nil {
 | 
			
		||||
								return affected, err
 | 
			
		||||
							}
 | 
			
		||||
							affected += cnt
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				cnt, err := session.innerInsert(bean)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return affected, err
 | 
			
		||||
				}
 | 
			
		||||
				affected += cnt
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return affected, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error) {
 | 
			
		||||
	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
 | 
			
		||||
	if sliceValue.Kind() != reflect.Slice {
 | 
			
		||||
		return 0, errors.New("needs a pointer to a slice")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sliceValue.Len() <= 0 {
 | 
			
		||||
		return 0, errors.New("could not insert a empty slice")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := session.statement.setRefBean(sliceValue.Index(0).Interface()); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tableName := session.statement.TableName()
 | 
			
		||||
	if len(tableName) <= 0 {
 | 
			
		||||
		return 0, ErrTableNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
	size := sliceValue.Len()
 | 
			
		||||
 | 
			
		||||
	var colNames []string
 | 
			
		||||
	var colMultiPlaces []string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
	var cols []*core.Column
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < size; i++ {
 | 
			
		||||
		v := sliceValue.Index(i)
 | 
			
		||||
		vv := reflect.Indirect(v)
 | 
			
		||||
		elemValue := v.Interface()
 | 
			
		||||
		var colPlaces []string
 | 
			
		||||
 | 
			
		||||
		// handle BeforeInsertProcessor
 | 
			
		||||
		// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
 | 
			
		||||
		for _, closure := range session.beforeClosures {
 | 
			
		||||
			closure(elemValue)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if processor, ok := interface{}(elemValue).(BeforeInsertProcessor); ok {
 | 
			
		||||
			processor.BeforeInsert()
 | 
			
		||||
		}
 | 
			
		||||
		// --
 | 
			
		||||
 | 
			
		||||
		if i == 0 {
 | 
			
		||||
			for _, col := range table.Columns() {
 | 
			
		||||
				ptrFieldValue, err := col.ValueOfV(&vv)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return 0, err
 | 
			
		||||
				}
 | 
			
		||||
				fieldValue := *ptrFieldValue
 | 
			
		||||
				if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if col.MapType == core.ONLYFROMDB {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if col.IsDeleted {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if session.statement.omitColumnMap.contain(col.Name) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
 | 
			
		||||
					val, t := session.engine.nowTime(col)
 | 
			
		||||
					args = append(args, val)
 | 
			
		||||
 | 
			
		||||
					var colName = col.Name
 | 
			
		||||
					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
						col := table.GetColumn(colName)
 | 
			
		||||
						setColumnTime(bean, col, t)
 | 
			
		||||
					})
 | 
			
		||||
				} else if col.IsVersion && session.statement.checkVersion {
 | 
			
		||||
					args = append(args, 1)
 | 
			
		||||
					var colName = col.Name
 | 
			
		||||
					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
						col := table.GetColumn(colName)
 | 
			
		||||
						setColumnInt(bean, col, 1)
 | 
			
		||||
					})
 | 
			
		||||
				} else {
 | 
			
		||||
					arg, err := session.value2Interface(col, fieldValue)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return 0, err
 | 
			
		||||
					}
 | 
			
		||||
					args = append(args, arg)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				colNames = append(colNames, col.Name)
 | 
			
		||||
				cols = append(cols, col)
 | 
			
		||||
				colPlaces = append(colPlaces, "?")
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			for _, col := range cols {
 | 
			
		||||
				ptrFieldValue, err := col.ValueOfV(&vv)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return 0, err
 | 
			
		||||
				}
 | 
			
		||||
				fieldValue := *ptrFieldValue
 | 
			
		||||
 | 
			
		||||
				if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if col.MapType == core.ONLYFROMDB {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if col.IsDeleted {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if session.statement.omitColumnMap.contain(col.Name) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
 | 
			
		||||
					val, t := session.engine.nowTime(col)
 | 
			
		||||
					args = append(args, val)
 | 
			
		||||
 | 
			
		||||
					var colName = col.Name
 | 
			
		||||
					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
						col := table.GetColumn(colName)
 | 
			
		||||
						setColumnTime(bean, col, t)
 | 
			
		||||
					})
 | 
			
		||||
				} else if col.IsVersion && session.statement.checkVersion {
 | 
			
		||||
					args = append(args, 1)
 | 
			
		||||
					var colName = col.Name
 | 
			
		||||
					session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
						col := table.GetColumn(colName)
 | 
			
		||||
						setColumnInt(bean, col, 1)
 | 
			
		||||
					})
 | 
			
		||||
				} else {
 | 
			
		||||
					arg, err := session.value2Interface(col, fieldValue)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return 0, err
 | 
			
		||||
					}
 | 
			
		||||
					args = append(args, arg)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				colPlaces = append(colPlaces, "?")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		colMultiPlaces = append(colMultiPlaces, strings.Join(colPlaces, ", "))
 | 
			
		||||
	}
 | 
			
		||||
	cleanupProcessorsClosures(&session.beforeClosures)
 | 
			
		||||
 | 
			
		||||
	var sql string
 | 
			
		||||
	if session.engine.dialect.DBType() == core.ORACLE {
 | 
			
		||||
		temp := fmt.Sprintf(") INTO %s (%v) VALUES (",
 | 
			
		||||
			session.engine.Quote(tableName),
 | 
			
		||||
			quoteColumns(colNames, session.engine.Quote, ","))
 | 
			
		||||
		sql = fmt.Sprintf("INSERT ALL INTO %s (%v) VALUES (%v) SELECT 1 FROM DUAL",
 | 
			
		||||
			session.engine.Quote(tableName),
 | 
			
		||||
			quoteColumns(colNames, session.engine.Quote, ","),
 | 
			
		||||
			strings.Join(colMultiPlaces, temp))
 | 
			
		||||
	} else {
 | 
			
		||||
		sql = fmt.Sprintf("INSERT INTO %s (%v) VALUES (%v)",
 | 
			
		||||
			session.engine.Quote(tableName),
 | 
			
		||||
			quoteColumns(colNames, session.engine.Quote, ","),
 | 
			
		||||
			strings.Join(colMultiPlaces, "),("))
 | 
			
		||||
	}
 | 
			
		||||
	res, err := session.exec(sql, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.cacheInsert(tableName)
 | 
			
		||||
 | 
			
		||||
	lenAfterClosures := len(session.afterClosures)
 | 
			
		||||
	for i := 0; i < size; i++ {
 | 
			
		||||
		elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface()
 | 
			
		||||
 | 
			
		||||
		// handle AfterInsertProcessor
 | 
			
		||||
		if session.isAutoCommit {
 | 
			
		||||
			// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
 | 
			
		||||
			for _, closure := range session.afterClosures {
 | 
			
		||||
				closure(elemValue)
 | 
			
		||||
			}
 | 
			
		||||
			if processor, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
 | 
			
		||||
				processor.AfterInsert()
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if lenAfterClosures > 0 {
 | 
			
		||||
				if value, has := session.afterInsertBeans[elemValue]; has && value != nil {
 | 
			
		||||
					*value = append(*value, session.afterClosures...)
 | 
			
		||||
				} else {
 | 
			
		||||
					afterClosures := make([]func(interface{}), lenAfterClosures)
 | 
			
		||||
					copy(afterClosures, session.afterClosures)
 | 
			
		||||
					session.afterInsertBeans[elemValue] = &afterClosures
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				if _, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
 | 
			
		||||
					session.afterInsertBeans[elemValue] = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cleanupProcessorsClosures(&session.afterClosures)
 | 
			
		||||
	return res.RowsAffected()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InsertMulti insert multiple records
 | 
			
		||||
func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
 | 
			
		||||
	if sliceValue.Kind() != reflect.Slice {
 | 
			
		||||
		return 0, ErrParamsType
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sliceValue.Len() <= 0 {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.innerInsertMulti(rowsSlicePtr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) innerInsert(bean interface{}) (int64, error) {
 | 
			
		||||
	if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if len(session.statement.TableName()) <= 0 {
 | 
			
		||||
		return 0, ErrTableNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
 | 
			
		||||
	// handle BeforeInsertProcessor
 | 
			
		||||
	for _, closure := range session.beforeClosures {
 | 
			
		||||
		closure(bean)
 | 
			
		||||
	}
 | 
			
		||||
	cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
 | 
			
		||||
 | 
			
		||||
	if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok {
 | 
			
		||||
		processor.BeforeInsert()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	colNames, args, err := session.genInsertColumns(bean)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	exprs := session.statement.exprColumns
 | 
			
		||||
	colPlaces := strings.Repeat("?, ", len(colNames))
 | 
			
		||||
	if exprs.Len() <= 0 && len(colPlaces) > 0 {
 | 
			
		||||
		colPlaces = colPlaces[0 : len(colPlaces)-2]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var buf = builder.NewWriter()
 | 
			
		||||
	if _, err := buf.WriteString(fmt.Sprintf("INSERT INTO %s", session.engine.Quote(tableName))); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(colPlaces) <= 0 {
 | 
			
		||||
		if session.engine.dialect.DBType() == core.MYSQL {
 | 
			
		||||
			if _, err := buf.WriteString(" VALUES ()"); err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if _, err := buf.WriteString(fmt.Sprintf("%s DEFAULT VALUES", output)); err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if _, err := buf.WriteString(" ("); err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := writeStrings(buf, append(colNames, exprs.colNames...), "`", "`"); err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if session.statement.cond.IsValid() {
 | 
			
		||||
			if _, 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 {
 | 
			
		||||
		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 {
 | 
			
		||||
				closure(bean)
 | 
			
		||||
			}
 | 
			
		||||
			if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
 | 
			
		||||
				processor.AfterInsert()
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			lenAfterClosures := len(session.afterClosures)
 | 
			
		||||
			if lenAfterClosures > 0 {
 | 
			
		||||
				if value, has := session.afterInsertBeans[bean]; has && value != nil {
 | 
			
		||||
					*value = append(*value, session.afterClosures...)
 | 
			
		||||
				} else {
 | 
			
		||||
					afterClosures := make([]func(interface{}), lenAfterClosures)
 | 
			
		||||
					copy(afterClosures, session.afterClosures)
 | 
			
		||||
					session.afterInsertBeans[bean] = &afterClosures
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
				if _, ok := interface{}(bean).(AfterInsertProcessor); ok {
 | 
			
		||||
					session.afterInsertBeans[bean] = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// for postgres, many of them didn't implement lastInsertId, so we should
 | 
			
		||||
	// implemented it ourself.
 | 
			
		||||
	if session.engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 {
 | 
			
		||||
		res, err := session.queryBytes("select seq_atable.currval from dual", args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		defer handleAfterInsertProcessorFunc(bean)
 | 
			
		||||
 | 
			
		||||
		session.cacheInsert(tableName)
 | 
			
		||||
 | 
			
		||||
		if table.Version != "" && session.statement.checkVersion {
 | 
			
		||||
			verValue, err := table.VersionColumn().ValueOf(bean)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				session.engine.logger.Error(err)
 | 
			
		||||
			} else if verValue.IsValid() && verValue.CanSet() {
 | 
			
		||||
				session.incrVersionFieldValue(verValue)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(res) < 1 {
 | 
			
		||||
			return 0, errors.New("insert no error but not returned id")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		idByte := res[0][table.AutoIncrement]
 | 
			
		||||
		id, err := strconv.ParseInt(string(idByte), 10, 64)
 | 
			
		||||
		if err != nil || id <= 0 {
 | 
			
		||||
			return 1, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			session.engine.logger.Error(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
 | 
			
		||||
			return 1, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		aiValue.Set(int64ToIntValue(id, aiValue.Type()))
 | 
			
		||||
 | 
			
		||||
		return 1, nil
 | 
			
		||||
	} else if len(table.AutoIncrement) > 0 && (session.engine.dialect.DBType() == core.POSTGRES || session.engine.dialect.DBType() == core.MSSQL) {
 | 
			
		||||
		res, err := session.queryBytes(sqlStr, args...)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		defer handleAfterInsertProcessorFunc(bean)
 | 
			
		||||
 | 
			
		||||
		session.cacheInsert(tableName)
 | 
			
		||||
 | 
			
		||||
		if table.Version != "" && session.statement.checkVersion {
 | 
			
		||||
			verValue, err := table.VersionColumn().ValueOf(bean)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				session.engine.logger.Error(err)
 | 
			
		||||
			} else if verValue.IsValid() && verValue.CanSet() {
 | 
			
		||||
				session.incrVersionFieldValue(verValue)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(res) < 1 {
 | 
			
		||||
			return 0, errors.New("insert successfully but not returned id")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		idByte := res[0][table.AutoIncrement]
 | 
			
		||||
		id, err := strconv.ParseInt(string(idByte), 10, 64)
 | 
			
		||||
		if err != nil || id <= 0 {
 | 
			
		||||
			return 1, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			session.engine.logger.Error(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
 | 
			
		||||
			return 1, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		aiValue.Set(int64ToIntValue(id, aiValue.Type()))
 | 
			
		||||
 | 
			
		||||
		return 1, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		res, err := session.exec(sqlStr, args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		defer handleAfterInsertProcessorFunc(bean)
 | 
			
		||||
 | 
			
		||||
		session.cacheInsert(tableName)
 | 
			
		||||
 | 
			
		||||
		if table.Version != "" && session.statement.checkVersion {
 | 
			
		||||
			verValue, err := table.VersionColumn().ValueOf(bean)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				session.engine.logger.Error(err)
 | 
			
		||||
			} else if verValue.IsValid() && verValue.CanSet() {
 | 
			
		||||
				session.incrVersionFieldValue(verValue)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if table.AutoIncrement == "" {
 | 
			
		||||
			return res.RowsAffected()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var id int64
 | 
			
		||||
		id, err = res.LastInsertId()
 | 
			
		||||
		if err != nil || id <= 0 {
 | 
			
		||||
			return res.RowsAffected()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		aiValue, err := table.AutoIncrColumn().ValueOf(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			session.engine.logger.Error(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
 | 
			
		||||
			return res.RowsAffected()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		aiValue.Set(int64ToIntValue(id, aiValue.Type()))
 | 
			
		||||
 | 
			
		||||
		return res.RowsAffected()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InsertOne insert only one struct into database as a record.
 | 
			
		||||
// The in parameter bean must a struct or a point to struct. The return
 | 
			
		||||
// parameter is inserted and error
 | 
			
		||||
func (session *Session) InsertOne(bean interface{}) (int64, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.innerInsert(bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) cacheInsert(table string) error {
 | 
			
		||||
	if !session.statement.UseCache {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	cacher := session.engine.getCacher(table)
 | 
			
		||||
	if cacher == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	session.engine.logger.Debug("[cache] clear sql:", table)
 | 
			
		||||
	cacher.ClearIds(table)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// genInsertColumns generates insert needed columns
 | 
			
		||||
func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) {
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
	colNames := make([]string, 0, len(table.ColumnsSeq()))
 | 
			
		||||
	args := make([]interface{}, 0, len(table.ColumnsSeq()))
 | 
			
		||||
 | 
			
		||||
	for _, col := range table.Columns() {
 | 
			
		||||
		if col.MapType == core.ONLYFROMDB {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if col.IsDeleted {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if session.statement.omitColumnMap.contain(col.Name) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fieldValuePtr, err := col.ValueOf(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		fieldValue := *fieldValuePtr
 | 
			
		||||
 | 
			
		||||
		if col.IsAutoIncrement {
 | 
			
		||||
			switch fieldValue.Type().Kind() {
 | 
			
		||||
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
 | 
			
		||||
				if fieldValue.Int() == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
 | 
			
		||||
				if fieldValue.Uint() == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			case reflect.String:
 | 
			
		||||
				if len(fieldValue.String()) == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			case reflect.Ptr:
 | 
			
		||||
				if fieldValue.Pointer() == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// !evalphobia! set fieldValue as nil when column is nullable and zero-value
 | 
			
		||||
		if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
 | 
			
		||||
			if col.Nullable && isZero(fieldValue.Interface()) {
 | 
			
		||||
				var nilValue *int
 | 
			
		||||
				fieldValue = reflect.ValueOf(nilValue)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
 | 
			
		||||
			// if time is non-empty, then set to auto time
 | 
			
		||||
			val, t := session.engine.nowTime(col)
 | 
			
		||||
			args = append(args, val)
 | 
			
		||||
 | 
			
		||||
			var colName = col.Name
 | 
			
		||||
			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
				col := table.GetColumn(colName)
 | 
			
		||||
				setColumnTime(bean, col, t)
 | 
			
		||||
			})
 | 
			
		||||
		} else if col.IsVersion && session.statement.checkVersion {
 | 
			
		||||
			args = append(args, 1)
 | 
			
		||||
		} else {
 | 
			
		||||
			arg, err := session.value2Interface(col, fieldValue)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return colNames, args, err
 | 
			
		||||
			}
 | 
			
		||||
			args = append(args, arg)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		colNames = append(colNames, col.Name)
 | 
			
		||||
	}
 | 
			
		||||
	return colNames, args, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) insertMapInterface(m map[string]interface{}) (int64, error) {
 | 
			
		||||
	if len(m) == 0 {
 | 
			
		||||
		return 0, ErrParamsType
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tableName := session.statement.TableName()
 | 
			
		||||
	if len(tableName) <= 0 {
 | 
			
		||||
		return 0, ErrTableNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, err := session.exec(sql, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	affected, err := res.RowsAffected()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return affected, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) insertMapString(m map[string]string) (int64, error) {
 | 
			
		||||
	if len(m) == 0 {
 | 
			
		||||
		return 0, ErrParamsType
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tableName := session.statement.TableName()
 | 
			
		||||
	if len(tableName) <= 0 {
 | 
			
		||||
		return 0, ErrTableNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, err := session.exec(sql, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	affected, err := res.RowsAffected()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return affected, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										100
									
								
								vendor/xorm.io/xorm/session_iterate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								vendor/xorm.io/xorm/session_iterate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
// Copyright 2016 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 "reflect"
 | 
			
		||||
 | 
			
		||||
// IterFunc only use by Iterate
 | 
			
		||||
type IterFunc func(idx int, bean interface{}) error
 | 
			
		||||
 | 
			
		||||
// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields
 | 
			
		||||
// are conditions.
 | 
			
		||||
func (session *Session) Rows(bean interface{}) (*Rows, error) {
 | 
			
		||||
	return newRows(session, bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Iterate record by record handle records from table, condiBeans's non-empty fields
 | 
			
		||||
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
 | 
			
		||||
// map[int64]*Struct
 | 
			
		||||
func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.statement.lastError != nil {
 | 
			
		||||
		return session.statement.lastError
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.statement.bufferSize > 0 {
 | 
			
		||||
		return session.bufferIterate(bean, fun)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rows, err := session.Rows(bean)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	i := 0
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		b := reflect.New(rows.beanType).Interface()
 | 
			
		||||
		err = rows.Scan(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = fun(i, b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BufferSize sets the buffersize for iterate
 | 
			
		||||
func (session *Session) BufferSize(size int) *Session {
 | 
			
		||||
	session.statement.bufferSize = size
 | 
			
		||||
	return session
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var bufferSize = session.statement.bufferSize
 | 
			
		||||
	var limit = session.statement.LimitN
 | 
			
		||||
	if limit > 0 && bufferSize > limit {
 | 
			
		||||
		bufferSize = limit
 | 
			
		||||
	}
 | 
			
		||||
	var start = session.statement.Start
 | 
			
		||||
	v := rValue(bean)
 | 
			
		||||
	sliceType := reflect.SliceOf(v.Type())
 | 
			
		||||
	var idx = 0
 | 
			
		||||
	for {
 | 
			
		||||
		slice := reflect.New(sliceType)
 | 
			
		||||
		if err := session.Limit(bufferSize, start).find(slice.Interface(), bean); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for i := 0; i < slice.Elem().Len(); i++ {
 | 
			
		||||
			if err := fun(idx, slice.Elem().Index(i).Addr().Interface()); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			idx++
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		start = start + slice.Elem().Len()
 | 
			
		||||
		if limit > 0 && idx+bufferSize > limit {
 | 
			
		||||
			bufferSize = limit - idx
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if bufferSize <= 0 || slice.Elem().Len() < bufferSize || idx == limit {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										320
									
								
								vendor/xorm.io/xorm/session_query.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								vendor/xorm.io/xorm/session_query.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,320 @@
 | 
			
		||||
// Copyright 2017 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"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (session *Session) genQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) {
 | 
			
		||||
	if len(sqlOrArgs) > 0 {
 | 
			
		||||
		return convertSQLOrArgs(sqlOrArgs...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.statement.RawSQL != "" {
 | 
			
		||||
		return session.statement.RawSQL, session.statement.RawParams, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(session.statement.TableName()) <= 0 {
 | 
			
		||||
		return "", nil, ErrTableNotFound
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var columnStr = session.statement.ColumnStr
 | 
			
		||||
	if len(session.statement.selectStr) > 0 {
 | 
			
		||||
		columnStr = session.statement.selectStr
 | 
			
		||||
	} else {
 | 
			
		||||
		if session.statement.JoinStr == "" {
 | 
			
		||||
			if columnStr == "" {
 | 
			
		||||
				if session.statement.GroupByStr != "" {
 | 
			
		||||
					columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
 | 
			
		||||
				} else {
 | 
			
		||||
					columnStr = session.statement.genColumnStr()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if columnStr == "" {
 | 
			
		||||
				if session.statement.GroupByStr != "" {
 | 
			
		||||
					columnStr = session.engine.quoteColumns(session.statement.GroupByStr)
 | 
			
		||||
				} else {
 | 
			
		||||
					columnStr = "*"
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if columnStr == "" {
 | 
			
		||||
			columnStr = "*"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := session.statement.processIDParam(); err != nil {
 | 
			
		||||
		return "", nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	args := append(session.statement.joinArgs, condArgs...)
 | 
			
		||||
	sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", nil, err
 | 
			
		||||
	}
 | 
			
		||||
	// for mssql and use limit
 | 
			
		||||
	qs := strings.Count(sqlStr, "?")
 | 
			
		||||
	if len(args)*2 == qs {
 | 
			
		||||
		args = append(args, args...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sqlStr, args, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Query runs a raw sql and return records as []map[string][]byte
 | 
			
		||||
func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.queryBytes(sqlStr, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func value2String(rawValue *reflect.Value) (str string, err error) {
 | 
			
		||||
	aa := reflect.TypeOf((*rawValue).Interface())
 | 
			
		||||
	vv := reflect.ValueOf((*rawValue).Interface())
 | 
			
		||||
	switch aa.Kind() {
 | 
			
		||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
			
		||||
		str = strconv.FormatInt(vv.Int(), 10)
 | 
			
		||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
			
		||||
		str = strconv.FormatUint(vv.Uint(), 10)
 | 
			
		||||
	case reflect.Float32, reflect.Float64:
 | 
			
		||||
		str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		str = vv.String()
 | 
			
		||||
	case reflect.Array, reflect.Slice:
 | 
			
		||||
		switch aa.Elem().Kind() {
 | 
			
		||||
		case reflect.Uint8:
 | 
			
		||||
			data := rawValue.Interface().([]byte)
 | 
			
		||||
			str = string(data)
 | 
			
		||||
			if str == "\x00" {
 | 
			
		||||
				str = "0"
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 | 
			
		||||
		}
 | 
			
		||||
	// time type
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		if aa.ConvertibleTo(core.TimeType) {
 | 
			
		||||
			str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		str = strconv.FormatBool(vv.Bool())
 | 
			
		||||
	case reflect.Complex128, reflect.Complex64:
 | 
			
		||||
		str = fmt.Sprintf("%v", vv.Complex())
 | 
			
		||||
	/* TODO: unsupported types below
 | 
			
		||||
	   case reflect.Map:
 | 
			
		||||
	   case reflect.Ptr:
 | 
			
		||||
	   case reflect.Uintptr:
 | 
			
		||||
	   case reflect.UnsafePointer:
 | 
			
		||||
	   case reflect.Chan, reflect.Func, reflect.Interface:
 | 
			
		||||
	*/
 | 
			
		||||
	default:
 | 
			
		||||
		err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name())
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) {
 | 
			
		||||
	result := make(map[string]string)
 | 
			
		||||
	scanResultContainers := make([]interface{}, len(fields))
 | 
			
		||||
	for i := 0; i < len(fields); i++ {
 | 
			
		||||
		var scanResultContainer interface{}
 | 
			
		||||
		scanResultContainers[i] = &scanResultContainer
 | 
			
		||||
	}
 | 
			
		||||
	if err := rows.Scan(scanResultContainers...); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for ii, key := range fields {
 | 
			
		||||
		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
 | 
			
		||||
		// if row is null then as empty string
 | 
			
		||||
		if rawValue.Interface() == nil {
 | 
			
		||||
			result[key] = ""
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if data, err := value2String(&rawValue); err == nil {
 | 
			
		||||
			result[key] = data
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func row2sliceStr(rows *core.Rows, fields []string) (results []string, err error) {
 | 
			
		||||
	result := make([]string, 0, len(fields))
 | 
			
		||||
	scanResultContainers := make([]interface{}, len(fields))
 | 
			
		||||
	for i := 0; i < len(fields); i++ {
 | 
			
		||||
		var scanResultContainer interface{}
 | 
			
		||||
		scanResultContainers[i] = &scanResultContainer
 | 
			
		||||
	}
 | 
			
		||||
	if err := rows.Scan(scanResultContainers...); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < len(fields); i++ {
 | 
			
		||||
		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[i]))
 | 
			
		||||
		// if row is null then as empty string
 | 
			
		||||
		if rawValue.Interface() == nil {
 | 
			
		||||
			result = append(result, "")
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if data, err := value2String(&rawValue); err == nil {
 | 
			
		||||
			result = append(result, data)
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
 | 
			
		||||
	fields, err := rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		result, err := row2mapStr(rows, fields)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		resultsSlice = append(resultsSlice, result)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resultsSlice, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
 | 
			
		||||
	fields, err := rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		record, err := row2sliceStr(rows, fields)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		resultsSlice = append(resultsSlice, record)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resultsSlice, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// QueryString runs a raw sql and return records as []map[string]string
 | 
			
		||||
func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rows, err := session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	return rows2Strings(rows)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// QuerySliceString runs a raw sql and return records as [][]string
 | 
			
		||||
func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rows, err := session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	return rows2SliceString(rows)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
 | 
			
		||||
	resultsMap = make(map[string]interface{}, len(fields))
 | 
			
		||||
	scanResultContainers := make([]interface{}, len(fields))
 | 
			
		||||
	for i := 0; i < len(fields); i++ {
 | 
			
		||||
		var scanResultContainer interface{}
 | 
			
		||||
		scanResultContainers[i] = &scanResultContainer
 | 
			
		||||
	}
 | 
			
		||||
	if err := rows.Scan(scanResultContainers...); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for ii, key := range fields {
 | 
			
		||||
		resultsMap[key] = reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])).Interface()
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) {
 | 
			
		||||
	fields, err := rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		result, err := row2mapInterface(rows, fields)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		resultsSlice = append(resultsSlice, result)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resultsSlice, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// QueryInterface runs a raw sql and return records as []map[string]interface{}
 | 
			
		||||
func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqlStr, args, err := session.genQuerySQL(sqlOrArgs...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rows, err := session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	return rows2Interfaces(rows)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										227
									
								
								vendor/xorm.io/xorm/session_raw.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								vendor/xorm.io/xorm/session_raw.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) {
 | 
			
		||||
	for _, filter := range session.engine.dialect.Filters() {
 | 
			
		||||
		*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.lastSQL = *sqlStr
 | 
			
		||||
	session.lastSQLArgs = paramStr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) {
 | 
			
		||||
	defer session.resetStatement()
 | 
			
		||||
 | 
			
		||||
	session.queryPreprocess(&sqlStr, args...)
 | 
			
		||||
 | 
			
		||||
	if session.engine.showSQL {
 | 
			
		||||
		if session.engine.showExecTime {
 | 
			
		||||
			b4ExecTime := time.Now()
 | 
			
		||||
			defer func() {
 | 
			
		||||
				execDuration := time.Since(b4ExecTime)
 | 
			
		||||
				if len(args) > 0 {
 | 
			
		||||
					session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
 | 
			
		||||
				} else {
 | 
			
		||||
					session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
 | 
			
		||||
				}
 | 
			
		||||
			}()
 | 
			
		||||
		} else {
 | 
			
		||||
			if len(args) > 0 {
 | 
			
		||||
				session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
 | 
			
		||||
			} else {
 | 
			
		||||
				session.engine.logger.Infof("[SQL] %v", sqlStr)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.isAutoCommit {
 | 
			
		||||
		var db *core.DB
 | 
			
		||||
		if session.sessionType == groupSession {
 | 
			
		||||
			db = session.engine.engineGroup.Slave().DB()
 | 
			
		||||
		} else {
 | 
			
		||||
			db = session.DB()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if session.prepareStmt {
 | 
			
		||||
			// don't clear stmt since session will cache them
 | 
			
		||||
			stmt, err := session.doPrepare(db, sqlStr)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			rows, err := stmt.QueryContext(session.ctx, args...)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return rows, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rows, err := db.QueryContext(session.ctx, sqlStr, args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return rows, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rows, err := session.tx.QueryContext(session.ctx, sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return rows, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
 | 
			
		||||
	return core.NewRow(session.queryRows(sqlStr, args...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func value2Bytes(rawValue *reflect.Value) ([]byte, error) {
 | 
			
		||||
	str, err := value2String(rawValue)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return []byte(str), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
 | 
			
		||||
	result := make(map[string][]byte)
 | 
			
		||||
	scanResultContainers := make([]interface{}, len(fields))
 | 
			
		||||
	for i := 0; i < len(fields); i++ {
 | 
			
		||||
		var scanResultContainer interface{}
 | 
			
		||||
		scanResultContainers[i] = &scanResultContainer
 | 
			
		||||
	}
 | 
			
		||||
	if err := rows.Scan(scanResultContainers...); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for ii, key := range fields {
 | 
			
		||||
		rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
 | 
			
		||||
		//if row is null then ignore
 | 
			
		||||
		if rawValue.Interface() == nil {
 | 
			
		||||
			result[key] = []byte{}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if data, err := value2Bytes(&rawValue); err == nil {
 | 
			
		||||
			result[key] = data
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, err // !nashtsai! REVIEW, should return err or just error log?
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
 | 
			
		||||
	fields, err := rows.Columns()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	for rows.Next() {
 | 
			
		||||
		result, err := row2map(rows, fields)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		resultsSlice = append(resultsSlice, result)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resultsSlice, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
 | 
			
		||||
	rows, err := session.queryRows(sqlStr, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer rows.Close()
 | 
			
		||||
 | 
			
		||||
	return rows2maps(rows)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
 | 
			
		||||
	defer session.resetStatement()
 | 
			
		||||
 | 
			
		||||
	session.queryPreprocess(&sqlStr, args...)
 | 
			
		||||
 | 
			
		||||
	if session.engine.showSQL {
 | 
			
		||||
		if session.engine.showExecTime {
 | 
			
		||||
			b4ExecTime := time.Now()
 | 
			
		||||
			defer func() {
 | 
			
		||||
				execDuration := time.Since(b4ExecTime)
 | 
			
		||||
				if len(args) > 0 {
 | 
			
		||||
					session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration)
 | 
			
		||||
				} else {
 | 
			
		||||
					session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration)
 | 
			
		||||
				}
 | 
			
		||||
			}()
 | 
			
		||||
		} else {
 | 
			
		||||
			if len(args) > 0 {
 | 
			
		||||
				session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args)
 | 
			
		||||
			} else {
 | 
			
		||||
				session.engine.logger.Infof("[SQL] %v", sqlStr)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !session.isAutoCommit {
 | 
			
		||||
		return session.tx.ExecContext(session.ctx, sqlStr, args...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.prepareStmt {
 | 
			
		||||
		stmt, err := session.doPrepare(session.DB(), sqlStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		res, err := stmt.ExecContext(session.ctx, args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return res, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.DB().ExecContext(session.ctx, sqlStr, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
 | 
			
		||||
	switch sqlOrArgs[0].(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
 | 
			
		||||
	case *builder.Builder:
 | 
			
		||||
		return sqlOrArgs[0].(*builder.Builder).ToSQL()
 | 
			
		||||
	case builder.Builder:
 | 
			
		||||
		bd := sqlOrArgs[0].(builder.Builder)
 | 
			
		||||
		return bd.ToSQL()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", nil, ErrUnSupportedType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Exec raw sql
 | 
			
		||||
func (session *Session) Exec(sqlOrArgs ...interface{}) (sql.Result, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(sqlOrArgs) == 0 {
 | 
			
		||||
		return nil, ErrUnSupportedType
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqlStr, args, err := convertSQLOrArgs(sqlOrArgs...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.exec(sqlStr, args...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										430
									
								
								vendor/xorm.io/xorm/session_schema.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										430
									
								
								vendor/xorm.io/xorm/session_schema.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,430 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Ping test if database is ok
 | 
			
		||||
func (session *Session) Ping() error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
 | 
			
		||||
	return session.DB().PingContext(session.ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateTable create a table according a bean
 | 
			
		||||
func (session *Session) CreateTable(bean interface{}) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.createTable(bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) createTable(bean interface{}) error {
 | 
			
		||||
	if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqlStr := session.statement.genCreateTableSQL()
 | 
			
		||||
	_, err := session.exec(sqlStr)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateIndexes create indexes
 | 
			
		||||
func (session *Session) CreateIndexes(bean interface{}) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.createIndexes(bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) createIndexes(bean interface{}) error {
 | 
			
		||||
	if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqls := session.statement.genIndexSQL()
 | 
			
		||||
	for _, sqlStr := range sqls {
 | 
			
		||||
		_, err := session.exec(sqlStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateUniques create uniques
 | 
			
		||||
func (session *Session) CreateUniques(bean interface{}) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
	return session.createUniques(bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) createUniques(bean interface{}) error {
 | 
			
		||||
	if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqls := session.statement.genUniqueSQL()
 | 
			
		||||
	for _, sqlStr := range sqls {
 | 
			
		||||
		_, err := session.exec(sqlStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DropIndexes drop indexes
 | 
			
		||||
func (session *Session) DropIndexes(bean interface{}) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.dropIndexes(bean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) dropIndexes(bean interface{}) error {
 | 
			
		||||
	if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqls := session.statement.genDelIndexSQL()
 | 
			
		||||
	for _, sqlStr := range sqls {
 | 
			
		||||
		_, err := session.exec(sqlStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DropTable drop table will drop table if exist, if drop failed, it will return error
 | 
			
		||||
func (session *Session) DropTable(beanOrTableName interface{}) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return session.dropTable(beanOrTableName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) dropTable(beanOrTableName interface{}) error {
 | 
			
		||||
	tableName := session.engine.TableName(beanOrTableName)
 | 
			
		||||
	var needDrop = true
 | 
			
		||||
	if !session.engine.dialect.SupportDropIfExists() {
 | 
			
		||||
		sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
 | 
			
		||||
		results, err := session.queryBytes(sqlStr, args...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		needDrop = len(results) > 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if needDrop {
 | 
			
		||||
		sqlStr := session.engine.Dialect().DropTableSql(session.engine.TableName(tableName, true))
 | 
			
		||||
		_, err := session.exec(sqlStr)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsTableExist if a table is exist
 | 
			
		||||
func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tableName := session.engine.TableName(beanOrTableName)
 | 
			
		||||
 | 
			
		||||
	return session.isTableExist(tableName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) isTableExist(tableName string) (bool, error) {
 | 
			
		||||
	sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
 | 
			
		||||
	results, err := session.queryBytes(sqlStr, args...)
 | 
			
		||||
	return len(results) > 0, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsTableEmpty if table have any records
 | 
			
		||||
func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
	return session.isTableEmpty(session.engine.TableName(bean))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) isTableEmpty(tableName string) (bool, error) {
 | 
			
		||||
	var total int64
 | 
			
		||||
	sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(session.engine.TableName(tableName, true)))
 | 
			
		||||
	err := session.queryRow(sqlStr).Scan(&total)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == sql.ErrNoRows {
 | 
			
		||||
			err = nil
 | 
			
		||||
		}
 | 
			
		||||
		return true, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return total == 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// find if index is exist according cols
 | 
			
		||||
func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
 | 
			
		||||
	indexes, err := session.engine.dialect.GetIndexes(tableName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, index := range indexes {
 | 
			
		||||
		if sliceEq(index.Cols, cols) {
 | 
			
		||||
			if unique {
 | 
			
		||||
				return index.Type == core.UniqueType, nil
 | 
			
		||||
			}
 | 
			
		||||
			return index.Type == core.IndexType, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) addColumn(colName string) error {
 | 
			
		||||
	col := session.statement.RefTable.GetColumn(colName)
 | 
			
		||||
	sql, args := session.statement.genAddColumnStr(col)
 | 
			
		||||
	_, err := session.exec(sql, args...)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) addIndex(tableName, idxName string) error {
 | 
			
		||||
	index := session.statement.RefTable.Indexes[idxName]
 | 
			
		||||
	sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
 | 
			
		||||
	_, err := session.exec(sqlStr)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) addUnique(tableName, uqeName string) error {
 | 
			
		||||
	index := session.statement.RefTable.Indexes[uqeName]
 | 
			
		||||
	sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
 | 
			
		||||
	_, err := session.exec(sqlStr)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sync2 synchronize structs to database tables
 | 
			
		||||
func (session *Session) Sync2(beans ...interface{}) error {
 | 
			
		||||
	engine := session.engine
 | 
			
		||||
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		session.isAutoClose = false
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tables, err := engine.dialect.GetTables()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	session.autoResetStatement = false
 | 
			
		||||
	defer func() {
 | 
			
		||||
		session.autoResetStatement = true
 | 
			
		||||
		session.resetStatement()
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	for _, bean := range beans {
 | 
			
		||||
		v := rValue(bean)
 | 
			
		||||
		table, err := engine.mapType(v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		var tbName string
 | 
			
		||||
		if len(session.statement.AltTableName) > 0 {
 | 
			
		||||
			tbName = session.statement.AltTableName
 | 
			
		||||
		} else {
 | 
			
		||||
			tbName = engine.TableName(bean)
 | 
			
		||||
		}
 | 
			
		||||
		tbNameWithSchema := engine.tbNameWithSchema(tbName)
 | 
			
		||||
 | 
			
		||||
		var oriTable *core.Table
 | 
			
		||||
		for _, tb := range tables {
 | 
			
		||||
			if strings.EqualFold(engine.tbNameWithSchema(tb.Name), engine.tbNameWithSchema(tbName)) {
 | 
			
		||||
				oriTable = tb
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// this is a new table
 | 
			
		||||
		if oriTable == nil {
 | 
			
		||||
			err = session.StoreEngine(session.statement.StoreEngine).createTable(bean)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = session.createUniques(bean)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = session.createIndexes(bean)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// this will modify an old table
 | 
			
		||||
		if err = engine.loadTableInfo(oriTable); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check columns
 | 
			
		||||
		for _, col := range table.Columns() {
 | 
			
		||||
			var oriCol *core.Column
 | 
			
		||||
			for _, col2 := range oriTable.Columns() {
 | 
			
		||||
				if strings.EqualFold(col.Name, col2.Name) {
 | 
			
		||||
					oriCol = col2
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// column is not exist on table
 | 
			
		||||
			if oriCol == nil {
 | 
			
		||||
				session.statement.RefTable = table
 | 
			
		||||
				session.statement.tableName = tbNameWithSchema
 | 
			
		||||
				if err = session.addColumn(col.Name); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = nil
 | 
			
		||||
			expectedType := engine.dialect.SqlType(col)
 | 
			
		||||
			curType := engine.dialect.SqlType(oriCol)
 | 
			
		||||
			if expectedType != curType {
 | 
			
		||||
				if expectedType == core.Text &&
 | 
			
		||||
					strings.HasPrefix(curType, core.Varchar) {
 | 
			
		||||
					// currently only support mysql & postgres
 | 
			
		||||
					if engine.dialect.DBType() == core.MYSQL ||
 | 
			
		||||
						engine.dialect.DBType() == core.POSTGRES {
 | 
			
		||||
						engine.logger.Infof("Table %s column %s change type from %s to %s\n",
 | 
			
		||||
							tbNameWithSchema, col.Name, curType, expectedType)
 | 
			
		||||
						_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
 | 
			
		||||
					} else {
 | 
			
		||||
						engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
 | 
			
		||||
							tbNameWithSchema, col.Name, curType, expectedType)
 | 
			
		||||
					}
 | 
			
		||||
				} else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) {
 | 
			
		||||
					if engine.dialect.DBType() == core.MYSQL {
 | 
			
		||||
						if oriCol.Length < col.Length {
 | 
			
		||||
							engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
 | 
			
		||||
								tbNameWithSchema, col.Name, oriCol.Length, col.Length)
 | 
			
		||||
							_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
 | 
			
		||||
						engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
 | 
			
		||||
							tbNameWithSchema, col.Name, curType, expectedType)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if expectedType == core.Varchar {
 | 
			
		||||
				if engine.dialect.DBType() == core.MYSQL {
 | 
			
		||||
					if oriCol.Length < col.Length {
 | 
			
		||||
						engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
 | 
			
		||||
							tbNameWithSchema, col.Name, oriCol.Length, col.Length)
 | 
			
		||||
						_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if col.Default != oriCol.Default {
 | 
			
		||||
				if (col.SQLType.Name == core.Bool || col.SQLType.Name == core.Boolean) &&
 | 
			
		||||
					((strings.EqualFold(col.Default, "true") && oriCol.Default == "1") ||
 | 
			
		||||
						(strings.EqualFold(col.Default, "false") && oriCol.Default == "0")) {
 | 
			
		||||
				} else {
 | 
			
		||||
					engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s",
 | 
			
		||||
						tbName, col.Name, oriCol.Default, col.Default)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if col.Nullable != oriCol.Nullable {
 | 
			
		||||
				engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v",
 | 
			
		||||
					tbName, col.Name, oriCol.Nullable, col.Nullable)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var foundIndexNames = make(map[string]bool)
 | 
			
		||||
		var addedNames = make(map[string]*core.Index)
 | 
			
		||||
 | 
			
		||||
		for name, index := range table.Indexes {
 | 
			
		||||
			var oriIndex *core.Index
 | 
			
		||||
			for name2, index2 := range oriTable.Indexes {
 | 
			
		||||
				if index.Equal(index2) {
 | 
			
		||||
					oriIndex = index2
 | 
			
		||||
					foundIndexNames[name2] = true
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if oriIndex != nil {
 | 
			
		||||
				if oriIndex.Type != index.Type {
 | 
			
		||||
					sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex)
 | 
			
		||||
					_, err = session.exec(sql)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					oriIndex = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if oriIndex == nil {
 | 
			
		||||
				addedNames[name] = index
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for name2, index2 := range oriTable.Indexes {
 | 
			
		||||
			if _, ok := foundIndexNames[name2]; !ok {
 | 
			
		||||
				sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2)
 | 
			
		||||
				_, err = session.exec(sql)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for name, index := range addedNames {
 | 
			
		||||
			if index.Type == core.UniqueType {
 | 
			
		||||
				session.statement.RefTable = table
 | 
			
		||||
				session.statement.tableName = tbNameWithSchema
 | 
			
		||||
				err = session.addUnique(tbNameWithSchema, name)
 | 
			
		||||
			} else if index.Type == core.IndexType {
 | 
			
		||||
				session.statement.RefTable = table
 | 
			
		||||
				session.statement.tableName = tbNameWithSchema
 | 
			
		||||
				err = session.addIndex(tbNameWithSchema, name)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check all the columns which removed from struct fields but left on database tables.
 | 
			
		||||
		for _, colName := range oriTable.ColumnsSeq() {
 | 
			
		||||
			if table.GetColumn(colName) == nil {
 | 
			
		||||
				engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(oriTable.Name, true), colName)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								vendor/xorm.io/xorm/session_stats.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								vendor/xorm.io/xorm/session_stats.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Count counts the records. bean's non-empty fields
 | 
			
		||||
// are conditions.
 | 
			
		||||
func (session *Session) Count(bean ...interface{}) (int64, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sqlStr string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
	var err error
 | 
			
		||||
	if session.statement.RawSQL == "" {
 | 
			
		||||
		sqlStr, args, err = session.statement.genCountSQL(bean...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		sqlStr = session.statement.RawSQL
 | 
			
		||||
		args = session.statement.RawParams
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var total int64
 | 
			
		||||
	err = session.queryRow(sqlStr, args...).Scan(&total)
 | 
			
		||||
	if err == sql.ErrNoRows || err == nil {
 | 
			
		||||
		return total, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sum call sum some column. bean's non-empty fields are conditions.
 | 
			
		||||
func (session *Session) sum(res interface{}, bean interface{}, columnNames ...string) error {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v := reflect.ValueOf(res)
 | 
			
		||||
	if v.Kind() != reflect.Ptr {
 | 
			
		||||
		return errors.New("need a pointer to a variable")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var isSlice = v.Elem().Kind() == reflect.Slice
 | 
			
		||||
	var sqlStr string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
	var err error
 | 
			
		||||
	if len(session.statement.RawSQL) == 0 {
 | 
			
		||||
		sqlStr, args, err = session.statement.genSumSQL(bean, columnNames...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		sqlStr = session.statement.RawSQL
 | 
			
		||||
		args = session.statement.RawParams
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if isSlice {
 | 
			
		||||
		err = session.queryRow(sqlStr, args...).ScanSlice(res)
 | 
			
		||||
	} else {
 | 
			
		||||
		err = session.queryRow(sqlStr, args...).Scan(res)
 | 
			
		||||
	}
 | 
			
		||||
	if err == sql.ErrNoRows || err == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sum call sum some column. bean's non-empty fields are conditions.
 | 
			
		||||
func (session *Session) Sum(bean interface{}, columnName string) (res float64, err error) {
 | 
			
		||||
	return res, session.sum(&res, bean, columnName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SumInt call sum some column. bean's non-empty fields are conditions.
 | 
			
		||||
func (session *Session) SumInt(bean interface{}, columnName string) (res int64, err error) {
 | 
			
		||||
	return res, session.sum(&res, bean, columnName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sums call sum some columns. bean's non-empty fields are conditions.
 | 
			
		||||
func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
 | 
			
		||||
	var res = make([]float64, len(columnNames), len(columnNames))
 | 
			
		||||
	return res, session.sum(&res, bean, columnNames...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SumsInt sum specify columns and return as []int64 instead of []float64
 | 
			
		||||
func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
 | 
			
		||||
	var res = make([]int64, len(columnNames), len(columnNames))
 | 
			
		||||
	return res, session.sum(&res, bean, columnNames...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								vendor/xorm.io/xorm/session_tx.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								vendor/xorm.io/xorm/session_tx.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
// Copyright 2016 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
 | 
			
		||||
 | 
			
		||||
// Begin a transaction
 | 
			
		||||
func (session *Session) Begin() error {
 | 
			
		||||
	if session.isAutoCommit {
 | 
			
		||||
		tx, err := session.DB().BeginTx(session.ctx, nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		session.isAutoCommit = false
 | 
			
		||||
		session.isCommitedOrRollbacked = false
 | 
			
		||||
		session.tx = tx
 | 
			
		||||
		session.saveLastSQL("BEGIN TRANSACTION")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Rollback When using transaction, you can rollback if any error
 | 
			
		||||
func (session *Session) Rollback() error {
 | 
			
		||||
	if !session.isAutoCommit && !session.isCommitedOrRollbacked {
 | 
			
		||||
		session.saveLastSQL(session.engine.dialect.RollBackStr())
 | 
			
		||||
		session.isCommitedOrRollbacked = true
 | 
			
		||||
		session.isAutoCommit = true
 | 
			
		||||
		return session.tx.Rollback()
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Commit When using transaction, Commit will commit all operations.
 | 
			
		||||
func (session *Session) Commit() error {
 | 
			
		||||
	if !session.isAutoCommit && !session.isCommitedOrRollbacked {
 | 
			
		||||
		session.saveLastSQL("COMMIT")
 | 
			
		||||
		session.isCommitedOrRollbacked = true
 | 
			
		||||
		session.isAutoCommit = true
 | 
			
		||||
		var err error
 | 
			
		||||
		if err = session.tx.Commit(); err == nil {
 | 
			
		||||
			// handle processors after tx committed
 | 
			
		||||
			closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
 | 
			
		||||
				if closuresPtr != nil {
 | 
			
		||||
					for _, closure := range *closuresPtr {
 | 
			
		||||
						closure(bean)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for bean, closuresPtr := range session.afterInsertBeans {
 | 
			
		||||
				closureCallFunc(closuresPtr, bean)
 | 
			
		||||
 | 
			
		||||
				if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
 | 
			
		||||
					processor.AfterInsert()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			for bean, closuresPtr := range session.afterUpdateBeans {
 | 
			
		||||
				closureCallFunc(closuresPtr, bean)
 | 
			
		||||
 | 
			
		||||
				if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
 | 
			
		||||
					processor.AfterUpdate()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			for bean, closuresPtr := range session.afterDeleteBeans {
 | 
			
		||||
				closureCallFunc(closuresPtr, bean)
 | 
			
		||||
 | 
			
		||||
				if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
 | 
			
		||||
					processor.AfterDelete()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
 | 
			
		||||
				if len(*slices) > 0 {
 | 
			
		||||
					*slices = make(map[interface{}]*[]func(interface{}), 0)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			cleanUpFunc(&session.afterInsertBeans)
 | 
			
		||||
			cleanUpFunc(&session.afterUpdateBeans)
 | 
			
		||||
			cleanUpFunc(&session.afterDeleteBeans)
 | 
			
		||||
		}
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										525
									
								
								vendor/xorm.io/xorm/session_update.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										525
									
								
								vendor/xorm.io/xorm/session_update.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,525 @@
 | 
			
		||||
// Copyright 2016 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 (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
 | 
			
		||||
	if table == nil ||
 | 
			
		||||
		session.tx != nil {
 | 
			
		||||
		return ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	oldhead, newsql := session.statement.convertUpdateSQL(sqlStr)
 | 
			
		||||
	if newsql == "" {
 | 
			
		||||
		return ErrCacheFailed
 | 
			
		||||
	}
 | 
			
		||||
	for _, filter := range session.engine.dialect.Filters() {
 | 
			
		||||
		newsql = filter.Do(newsql, session.engine.dialect, table)
 | 
			
		||||
	}
 | 
			
		||||
	session.engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql)
 | 
			
		||||
 | 
			
		||||
	var nStart int
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		if strings.Index(sqlStr, "?") > -1 {
 | 
			
		||||
			nStart = strings.Count(oldhead, "?")
 | 
			
		||||
		} else {
 | 
			
		||||
			// only for pq, TODO: if any other databse?
 | 
			
		||||
			nStart = strings.Count(oldhead, "$")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cacher := session.engine.getCacher(tableName)
 | 
			
		||||
	session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:])
 | 
			
		||||
	ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		rows, err := session.NoCache().queryRows(newsql, args[nStart:]...)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		defer rows.Close()
 | 
			
		||||
 | 
			
		||||
		ids = make([]core.PK, 0)
 | 
			
		||||
		for rows.Next() {
 | 
			
		||||
			var res = make([]string, len(table.PrimaryKeys))
 | 
			
		||||
			err = rows.ScanSlice(&res)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
 | 
			
		||||
			for i, col := range table.PKColumns() {
 | 
			
		||||
				if col.SQLType.IsNumeric() {
 | 
			
		||||
					n, err := strconv.ParseInt(res[i], 10, 64)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					pk[i] = n
 | 
			
		||||
				} else if col.SQLType.IsText() {
 | 
			
		||||
					pk[i] = res[i]
 | 
			
		||||
				} else {
 | 
			
		||||
					return errors.New("not supported")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ids = append(ids, pk)
 | 
			
		||||
		}
 | 
			
		||||
		session.engine.logger.Debug("[cacheUpdate] find updated id", ids)
 | 
			
		||||
	} /*else {
 | 
			
		||||
	    session.engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args)
 | 
			
		||||
	    cacher.DelIds(tableName, genSqlKey(newsql, args))
 | 
			
		||||
	}*/
 | 
			
		||||
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		sid, err := id.ToString()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if bean := cacher.GetBean(tableName, sid); bean != nil {
 | 
			
		||||
			sqls := splitNNoCase(sqlStr, "where", 2)
 | 
			
		||||
			if len(sqls) == 0 || len(sqls) > 2 {
 | 
			
		||||
				return ErrCacheFailed
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			sqls = splitNNoCase(sqls[0], "set", 2)
 | 
			
		||||
			if len(sqls) != 2 {
 | 
			
		||||
				return ErrCacheFailed
 | 
			
		||||
			}
 | 
			
		||||
			kvs := strings.Split(strings.TrimSpace(sqls[1]), ",")
 | 
			
		||||
 | 
			
		||||
			for idx, kv := range kvs {
 | 
			
		||||
				sps := strings.SplitN(kv, "=", 2)
 | 
			
		||||
				sps2 := strings.Split(sps[0], ".")
 | 
			
		||||
				colName := sps2[len(sps2)-1]
 | 
			
		||||
				// treat quote prefix, suffix and '`' as quotes
 | 
			
		||||
				quotes := append(strings.Split(session.engine.Quote(""), ""), "`")
 | 
			
		||||
				if strings.ContainsAny(colName, strings.Join(quotes, "")) {
 | 
			
		||||
					colName = strings.TrimSpace(eraseAny(colName, quotes...))
 | 
			
		||||
				} else {
 | 
			
		||||
					session.engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName)
 | 
			
		||||
					return ErrCacheFailed
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if col := table.GetColumn(colName); col != nil {
 | 
			
		||||
					fieldValue, err := col.ValueOf(bean)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						session.engine.logger.Error(err)
 | 
			
		||||
					} else {
 | 
			
		||||
						session.engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
 | 
			
		||||
						if col.IsVersion && session.statement.checkVersion {
 | 
			
		||||
							session.incrVersionFieldValue(fieldValue)
 | 
			
		||||
						} else {
 | 
			
		||||
							fieldValue.Set(reflect.ValueOf(args[idx]))
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					session.engine.logger.Errorf("[cacheUpdate] ERROR: column %v is not table %v's",
 | 
			
		||||
						colName, table.Name)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			session.engine.logger.Debug("[cacheUpdate] update cache", tableName, id, bean)
 | 
			
		||||
			cacher.PutBean(tableName, sid, bean)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	session.engine.logger.Debug("[cacheUpdate] clear cached table sql:", tableName)
 | 
			
		||||
	cacher.ClearIds(tableName)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update records, bean's non-empty fields are updated contents,
 | 
			
		||||
// condiBean' non-empty filds are conditions
 | 
			
		||||
// CAUTION:
 | 
			
		||||
//        1.bool will defaultly be updated content nor conditions
 | 
			
		||||
//         You should call UseBool if you have bool to use.
 | 
			
		||||
//        2.float32 & float64 may be not inexact as conditions
 | 
			
		||||
func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
 | 
			
		||||
	if session.isAutoClose {
 | 
			
		||||
		defer session.Close()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if session.statement.lastError != nil {
 | 
			
		||||
		return 0, session.statement.lastError
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v := rValue(bean)
 | 
			
		||||
	t := v.Type()
 | 
			
		||||
 | 
			
		||||
	var colNames []string
 | 
			
		||||
	var args []interface{}
 | 
			
		||||
 | 
			
		||||
	// handle before update processors
 | 
			
		||||
	for _, closure := range session.beforeClosures {
 | 
			
		||||
		closure(bean)
 | 
			
		||||
	}
 | 
			
		||||
	cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
 | 
			
		||||
	if processor, ok := interface{}(bean).(BeforeUpdateProcessor); ok {
 | 
			
		||||
		processor.BeforeUpdate()
 | 
			
		||||
	}
 | 
			
		||||
	// --
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	var isMap = t.Kind() == reflect.Map
 | 
			
		||||
	var isStruct = t.Kind() == reflect.Struct
 | 
			
		||||
	if isStruct {
 | 
			
		||||
		if err := session.statement.setRefBean(bean); err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(session.statement.TableName()) <= 0 {
 | 
			
		||||
			return 0, ErrTableNotFound
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if session.statement.ColumnStr == "" {
 | 
			
		||||
			colNames, args = session.statement.buildUpdates(bean, false, false,
 | 
			
		||||
				false, false, true)
 | 
			
		||||
		} else {
 | 
			
		||||
			colNames, args, err = session.genUpdateColumns(bean)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if isMap {
 | 
			
		||||
		colNames = make([]string, 0)
 | 
			
		||||
		args = make([]interface{}, 0)
 | 
			
		||||
		bValue := reflect.Indirect(reflect.ValueOf(bean))
 | 
			
		||||
 | 
			
		||||
		for _, v := range bValue.MapKeys() {
 | 
			
		||||
			colNames = append(colNames, session.engine.Quote(v.String())+" = ?")
 | 
			
		||||
			args = append(args, bValue.MapIndex(v).Interface())
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		return 0, ErrParamsType
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
 | 
			
		||||
	if session.statement.UseAutoTime && table != nil && table.Updated != "" {
 | 
			
		||||
		if !session.statement.columnMap.contain(table.Updated) &&
 | 
			
		||||
			!session.statement.omitColumnMap.contain(table.Updated) {
 | 
			
		||||
			colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
 | 
			
		||||
			col := table.UpdatedColumn()
 | 
			
		||||
			val, t := session.engine.nowTime(col)
 | 
			
		||||
			args = append(args, val)
 | 
			
		||||
 | 
			
		||||
			var colName = col.Name
 | 
			
		||||
			if isStruct {
 | 
			
		||||
				session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
					col := table.GetColumn(colName)
 | 
			
		||||
					setColumnTime(bean, col, t)
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// for update action to like "column = column + ?"
 | 
			
		||||
	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.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.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 {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var autoCond builder.Cond
 | 
			
		||||
	if !session.statement.noAutoCondition {
 | 
			
		||||
		condBeanIsStruct := false
 | 
			
		||||
		if len(condiBean) > 0 {
 | 
			
		||||
			if c, ok := condiBean[0].(map[string]interface{}); ok {
 | 
			
		||||
				autoCond = builder.Eq(c)
 | 
			
		||||
			} else {
 | 
			
		||||
				ct := reflect.TypeOf(condiBean[0])
 | 
			
		||||
				k := ct.Kind()
 | 
			
		||||
				if k == reflect.Ptr {
 | 
			
		||||
					k = ct.Elem().Kind()
 | 
			
		||||
				}
 | 
			
		||||
				if k == reflect.Struct {
 | 
			
		||||
					var err error
 | 
			
		||||
					autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return 0, err
 | 
			
		||||
					}
 | 
			
		||||
					condBeanIsStruct = true
 | 
			
		||||
				} else {
 | 
			
		||||
					return 0, ErrConditionType
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !condBeanIsStruct && table != nil {
 | 
			
		||||
			if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled
 | 
			
		||||
				autoCond1 := session.engine.CondDeleted(session.engine.Quote(col.Name))
 | 
			
		||||
 | 
			
		||||
				if autoCond == nil {
 | 
			
		||||
					autoCond = autoCond1
 | 
			
		||||
				} else {
 | 
			
		||||
					autoCond = autoCond.And(autoCond1)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	st := &session.statement
 | 
			
		||||
 | 
			
		||||
	var sqlStr string
 | 
			
		||||
	var condArgs []interface{}
 | 
			
		||||
	var condSQL string
 | 
			
		||||
	cond := session.statement.cond.And(autoCond)
 | 
			
		||||
 | 
			
		||||
	var doIncVer = (table != nil && table.Version != "" && session.statement.checkVersion)
 | 
			
		||||
	var verValue *reflect.Value
 | 
			
		||||
	if doIncVer {
 | 
			
		||||
		verValue, err = table.VersionColumn().ValueOf(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cond = cond.And(builder.Eq{session.engine.Quote(table.Version): verValue.Interface()})
 | 
			
		||||
		colNames = append(colNames, session.engine.Quote(table.Version)+" = "+session.engine.Quote(table.Version)+" + 1")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	condSQL, condArgs, err = builder.ToSQL(cond)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(condSQL) > 0 {
 | 
			
		||||
		condSQL = "WHERE " + condSQL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if st.OrderStr != "" {
 | 
			
		||||
		condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var tableName = session.statement.TableName()
 | 
			
		||||
	// TODO: Oracle support needed
 | 
			
		||||
	var top string
 | 
			
		||||
	if st.LimitN > 0 {
 | 
			
		||||
		if st.Engine.dialect.DBType() == core.MYSQL {
 | 
			
		||||
			condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
 | 
			
		||||
		} else if st.Engine.dialect.DBType() == core.SQLITE {
 | 
			
		||||
			tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
 | 
			
		||||
			cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)",
 | 
			
		||||
				session.engine.Quote(tableName), tempCondSQL), condArgs...))
 | 
			
		||||
			condSQL, condArgs, err = builder.ToSQL(cond)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
			if len(condSQL) > 0 {
 | 
			
		||||
				condSQL = "WHERE " + condSQL
 | 
			
		||||
			}
 | 
			
		||||
		} else if st.Engine.dialect.DBType() == core.POSTGRES {
 | 
			
		||||
			tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
 | 
			
		||||
			cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)",
 | 
			
		||||
				session.engine.Quote(tableName), tempCondSQL), condArgs...))
 | 
			
		||||
			condSQL, condArgs, err = builder.ToSQL(cond)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if len(condSQL) > 0 {
 | 
			
		||||
				condSQL = "WHERE " + condSQL
 | 
			
		||||
			}
 | 
			
		||||
		} else if st.Engine.dialect.DBType() == core.MSSQL {
 | 
			
		||||
			if st.OrderStr != "" && st.Engine.dialect.DBType() == core.MSSQL &&
 | 
			
		||||
				table != nil && len(table.PrimaryKeys) == 1 {
 | 
			
		||||
				cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)",
 | 
			
		||||
					table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0],
 | 
			
		||||
					session.engine.Quote(tableName), condSQL), condArgs...)
 | 
			
		||||
 | 
			
		||||
				condSQL, condArgs, err = builder.ToSQL(cond)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return 0, err
 | 
			
		||||
				}
 | 
			
		||||
				if len(condSQL) > 0 {
 | 
			
		||||
					condSQL = "WHERE " + condSQL
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				top = fmt.Sprintf("TOP (%d) ", st.LimitN)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(colNames) <= 0 {
 | 
			
		||||
		return 0, errors.New("No content found to be updated")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v",
 | 
			
		||||
		top,
 | 
			
		||||
		session.engine.Quote(tableName),
 | 
			
		||||
		strings.Join(colNames, ", "),
 | 
			
		||||
		condSQL)
 | 
			
		||||
 | 
			
		||||
	res, err := session.exec(sqlStr, append(args, condArgs...)...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	} else if doIncVer {
 | 
			
		||||
		if verValue != nil && verValue.IsValid() && verValue.CanSet() {
 | 
			
		||||
			session.incrVersionFieldValue(verValue)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
 | 
			
		||||
		// session.cacheUpdate(table, tableName, sqlStr, args...)
 | 
			
		||||
		session.engine.logger.Debug("[cacheUpdate] clear table ", tableName)
 | 
			
		||||
		cacher.ClearIds(tableName)
 | 
			
		||||
		cacher.ClearBeans(tableName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// handle after update processors
 | 
			
		||||
	if session.isAutoCommit {
 | 
			
		||||
		for _, closure := range session.afterClosures {
 | 
			
		||||
			closure(bean)
 | 
			
		||||
		}
 | 
			
		||||
		if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
 | 
			
		||||
			session.engine.logger.Debug("[event]", tableName, " has after update processor")
 | 
			
		||||
			processor.AfterUpdate()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		lenAfterClosures := len(session.afterClosures)
 | 
			
		||||
		if lenAfterClosures > 0 {
 | 
			
		||||
			if value, has := session.afterUpdateBeans[bean]; has && value != nil {
 | 
			
		||||
				*value = append(*value, session.afterClosures...)
 | 
			
		||||
			} else {
 | 
			
		||||
				afterClosures := make([]func(interface{}), lenAfterClosures)
 | 
			
		||||
				copy(afterClosures, session.afterClosures)
 | 
			
		||||
				// FIXME: if bean is a map type, it will panic because map cannot be as map key
 | 
			
		||||
				session.afterUpdateBeans[bean] = &afterClosures
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			if _, ok := interface{}(bean).(AfterUpdateProcessor); ok {
 | 
			
		||||
				session.afterUpdateBeans[bean] = nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
 | 
			
		||||
	// --
 | 
			
		||||
 | 
			
		||||
	return res.RowsAffected()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interface{}, error) {
 | 
			
		||||
	table := session.statement.RefTable
 | 
			
		||||
	colNames := make([]string, 0, len(table.ColumnsSeq()))
 | 
			
		||||
	args := make([]interface{}, 0, len(table.ColumnsSeq()))
 | 
			
		||||
 | 
			
		||||
	for _, col := range table.Columns() {
 | 
			
		||||
		if !col.IsVersion && !col.IsCreated && !col.IsUpdated {
 | 
			
		||||
			if session.statement.omitColumnMap.contain(col.Name) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if col.MapType == core.ONLYFROMDB {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fieldValuePtr, err := col.ValueOf(bean)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		fieldValue := *fieldValuePtr
 | 
			
		||||
 | 
			
		||||
		if col.IsAutoIncrement {
 | 
			
		||||
			switch fieldValue.Type().Kind() {
 | 
			
		||||
			case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
 | 
			
		||||
				if fieldValue.Int() == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
 | 
			
		||||
				if fieldValue.Uint() == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			case reflect.String:
 | 
			
		||||
				if len(fieldValue.String()) == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			case reflect.Ptr:
 | 
			
		||||
				if fieldValue.Pointer() == 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (col.IsDeleted && !session.statement.unscoped) || col.IsCreated {
 | 
			
		||||
			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
 | 
			
		||||
		if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
 | 
			
		||||
			if col.Nullable && isZero(fieldValue.Interface()) {
 | 
			
		||||
				var nilValue *int
 | 
			
		||||
				fieldValue = reflect.ValueOf(nilValue)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
 | 
			
		||||
			// if time is non-empty, then set to auto time
 | 
			
		||||
			val, t := session.engine.nowTime(col)
 | 
			
		||||
			args = append(args, val)
 | 
			
		||||
 | 
			
		||||
			var colName = col.Name
 | 
			
		||||
			session.afterClosures = append(session.afterClosures, func(bean interface{}) {
 | 
			
		||||
				col := table.GetColumn(colName)
 | 
			
		||||
				setColumnTime(bean, col, t)
 | 
			
		||||
			})
 | 
			
		||||
		} else if col.IsVersion && session.statement.checkVersion {
 | 
			
		||||
			args = append(args, 1)
 | 
			
		||||
		} else {
 | 
			
		||||
			arg, err := session.value2Interface(col, fieldValue)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return colNames, args, err
 | 
			
		||||
			}
 | 
			
		||||
			args = append(args, arg)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
 | 
			
		||||
	}
 | 
			
		||||
	return colNames, args, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1256
									
								
								vendor/xorm.io/xorm/statement.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1256
									
								
								vendor/xorm.io/xorm/statement.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										170
									
								
								vendor/xorm.io/xorm/statement_args.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								vendor/xorm.io/xorm/statement_args.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal 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
									
								
								vendor/xorm.io/xorm/statement_columnmap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/xorm.io/xorm/statement_columnmap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal 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
									
								
								vendor/xorm.io/xorm/statement_exprparam.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/xorm.io/xorm/statement_exprparam.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal 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
									
								
								vendor/xorm.io/xorm/statement_quote.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/xorm.io/xorm/statement_quote.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal 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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								vendor/xorm.io/xorm/syslogger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								vendor/xorm.io/xorm/syslogger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
// Copyright 2015 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.
 | 
			
		||||
 | 
			
		||||
// +build !windows,!nacl,!plan9
 | 
			
		||||
 | 
			
		||||
package xorm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log/syslog"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ core.ILogger = &SyslogLogger{}
 | 
			
		||||
 | 
			
		||||
// SyslogLogger will be depricated
 | 
			
		||||
type SyslogLogger struct {
 | 
			
		||||
	w       *syslog.Writer
 | 
			
		||||
	showSQL bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSyslogLogger implements core.ILogger
 | 
			
		||||
func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
 | 
			
		||||
	return &SyslogLogger{w: w}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debug log content as Debug
 | 
			
		||||
func (s *SyslogLogger) Debug(v ...interface{}) {
 | 
			
		||||
	s.w.Debug(fmt.Sprint(v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debugf log content as Debug and format
 | 
			
		||||
func (s *SyslogLogger) Debugf(format string, v ...interface{}) {
 | 
			
		||||
	s.w.Debug(fmt.Sprintf(format, v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error log content as Error
 | 
			
		||||
func (s *SyslogLogger) Error(v ...interface{}) {
 | 
			
		||||
	s.w.Err(fmt.Sprint(v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Errorf log content as Errorf and format
 | 
			
		||||
func (s *SyslogLogger) Errorf(format string, v ...interface{}) {
 | 
			
		||||
	s.w.Err(fmt.Sprintf(format, v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info log content as Info
 | 
			
		||||
func (s *SyslogLogger) Info(v ...interface{}) {
 | 
			
		||||
	s.w.Info(fmt.Sprint(v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Infof log content as Infof and format
 | 
			
		||||
func (s *SyslogLogger) Infof(format string, v ...interface{}) {
 | 
			
		||||
	s.w.Info(fmt.Sprintf(format, v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warn log content as Warn
 | 
			
		||||
func (s *SyslogLogger) Warn(v ...interface{}) {
 | 
			
		||||
	s.w.Warning(fmt.Sprint(v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warnf log content as Warnf and format
 | 
			
		||||
func (s *SyslogLogger) Warnf(format string, v ...interface{}) {
 | 
			
		||||
	s.w.Warning(fmt.Sprintf(format, v...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Level shows log level
 | 
			
		||||
func (s *SyslogLogger) Level() core.LogLevel {
 | 
			
		||||
	return core.LOG_UNKNOWN
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
 | 
			
		||||
func (s *SyslogLogger) SetLevel(l core.LogLevel) {}
 | 
			
		||||
 | 
			
		||||
// ShowSQL set if logging SQL
 | 
			
		||||
func (s *SyslogLogger) ShowSQL(show ...bool) {
 | 
			
		||||
	if len(show) == 0 {
 | 
			
		||||
		s.showSQL = true
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	s.showSQL = show[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsShowSQL if logging SQL
 | 
			
		||||
func (s *SyslogLogger) IsShowSQL() bool {
 | 
			
		||||
	return s.showSQL
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										311
									
								
								vendor/xorm.io/xorm/tag.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								vendor/xorm.io/xorm/tag.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,311 @@
 | 
			
		||||
// Copyright 2017 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"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type tagContext struct {
 | 
			
		||||
	tagName         string
 | 
			
		||||
	params          []string
 | 
			
		||||
	preTag, nextTag string
 | 
			
		||||
	table           *core.Table
 | 
			
		||||
	col             *core.Column
 | 
			
		||||
	fieldValue      reflect.Value
 | 
			
		||||
	isIndex         bool
 | 
			
		||||
	isUnique        bool
 | 
			
		||||
	indexNames      map[string]int
 | 
			
		||||
	engine          *Engine
 | 
			
		||||
	hasCacheTag     bool
 | 
			
		||||
	hasNoCacheTag   bool
 | 
			
		||||
	ignoreNext      bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tagHandler describes tag handler for XORM
 | 
			
		||||
type tagHandler func(ctx *tagContext) error
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// defaultTagHandlers enumerates all the default tag handler
 | 
			
		||||
	defaultTagHandlers = map[string]tagHandler{
 | 
			
		||||
		"<-":       OnlyFromDBTagHandler,
 | 
			
		||||
		"->":       OnlyToDBTagHandler,
 | 
			
		||||
		"PK":       PKTagHandler,
 | 
			
		||||
		"NULL":     NULLTagHandler,
 | 
			
		||||
		"NOT":      IgnoreTagHandler,
 | 
			
		||||
		"AUTOINCR": AutoIncrTagHandler,
 | 
			
		||||
		"DEFAULT":  DefaultTagHandler,
 | 
			
		||||
		"CREATED":  CreatedTagHandler,
 | 
			
		||||
		"UPDATED":  UpdatedTagHandler,
 | 
			
		||||
		"DELETED":  DeletedTagHandler,
 | 
			
		||||
		"VERSION":  VersionTagHandler,
 | 
			
		||||
		"UTC":      UTCTagHandler,
 | 
			
		||||
		"LOCAL":    LocalTagHandler,
 | 
			
		||||
		"NOTNULL":  NotNullTagHandler,
 | 
			
		||||
		"INDEX":    IndexTagHandler,
 | 
			
		||||
		"UNIQUE":   UniqueTagHandler,
 | 
			
		||||
		"CACHE":    CacheTagHandler,
 | 
			
		||||
		"NOCACHE":  NoCacheTagHandler,
 | 
			
		||||
		"COMMENT":  CommentTagHandler,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	for k := range core.SqlTypes {
 | 
			
		||||
		defaultTagHandlers[k] = SQLTypeTagHandler
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IgnoreTagHandler describes ignored tag handler
 | 
			
		||||
func IgnoreTagHandler(ctx *tagContext) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OnlyFromDBTagHandler describes mapping direction tag handler
 | 
			
		||||
func OnlyFromDBTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.MapType = core.ONLYFROMDB
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OnlyToDBTagHandler describes mapping direction tag handler
 | 
			
		||||
func OnlyToDBTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.MapType = core.ONLYTODB
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PKTagHandler decribes primary key tag handler
 | 
			
		||||
func PKTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.IsPrimaryKey = true
 | 
			
		||||
	ctx.col.Nullable = false
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NULLTagHandler describes null tag handler
 | 
			
		||||
func NULLTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT")
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NotNullTagHandler describes notnull tag handler
 | 
			
		||||
func NotNullTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.Nullable = false
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AutoIncrTagHandler describes autoincr tag handler
 | 
			
		||||
func AutoIncrTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.IsAutoIncrement = true
 | 
			
		||||
	/*
 | 
			
		||||
		if len(ctx.params) > 0 {
 | 
			
		||||
			autoStartInt, err := strconv.Atoi(ctx.params[0])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			ctx.col.AutoIncrStart = autoStartInt
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.col.AutoIncrStart = 1
 | 
			
		||||
		}
 | 
			
		||||
	*/
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultTagHandler describes default tag handler
 | 
			
		||||
func DefaultTagHandler(ctx *tagContext) error {
 | 
			
		||||
	if len(ctx.params) > 0 {
 | 
			
		||||
		ctx.col.Default = ctx.params[0]
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.col.Default = ctx.nextTag
 | 
			
		||||
		ctx.ignoreNext = true
 | 
			
		||||
	}
 | 
			
		||||
	ctx.col.DefaultIsEmpty = false
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreatedTagHandler describes created tag handler
 | 
			
		||||
func CreatedTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.IsCreated = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VersionTagHandler describes version tag handler
 | 
			
		||||
func VersionTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.IsVersion = true
 | 
			
		||||
	ctx.col.Default = "1"
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UTCTagHandler describes utc tag handler
 | 
			
		||||
func UTCTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.TimeZone = time.UTC
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LocalTagHandler describes local tag handler
 | 
			
		||||
func LocalTagHandler(ctx *tagContext) error {
 | 
			
		||||
	if len(ctx.params) == 0 {
 | 
			
		||||
		ctx.col.TimeZone = time.Local
 | 
			
		||||
	} else {
 | 
			
		||||
		var err error
 | 
			
		||||
		ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UpdatedTagHandler describes updated tag handler
 | 
			
		||||
func UpdatedTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.IsUpdated = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeletedTagHandler describes deleted tag handler
 | 
			
		||||
func DeletedTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.IsDeleted = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IndexTagHandler describes index tag handler
 | 
			
		||||
func IndexTagHandler(ctx *tagContext) error {
 | 
			
		||||
	if len(ctx.params) > 0 {
 | 
			
		||||
		ctx.indexNames[ctx.params[0]] = core.IndexType
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.isIndex = true
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UniqueTagHandler describes unique tag handler
 | 
			
		||||
func UniqueTagHandler(ctx *tagContext) error {
 | 
			
		||||
	if len(ctx.params) > 0 {
 | 
			
		||||
		ctx.indexNames[ctx.params[0]] = core.UniqueType
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.isUnique = true
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CommentTagHandler add comment to column
 | 
			
		||||
func CommentTagHandler(ctx *tagContext) error {
 | 
			
		||||
	if len(ctx.params) > 0 {
 | 
			
		||||
		ctx.col.Comment = strings.Trim(ctx.params[0], "' ")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SQLTypeTagHandler describes SQL Type tag handler
 | 
			
		||||
func SQLTypeTagHandler(ctx *tagContext) error {
 | 
			
		||||
	ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
 | 
			
		||||
	if len(ctx.params) > 0 {
 | 
			
		||||
		if ctx.tagName == core.Enum {
 | 
			
		||||
			ctx.col.EnumOptions = make(map[string]int)
 | 
			
		||||
			for k, v := range ctx.params {
 | 
			
		||||
				v = strings.TrimSpace(v)
 | 
			
		||||
				v = strings.Trim(v, "'")
 | 
			
		||||
				ctx.col.EnumOptions[v] = k
 | 
			
		||||
			}
 | 
			
		||||
		} else if ctx.tagName == core.Set {
 | 
			
		||||
			ctx.col.SetOptions = make(map[string]int)
 | 
			
		||||
			for k, v := range ctx.params {
 | 
			
		||||
				v = strings.TrimSpace(v)
 | 
			
		||||
				v = strings.Trim(v, "'")
 | 
			
		||||
				ctx.col.SetOptions[v] = k
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			var err error
 | 
			
		||||
			if len(ctx.params) == 2 {
 | 
			
		||||
				ctx.col.Length, err = strconv.Atoi(ctx.params[0])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			} else if len(ctx.params) == 1 {
 | 
			
		||||
				ctx.col.Length, err = strconv.Atoi(ctx.params[0])
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExtendsTagHandler describes extends tag handler
 | 
			
		||||
func ExtendsTagHandler(ctx *tagContext) error {
 | 
			
		||||
	var fieldValue = ctx.fieldValue
 | 
			
		||||
	var isPtr = false
 | 
			
		||||
	switch fieldValue.Kind() {
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		f := fieldValue.Type().Elem()
 | 
			
		||||
		if f.Kind() == reflect.Struct {
 | 
			
		||||
			fieldPtr := fieldValue
 | 
			
		||||
			fieldValue = fieldValue.Elem()
 | 
			
		||||
			if !fieldValue.IsValid() || fieldPtr.IsNil() {
 | 
			
		||||
				fieldValue = reflect.New(f).Elem()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		isPtr = true
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		parentTable, err := ctx.engine.mapType(fieldValue)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		for _, col := range parentTable.Columns() {
 | 
			
		||||
			col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
 | 
			
		||||
 | 
			
		||||
			var tagPrefix = ctx.col.FieldName
 | 
			
		||||
			if len(ctx.params) > 0 {
 | 
			
		||||
				col.Nullable = isPtr
 | 
			
		||||
				tagPrefix = ctx.params[0]
 | 
			
		||||
				if col.IsPrimaryKey {
 | 
			
		||||
					col.Name = ctx.col.FieldName
 | 
			
		||||
					col.IsPrimaryKey = false
 | 
			
		||||
				} else {
 | 
			
		||||
					col.Name = fmt.Sprintf("%v%v", tagPrefix, col.Name)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if col.Nullable {
 | 
			
		||||
				col.IsAutoIncrement = false
 | 
			
		||||
				col.IsPrimaryKey = false
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ctx.table.AddColumn(col)
 | 
			
		||||
			for indexName, indexType := range col.Indexes {
 | 
			
		||||
				addIndex(indexName, ctx.table, col, indexType)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		//TODO: warning
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CacheTagHandler describes cache tag handler
 | 
			
		||||
func CacheTagHandler(ctx *tagContext) error {
 | 
			
		||||
	if !ctx.hasCacheTag {
 | 
			
		||||
		ctx.hasCacheTag = true
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NoCacheTagHandler describes nocache tag handler
 | 
			
		||||
func NoCacheTagHandler(ctx *tagContext) error {
 | 
			
		||||
	if !ctx.hasNoCacheTag {
 | 
			
		||||
		ctx.hasNoCacheTag = true
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_mssql.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_mssql.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test"
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_mssql_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_mssql_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test" -cache=true
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_mymysql.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_mymysql.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=mymysql -conn_str="xorm_test/root/"
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_mymysql_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_mymysql_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=mymysql -conn_str="xorm_test/root/" -cache=true
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_mysql.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_mysql.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=mysql -conn_str="root:@/xorm_test"
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_mysql_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_mysql_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=mysql -conn_str="root:@/xorm_test" -cache=true
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_postgres.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_postgres.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=postgres -conn_str="dbname=xorm_test sslmode=disable"
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_postgres_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_postgres_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=postgres -conn_str="dbname=xorm_test sslmode=disable" -cache=true
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_sqlite.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_sqlite.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc"
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_sqlite_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_sqlite_cache.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" -cache=true
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/xorm.io/xorm/test_tidb.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/xorm.io/xorm/test_tidb.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
go test -db=mysql -conn_str="root:@tcp(localhost:4000)/xorm_test" -ignore_select_update=true
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/xorm.io/xorm/transaction.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/xorm.io/xorm/transaction.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
// Copyright 2018 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
 | 
			
		||||
 | 
			
		||||
// Transaction Execute sql wrapped in a transaction(abbr as tx), tx will automatic commit if no errors occurred
 | 
			
		||||
func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interface{}, error) {
 | 
			
		||||
	session := engine.NewSession()
 | 
			
		||||
	defer session.Close()
 | 
			
		||||
 | 
			
		||||
	if err := session.Begin(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := f(session)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := session.Commit(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/xorm.io/xorm/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/xorm.io/xorm/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
// Copyright 2017 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 (
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ptrPkType = reflect.TypeOf(&core.PK{})
 | 
			
		||||
	pkType    = reflect.TypeOf(core.PK{})
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										126
									
								
								vendor/xorm.io/xorm/xorm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								vendor/xorm.io/xorm/xorm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
// Copyright 2015 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.
 | 
			
		||||
 | 
			
		||||
// +build go1.8
 | 
			
		||||
 | 
			
		||||
package xorm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/core"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Version show the xorm's version
 | 
			
		||||
	Version string = "0.8.0.1015"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func regDrvsNDialects() bool {
 | 
			
		||||
	providedDrvsNDialects := map[string]struct {
 | 
			
		||||
		dbType     core.DbType
 | 
			
		||||
		getDriver  func() core.Driver
 | 
			
		||||
		getDialect func() core.Dialect
 | 
			
		||||
	}{
 | 
			
		||||
		"mssql":    {"mssql", func() core.Driver { return &odbcDriver{} }, func() core.Dialect { return &mssql{} }},
 | 
			
		||||
		"odbc":     {"mssql", func() core.Driver { return &odbcDriver{} }, func() core.Dialect { return &mssql{} }}, // !nashtsai! TODO change this when supporting MS Access
 | 
			
		||||
		"mysql":    {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }},
 | 
			
		||||
		"mymysql":  {"mysql", func() core.Driver { return &mymysqlDriver{} }, func() core.Dialect { return &mysql{} }},
 | 
			
		||||
		"postgres": {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }},
 | 
			
		||||
		"pgx":      {"postgres", func() core.Driver { return &pqDriverPgx{} }, func() core.Dialect { return &postgres{} }},
 | 
			
		||||
		"sqlite3":  {"sqlite3", func() core.Driver { return &sqlite3Driver{} }, func() core.Dialect { return &sqlite3{} }},
 | 
			
		||||
		"oci8":     {"oracle", func() core.Driver { return &oci8Driver{} }, func() core.Dialect { return &oracle{} }},
 | 
			
		||||
		"goracle":  {"oracle", func() core.Driver { return &goracleDriver{} }, func() core.Dialect { return &oracle{} }},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for driverName, v := range providedDrvsNDialects {
 | 
			
		||||
		if driver := core.QueryDriver(driverName); driver == nil {
 | 
			
		||||
			core.RegisterDriver(driverName, v.getDriver())
 | 
			
		||||
			core.RegisterDialect(v.dbType, v.getDialect)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func close(engine *Engine) {
 | 
			
		||||
	engine.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	regDrvsNDialects()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewEngine new a db manager according to the parameter. Currently support four
 | 
			
		||||
// drivers
 | 
			
		||||
func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
 | 
			
		||||
	driver := core.QueryDriver(driverName)
 | 
			
		||||
	if driver == nil {
 | 
			
		||||
		return nil, fmt.Errorf("Unsupported driver name: %v", driverName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uri, err := driver.Parse(driverName, dataSourceName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dialect := core.QueryDialect(uri.DbType)
 | 
			
		||||
	if dialect == nil {
 | 
			
		||||
		return nil, fmt.Errorf("Unsupported dialect type: %v", uri.DbType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	db, err := core.Open(driverName, dataSourceName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = dialect.Init(db, uri, driverName, dataSourceName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	engine := &Engine{
 | 
			
		||||
		db:             db,
 | 
			
		||||
		dialect:        dialect,
 | 
			
		||||
		Tables:         make(map[reflect.Type]*core.Table),
 | 
			
		||||
		mutex:          &sync.RWMutex{},
 | 
			
		||||
		TagIdentifier:  "xorm",
 | 
			
		||||
		TZLocation:     time.Local,
 | 
			
		||||
		tagHandlers:    defaultTagHandlers,
 | 
			
		||||
		cachers:        make(map[string]core.Cacher),
 | 
			
		||||
		defaultContext: context.Background(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if uri.DbType == core.SQLITE {
 | 
			
		||||
		engine.DatabaseTZ = time.UTC
 | 
			
		||||
	} else {
 | 
			
		||||
		engine.DatabaseTZ = time.Local
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logger := NewSimpleLogger(os.Stdout)
 | 
			
		||||
	logger.SetLevel(core.LOG_INFO)
 | 
			
		||||
	engine.SetLogger(logger)
 | 
			
		||||
	engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper)))
 | 
			
		||||
 | 
			
		||||
	runtime.SetFinalizer(engine, close)
 | 
			
		||||
 | 
			
		||||
	return engine, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewEngineWithParams new a db manager with params. The params will be passed to dialect.
 | 
			
		||||
func NewEngineWithParams(driverName string, dataSourceName string, params map[string]string) (*Engine, error) {
 | 
			
		||||
	engine, err := NewEngine(driverName, dataSourceName)
 | 
			
		||||
	engine.dialect.SetParams(params)
 | 
			
		||||
	return engine, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clone clone an engine
 | 
			
		||||
func (engine *Engine) Clone() (*Engine, error) {
 | 
			
		||||
	return NewEngine(engine.DriverName(), engine.DataSourceName())
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user