]> source.dussan.org Git - gitea.git/commitdiff
Upgrade xorm to v1.1.1 (#16339)
authorLunny Xiao <xiaolunwen@gmail.com>
Sun, 4 Jul 2021 13:10:46 +0000 (21:10 +0800)
committerGitHub <noreply@github.com>
Sun, 4 Jul 2021 13:10:46 +0000 (15:10 +0200)
39 files changed:
go.mod
go.sum
vendor/modules.txt
vendor/xorm.io/xorm/.drone.yml
vendor/xorm.io/xorm/.gitignore
vendor/xorm.io/xorm/.revive.toml
vendor/xorm.io/xorm/CHANGELOG.md
vendor/xorm.io/xorm/convert.go
vendor/xorm.io/xorm/dialects/dialect.go
vendor/xorm.io/xorm/dialects/filter.go
vendor/xorm.io/xorm/dialects/mssql.go
vendor/xorm.io/xorm/dialects/mysql.go
vendor/xorm.io/xorm/dialects/oracle.go
vendor/xorm.io/xorm/dialects/postgres.go
vendor/xorm.io/xorm/dialects/sqlite3.go
vendor/xorm.io/xorm/engine.go
vendor/xorm.io/xorm/go.mod
vendor/xorm.io/xorm/go.sum
vendor/xorm.io/xorm/interface.go
vendor/xorm.io/xorm/internal/json/jsoniter.go [new file with mode: 0644]
vendor/xorm.io/xorm/internal/statements/expr.go [new file with mode: 0644]
vendor/xorm.io/xorm/internal/statements/expr_param.go [deleted file]
vendor/xorm.io/xorm/internal/statements/insert.go
vendor/xorm.io/xorm/internal/statements/query.go
vendor/xorm.io/xorm/internal/statements/statement.go
vendor/xorm.io/xorm/internal/statements/update.go
vendor/xorm.io/xorm/log/logger.go
vendor/xorm.io/xorm/scan.go [new file with mode: 0644]
vendor/xorm.io/xorm/schemas/column.go
vendor/xorm.io/xorm/schemas/table.go
vendor/xorm.io/xorm/schemas/version.go [new file with mode: 0644]
vendor/xorm.io/xorm/session.go
vendor/xorm.io/xorm/session_convert.go
vendor/xorm.io/xorm/session_insert.go
vendor/xorm.io/xorm/session_query.go
vendor/xorm.io/xorm/session_raw.go
vendor/xorm.io/xorm/session_update.go
vendor/xorm.io/xorm/tags/parser.go
vendor/xorm.io/xorm/tags/tag.go

diff --git a/go.mod b/go.mod
index dbec7b37104b44fc59af44b5a3df43e986636202..82c98c91678742ff6efbd03029bdc5db2d61d0bf 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -139,7 +139,7 @@ require (
        mvdan.cc/xurls/v2 v2.2.0
        strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
        xorm.io/builder v0.3.9
-       xorm.io/xorm v1.1.0
+       xorm.io/xorm v1.1.1
 )
 
 replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
diff --git a/go.sum b/go.sum
index 110e2e6834effa4de18f8bc97c022da8dfc68232..9c4f97329a03bfd8a5c9ae21406b204f6633226e 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -1615,5 +1615,5 @@ xorm.io/builder v0.3.8/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
 xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=
 xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
 xorm.io/xorm v1.0.6/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=
-xorm.io/xorm v1.1.0 h1:mkEsQXLauZajiOld2cB2PkFcUZKePepPgs1bC1dw8RA=
-xorm.io/xorm v1.1.0/go.mod h1:EDzNHMuCVZNszkIRSLL2nI0zX+nQE8RstAVranlSfqI=
+xorm.io/xorm v1.1.1 h1:cc1yot5rhoBucfk2lgZPZPEuI/9QsVvHuQpjI0wmcf8=
+xorm.io/xorm v1.1.1/go.mod h1:Cb0DKYTHbyECMaSfgRnIZp5aiUgQozxcJJ0vzcLGJSg=
index 136d828e944c342da0b739289a59f8c23510be18..11e1ff1b8c4323e88a5429ed6881b5a08bfe797a 100644 (file)
@@ -1037,7 +1037,7 @@ strk.kbt.io/projects/go/libravatar
 # xorm.io/builder v0.3.9
 ## explicit
 xorm.io/builder
-# xorm.io/xorm v1.1.0
+# xorm.io/xorm v1.1.1
 ## explicit
 xorm.io/xorm
 xorm.io/xorm/caches
index 05f06e99cc7386b1a8a63a8740bacf97d7b4cd0b..4f84d7faa0ef601e6d22aa9470961db06b0dac56 100644 (file)
 ---
 kind: pipeline
-name: testing
+name: test-mysql
+environment:
+  GO111MODULE: "on"
+  GOPROXY: "https://goproxy.io"
+  CGO_ENABLED: 1
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
 - name: test-vet
   image: golang:1.15
-  environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
-  commands:
-    - make vet
-    - make fmt-check
-  volumes:
-  - name: cache
-    path: /go
-  when:
-    event:
-    - push
-    - pull_request
-
-- name: rebuild-cache
-  image: meltwater/drone-cache
-  pull: true
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
-volumes:
-  - name: cache
-    temp: {}
-
----
-kind: pipeline
-name: test-sqlite
-depends_on:
-  - testing
-steps:
-- name: restore-cache
-  image: meltwater/drone-cache:dev
   pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
   volumes:
   - name: cache
-    path: /go
-
+    path: /go/pkg/mod
+  commands:
+    - make vet
 - name: test-sqlite3
   image: golang:1.15
-  environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
-  commands:
-  - make test-sqlite3
-  - TEST_CACHE_ENABLE=true make test-sqlite3
-  - TEST_QUOTE_POLICY=reserved make test-sqlite3
   volumes:
   - name: cache
-    path: /go
-
-- name: test-sqlite
-  image: golang:1.15
-  environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
+    path: /go/pkg/mod
+  depends_on:
+  - test-vet
   commands:
-  - make test-sqlite
-  - TEST_CACHE_ENABLE=true make test-sqlite
-  - TEST_QUOTE_POLICY=reserved make test-sqlite
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache:dev
-  pull: true
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
-volumes:
-  - name: cache
-    temp: {}
-
----
-kind: pipeline
-name: test-mysql
-depends_on:
-  - testing
-steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
+    - make fmt-check
+    - make test
+    - make test-sqlite3
+    - TEST_CACHE_ENABLE=true make test-sqlite3
+    - TEST_QUOTE_POLICY=reserved make test-sqlite3
+    - make test-sqlite
+    - TEST_CACHE_ENABLE=true make test-sqlite
+    - TEST_QUOTE_POLICY=reserved make test-sqlite
 - name: test-mysql
   image: golang:1.15
+  pull: never
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
+  depends_on:
+  - test-vet
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_MYSQL_HOST: mysql
     TEST_MYSQL_CHARSET: utf8
     TEST_MYSQL_DBNAME: xorm_test
     TEST_MYSQL_USERNAME: root
     TEST_MYSQL_PASSWORD:
   commands:
-  - make test
-  - make test-mysql
   - TEST_CACHE_ENABLE=true make test-mysql
-  - TEST_QUOTE_POLICY=reserved make test-mysql
-  volumes:
-  - name: cache
-    path: /go
   
 - name: test-mysql-utf8mb4
   image: golang:1.15
+  pull: never
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   depends_on:
   - test-mysql
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_MYSQL_HOST: mysql
     TEST_MYSQL_CHARSET: utf8mb4
     TEST_MYSQL_DBNAME: xorm_test
@@ -192,62 +67,15 @@ steps:
     TEST_MYSQL_PASSWORD:
   commands:
   - make test-mysql
-  - TEST_CACHE_ENABLE=true make test-mysql
   - TEST_QUOTE_POLICY=reserved make test-mysql
-  volumes:
-  - name: cache
-    path: /go
-
-- name: test-mymysql
-  pull: default
-  image: golang:1.15
-  depends_on:
-    - test-mysql-utf8mb4
-  environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
-    TEST_MYSQL_HOST: mysql:3306
-    TEST_MYSQL_DBNAME: xorm_test
-    TEST_MYSQL_USERNAME: root
-    TEST_MYSQL_PASSWORD:
-  commands:
-  - make test-mymysql
-  - TEST_CACHE_ENABLE=true make test-mymysql
-  - TEST_QUOTE_POLICY=reserved make test-mymysql
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache
-  depends_on:
-  - test-mysql
-  - test-mysql-utf8mb4
-  - test-mymysql
-  pull: true
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
 
 volumes:
-  - name: cache
-    temp: {}
+- name: cache
+  host:
+    path: /tmp/cache
 
 services:
 - name: mysql
-  pull: default
   image: mysql:5.7
   environment:
     MYSQL_ALLOW_EMPTY_PASSWORD: yes
@@ -258,32 +86,18 @@ kind: pipeline
 name: test-mysql8
 depends_on:
   - test-mysql
-  - test-sqlite
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
 - name: test-mysql8
   image: golang:1.15
+  pull: never
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_MYSQL_HOST: mysql8
     TEST_MYSQL_CHARSET: utf8mb4
     TEST_MYSQL_DBNAME: xorm_test
@@ -293,35 +107,14 @@ steps:
   - make test-mysql
   - TEST_CACHE_ENABLE=true make test-mysql
   - TEST_QUOTE_POLICY=reserved make test-mysql
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache:dev
-  pull: true
-  depends_on:
-  - test-mysql8
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
 
 volumes:
-  - name: cache
-    temp: {}
+- name: cache
+  host:
+    path: /tmp/cache
 
 services:
 - name: mysql8
-  pull: default
   image: mysql:8.0
   environment:
     MYSQL_ALLOW_EMPTY_PASSWORD: yes
@@ -332,31 +125,18 @@ kind: pipeline
 name: test-mariadb
 depends_on:
   - test-mysql8
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
 - name: test-mariadb
   image: golang:1.15
+  pull: never
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_MYSQL_HOST: mariadb
     TEST_MYSQL_CHARSET: utf8mb4
     TEST_MYSQL_DBNAME: xorm_test
@@ -366,35 +146,14 @@ steps:
   - make test-mysql
   - TEST_CACHE_ENABLE=true make test-mysql
   - TEST_QUOTE_POLICY=reserved make test-mysql
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache:dev
-  depends_on:
-  - test-mariadb
-  pull: true
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
 
 volumes:
-  - name: cache
-    temp: {}
+- name: cache
+  host:
+    path: /tmp/cache
 
 services:
 - name: mariadb
-  pull: default
   image: mariadb:10.4
   environment:
     MYSQL_ALLOW_EMPTY_PASSWORD: yes
@@ -405,32 +164,18 @@ kind: pipeline
 name: test-postgres
 depends_on:
   - test-mariadb
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
 - name: test-postgres
-  pull: default
+  pull: never
   image: golang:1.15
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_PGSQL_HOST: pgsql
     TEST_PGSQL_DBNAME: xorm_test
     TEST_PGSQL_USERNAME: postgres
@@ -438,60 +183,31 @@ steps:
   commands:
   - make test-postgres
   - TEST_CACHE_ENABLE=true make test-postgres
-  - TEST_QUOTE_POLICY=reserved make test-postgres
-  volumes:
-  - name: cache
-    path: /go
 
 - name: test-postgres-schema
-  pull: default
+  pull: never
   image: golang:1.15
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   depends_on:
   - test-postgres
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_PGSQL_HOST: pgsql
     TEST_PGSQL_SCHEMA: xorm
     TEST_PGSQL_DBNAME: xorm_test
     TEST_PGSQL_USERNAME: postgres
     TEST_PGSQL_PASSWORD: postgres
   commands:
-  - make test-postgres
-  - TEST_CACHE_ENABLE=true make test-postgres
   - TEST_QUOTE_POLICY=reserved make test-postgres
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache:dev
-  pull: true
-  depends_on:
-  - test-postgres-schema
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
 
 volumes:
-  - name: cache
-    temp: {}
+- name: cache
+  host:
+    path: /tmp/cache
 
 services:
 - name: pgsql
-  pull: default
   image: postgres:9.5
   environment:
     POSTGRES_DB: xorm_test
@@ -503,32 +219,18 @@ kind: pipeline
 name: test-mssql
 depends_on:
   - test-postgres
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
 - name: test-mssql
-  pull: default
+  pull: never
   image: golang:1.15
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_MSSQL_HOST: mssql
     TEST_MSSQL_DBNAME: xorm_test
     TEST_MSSQL_USERNAME: sa
@@ -538,70 +240,38 @@ steps:
   - TEST_CACHE_ENABLE=true make test-mssql
   - TEST_QUOTE_POLICY=reserved make test-mssql
   - TEST_MSSQL_DEFAULT_VARCHAR=NVARCHAR TEST_MSSQL_DEFAULT_CHAR=NCHAR make test-mssql
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache:dev
-  pull: true
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
 
 volumes:
-  - name: cache
-    temp: {}
+- name: cache
+  host:
+    path: /tmp/cache
 
 services:
 - name: mssql
-  pull: default
-  image: microsoft/mssql-server-linux:latest
+  pull: always
+  image: mcr.microsoft.com/mssql/server:latest
   environment:
     ACCEPT_EULA: Y
     SA_PASSWORD: yourStrong(!)Password
-    MSSQL_PID: Developer
+    MSSQL_PID: Standard
 
 ---
 kind: pipeline
 name: test-tidb
 depends_on:
   - test-mssql
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
 - name: test-tidb
-  pull: default
+  pull: never
   image: golang:1.15
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_TIDB_HOST: "tidb:4000"
     TEST_TIDB_DBNAME: xorm_test
     TEST_TIDB_USERNAME: root
@@ -610,33 +280,14 @@ steps:
   - make test-tidb
   - TEST_CACHE_ENABLE=true make test-tidb
   - TEST_QUOTE_POLICY=reserved make test-tidb
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache:dev
-  pull: true
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
 
 volumes:
-  - name: cache
-    temp: {}
+- name: cache
+  host:
+    path: /tmp/cache
 
 services:
 - name: tidb
-  pull: default
   image: pingcap/tidb:v3.0.3
 
 ---
@@ -644,32 +295,18 @@ kind: pipeline
 name: test-cockroach
 depends_on:
   - test-tidb
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
-- name: restore-cache
-  image: meltwater/drone-cache
-  pull: always
-  settings:
-    backend: "filesystem"
-    restore: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
-
 - name: test-cockroach
-  pull: default
+  pull: never
   image: golang:1.15
+  volumes:
+  - name: cache
+    path: /go/pkg/mod
   environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
-    CGO_ENABLED: 1
-    GOMODCACHE: '/drone/src/pkg.mod'
-    GOCACHE: '/drone/src/pkg.build'
     TEST_COCKROACH_HOST: "cockroach:26257"
     TEST_COCKROACH_DBNAME: xorm_test
     TEST_COCKROACH_USERNAME: root
@@ -678,33 +315,14 @@ steps:
   - sleep 10
   - make test-cockroach
   - TEST_CACHE_ENABLE=true make test-cockroach
-  volumes:
-  - name: cache
-    path: /go
-
-- name: rebuild-cache
-  image: meltwater/drone-cache:dev
-  pull: true
-  settings:
-    backend: "filesystem"
-    rebuild: true
-    cache_key: '{{ .Repo.Name }}_{{ checksum "go.mod" }}_{{ checksum "go.sum" }}_{{ arch }}_{{ os }}'
-    archive_format: "gzip"
-    filesystem_cache_root: "/go"
-    mount:
-      - pkg.mod
-      - pkg.build
-  volumes:
-  - name: cache
-    path: /go
 
 volumes:
-  - name: cache
-    temp: {}
+- name: cache
+  host:
+    path: /tmp/cache
 
 services:
 - name: cockroach
-  pull: default
   image: cockroachdb/cockroach:v19.2.4
   commands:
   - /cockroach/cockroach start --insecure
@@ -713,8 +331,6 @@ services:
 kind: pipeline
 name: merge_coverage
 depends_on:
-  - testing
-  - test-sqlite
   - test-mysql
   - test-mysql8
   - test-mariadb
@@ -722,18 +338,12 @@ depends_on:
   - test-mssql
   - test-tidb
   - test-cockroach
+trigger:
+  ref:
+  - refs/heads/master
+  - refs/pull/*/head
 steps:
 - name: merge_coverage
-  pull: default
   image: golang:1.15
-  environment:
-    GO111MODULE: "on"
-    GOPROXY: "https://goproxy.io"
   commands:
   - make coverage
-  when:
-    branch:
-      - master
-    event:
-      - push
-      - pull_request
index a3fbadd4bde27762a3999c0b8f0ed6884d5d10c5..a183a295897be38dea65246863e40c00e70bbb8b 100644 (file)
@@ -36,4 +36,5 @@ test.db.sql
 *coverage.out
 test.db
 integrations/*.sql
-integrations/test_sqlite*
\ No newline at end of file
+integrations/test_sqlite*
+cover.out
\ No newline at end of file
index 6dec7465ae98cb281f3a7fd7745eafaa8ad3226e..9e3b629d2386e48da26723b8cae77272eb9e9e89 100644 (file)
@@ -8,20 +8,22 @@ warningCode = 1
 [rule.context-as-argument]
 [rule.context-keys-type]
 [rule.dot-imports]
+[rule.empty-lines]
+[rule.errorf]
 [rule.error-return]
 [rule.error-strings]
 [rule.error-naming]
 [rule.exported]
 [rule.if-return]
 [rule.increment-decrement]
-[rule.var-naming]
-  arguments = [["ID", "UID", "UUID", "URL", "JSON"], []]
-[rule.var-declaration]
+[rule.indent-error-flow]
 [rule.package-comments]
 [rule.range]
 [rule.receiver-naming]
+[rule.struct-tag]
 [rule.time-naming]
 [rule.unexported-return]
-[rule.indent-error-flow]
-[rule.errorf]
-[rule.struct-tag]
\ No newline at end of file
+[rule.unnecessary-stmt]
+[rule.var-declaration]
+[rule.var-naming]
+  arguments = [["ID", "UID", "UUID", "URL", "JSON"], []]
\ No newline at end of file
index 13e721ecaef49134b59ff2208c55b61277e626e2..ce5b4fe94c97281ffcced698b1f98e941e621135 100644 (file)
@@ -3,6 +3,36 @@
 This changelog goes through all the changes that have been made in each release
 without substantial changes to our git log.
 
+## [1.1.1](https://gitea.com/xorm/xorm/releases/tag/1.1.1) - 2021-07-03
+
+* BUGFIXES
+  * Ignore comments when deciding when to replace question marks. #1954 (#1955)
+  * Fix bug didn't reset statement on update (#1939)
+  * Fix create table with struct missing columns (#1938)
+  * Fix #929 (#1936)
+  * Fix exist (#1921)
+* ENHANCEMENTS
+  * Improve get field value of bean (#1961)
+  * refactor splitTag function (#1960)
+  * Fix #1663 (#1952)
+  * fix pg GetColumns missing comment (#1949)
+  * Support build flag jsoniter to replace default json (#1916)
+  * refactor exprParam (#1825)
+  * Add DBVersion (#1723)
+* TESTING
+  * Add test to confirm #1247 resolved (#1951)
+  * Add test for dump table with default value (#1950)
+  * Test for #1486 (#1942)
+  * Add sync tests to confirm #539 is gone (#1937)
+  * test for unsigned int32 (#1923)
+  * Add tests for array store (#1922)
+* BUILD
+  * Remove mymysql from ci (#1928)
+* MISC
+  * fix lint (#1953)
+  * Compitable with cockroach (#1930)
+  * Replace goracle  with godror (#1914)
+
 ## [1.1.0](https://gitea.com/xorm/xorm/releases/tag/1.1.0) - 2021-05-14
 
 * FEATURES
index c19d30e07f485b3514b1be6f16dc2eb8492eda26..b7f30caddca65486f6036e261f1f05e94450e702 100644 (file)
@@ -175,7 +175,10 @@ func convertAssign(dest, src interface{}) error {
                return nil
        }
 
-       dpv := reflect.ValueOf(dest)
+       return convertAssignV(reflect.ValueOf(dest), src)
+}
+
+func convertAssignV(dpv reflect.Value, src interface{}) error {
        if dpv.Kind() != reflect.Ptr {
                return errors.New("destination not a pointer")
        }
@@ -183,9 +186,7 @@ func convertAssign(dest, src interface{}) error {
                return errNilPtr
        }
 
-       if !sv.IsValid() {
-               sv = reflect.ValueOf(src)
-       }
+       var sv = reflect.ValueOf(src)
 
        dv := reflect.Indirect(dpv)
        if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
@@ -244,7 +245,7 @@ func convertAssign(dest, src interface{}) error {
                return nil
        }
 
-       return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
+       return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dpv.Interface())
 }
 
 func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
@@ -375,48 +376,3 @@ func str2PK(s string, tp reflect.Type) (interface{}, error) {
        }
        return v.Interface(), nil
 }
-
-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()
-}
index b02ec4ae29da661303ebdf43cde4075242b0e436..325836b48411cfda601f76193ef7c8c8192bb059 100644 (file)
@@ -44,6 +44,7 @@ type Dialect interface {
        URI() *URI
        SQLType(*schemas.Column) string
        FormatBytes(b []byte) string
+       Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error)
 
        IsReserved(string) bool
        Quoter() schemas.Quoter
@@ -217,7 +218,7 @@ func regDrvsNDialects() bool {
                "sqlite3":  {"sqlite3", func() Driver { return &sqlite3Driver{} }, func() Dialect { return &sqlite3{} }},
                "sqlite":   {"sqlite3", func() Driver { return &sqlite3Driver{} }, func() Dialect { return &sqlite3{} }},
                "oci8":     {"oracle", func() Driver { return &oci8Driver{} }, func() Dialect { return &oracle{} }},
-               "goracle":  {"oracle", func() Driver { return &goracleDriver{} }, func() Dialect { return &oracle{} }},
+               "godror":   {"oracle", func() Driver { return &godrorDriver{} }, func() Dialect { return &oracle{} }},
        }
 
        for driverName, v := range providedDrvsNDialects {
index 2a36a731eeabeb9e85a79014e7e84153c11884e8..bfe2e93ebcdd3b6c5063589223378bc607498a4e 100644 (file)
@@ -23,13 +23,45 @@ type SeqFilter struct {
 func convertQuestionMark(sql, prefix string, start int) string {
        var buf strings.Builder
        var beginSingleQuote bool
+       var isLineComment bool
+       var isComment bool
+       var isMaybeLineComment bool
+       var isMaybeComment bool
+       var isMaybeCommentEnd bool
        var index = start
        for _, c := range sql {
-               if !beginSingleQuote && c == '?' {
+               if !beginSingleQuote && !isLineComment && !isComment && c == '?' {
                        buf.WriteString(fmt.Sprintf("%s%v", prefix, index))
                        index++
                } else {
-                       if c == '\'' {
+                       if isMaybeLineComment {
+                               if c == '-' {
+                                       isLineComment = true
+                               }
+                               isMaybeLineComment = false
+                       } else if isMaybeComment {
+                               if c == '*' {
+                                       isComment = true
+                               }
+                               isMaybeComment = false
+                       } else if isMaybeCommentEnd {
+                               if c == '/' {
+                                       isComment = false
+                               }
+                               isMaybeCommentEnd = false
+                       } else if isLineComment {
+                               if c == '\n' {
+                                       isLineComment = false
+                               }
+                       } else if isComment {
+                               if c == '*' {
+                                       isMaybeCommentEnd = true
+                               }
+                       } else if !beginSingleQuote && c == '-' {
+                               isMaybeLineComment = true
+                       } else if !beginSingleQuote && c == '/' {
+                               isMaybeComment = true
+                       } else if c == '\'' {
                                beginSingleQuote = !beginSingleQuote
                        }
                        buf.WriteRune(c)
index 15d1cd06c019e2d23b0db27d92c9b6802a86e3e5..7e922e621e8df916fecfb5b158146f23ba2f8659 100644 (file)
@@ -253,6 +253,31 @@ func (db *mssql) SetParams(params map[string]string) {
        }
 }
 
+func (db *mssql) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) {
+       rows, err := queryer.QueryContext(ctx,
+               "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel') AS ProductLevel, SERVERPROPERTY ('edition') AS ProductEdition")
+       if err != nil {
+               return nil, err
+       }
+       defer rows.Close()
+
+       var version, level, edition string
+       if !rows.Next() {
+               return nil, errors.New("unknow version")
+       }
+
+       if err := rows.Scan(&version, &level, &edition); err != nil {
+               return nil, err
+       }
+
+       // MSSQL: Microsoft SQL Server 2017 (RTM-CU13) (KB4466404) - 14.0.3048.4 (X64) Nov 30 2018 12:57:58 Copyright (C) 2017 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 16.04.5 LTS)
+       return &schemas.Version{
+               Number:  version,
+               Level:   level,
+               Edition: edition,
+       }, nil
+}
+
 func (db *mssql) SQLType(c *schemas.Column) string {
        var res string
        switch t := c.SQLType.Name; t {
@@ -284,7 +309,7 @@ func (db *mssql) SQLType(c *schemas.Column) string {
        case schemas.TimeStampz:
                res = "DATETIMEOFFSET"
                c.Length = 7
-       case schemas.MediumInt, schemas.UnsignedInt:
+       case schemas.MediumInt:
                res = schemas.Int
        case schemas.Text, schemas.MediumText, schemas.TinyText, schemas.LongText, schemas.Json:
                res = db.defaultVarchar + "(MAX)"
@@ -296,7 +321,7 @@ func (db *mssql) SQLType(c *schemas.Column) string {
        case schemas.TinyInt:
                res = schemas.TinyInt
                c.Length = 0
-       case schemas.BigInt, schemas.UnsignedBigInt:
+       case schemas.BigInt, schemas.UnsignedBigInt, schemas.UnsignedInt:
                res = schemas.BigInt
                c.Length = 0
        case schemas.NVarchar:
index 2b530daf4b8fc84d6c31c675b916c1a5ddcbed61..a169b9010e7af08c05e53fe101041ecb64f96d4b 100644 (file)
@@ -188,6 +188,43 @@ func (db *mysql) Init(uri *URI) error {
        return db.Base.Init(db, uri)
 }
 
+func (db *mysql) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) {
+       rows, err := queryer.QueryContext(ctx, "SELECT @@VERSION")
+       if err != nil {
+               return nil, err
+       }
+       defer rows.Close()
+
+       var version string
+       if !rows.Next() {
+               return nil, errors.New("Unknow version")
+       }
+
+       if err := rows.Scan(&version); err != nil {
+               return nil, err
+       }
+
+       fields := strings.Split(version, "-")
+       if len(fields) == 3 && fields[1] == "TiDB" {
+               // 5.7.25-TiDB-v3.0.3
+               return &schemas.Version{
+                       Number:  strings.TrimPrefix(fields[2], "v"),
+                       Level:   fields[0],
+                       Edition: fields[1],
+               }, nil
+       }
+
+       var edition string
+       if len(fields) == 2 {
+               edition = fields[1]
+       }
+
+       return &schemas.Version{
+               Number:  fields[0],
+               Edition: edition,
+       }, nil
+}
+
 func (db *mysql) SetParams(params map[string]string) {
        rowFormat, ok := params["rowFormat"]
        if ok {
index 91eed25169c70c77e963f776c03d8d994d9e37e5..0b06c4c63c8c2a04d0c2ca53fc29fe4f7779e4e4 100644 (file)
@@ -515,6 +515,26 @@ func (db *oracle) Init(uri *URI) error {
        return db.Base.Init(db, uri)
 }
 
+func (db *oracle) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) {
+       rows, err := queryer.QueryContext(ctx, "select * from v$version where banner like 'Oracle%'")
+       if err != nil {
+               return nil, err
+       }
+       defer rows.Close()
+
+       var version string
+       if !rows.Next() {
+               return nil, errors.New("unknow version")
+       }
+
+       if err := rows.Scan(&version); err != nil {
+               return nil, err
+       }
+       return &schemas.Version{
+               Number: version,
+       }, nil
+}
+
 func (db *oracle) SQLType(c *schemas.Column) string {
        var res string
        switch t := c.SQLType.Name; t {
@@ -802,10 +822,10 @@ func (db *oracle) Filters() []Filter {
        }
 }
 
-type goracleDriver struct {
+type godrorDriver struct {
 }
 
-func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*URI, error) {
+func (cfg *godrorDriver) Parse(driverName, dataSourceName string) (*URI, error) {
        db := &URI{DBType: schemas.ORACLE}
        dsnPattern := regexp.MustCompile(
                `^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
index e76e5b7ed89aa3ee760d87b3f60b6d3e8081ea51..9acf763ab4c7854e7fc688279a9648948c618768 100644 (file)
@@ -788,6 +788,42 @@ func (db *postgres) Init(uri *URI) error {
        return db.Base.Init(db, uri)
 }
 
+func (db *postgres) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) {
+       rows, err := queryer.QueryContext(ctx, "SELECT version()")
+       if err != nil {
+               return nil, err
+       }
+       defer rows.Close()
+
+       var version string
+       if !rows.Next() {
+               return nil, errors.New("Unknow version")
+       }
+
+       if err := rows.Scan(&version); err != nil {
+               return nil, err
+       }
+
+       // Postgres: 9.5.22 on x86_64-pc-linux-gnu (Debian 9.5.22-1.pgdg90+1), compiled by gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516, 64-bit
+       // CockroachDB CCL v19.2.4 (x86_64-unknown-linux-gnu, built
+       if strings.HasPrefix(version, "CockroachDB") {
+               versions := strings.Split(strings.TrimPrefix(version, "CockroachDB CCL "), " ")
+               return &schemas.Version{
+                       Number:  strings.TrimPrefix(versions[0], "v"),
+                       Edition: "CockroachDB",
+               }, nil
+       } else if strings.HasPrefix(version, "PostgreSQL") {
+               versions := strings.Split(strings.TrimPrefix(version, "PostgreSQL "), " on ")
+               return &schemas.Version{
+                       Number:  versions[0],
+                       Level:   versions[1],
+                       Edition: "PostgreSQL",
+               }, nil
+       }
+
+       return nil, errors.New("unknow database version")
+}
+
 func (db *postgres) getSchema() string {
        if db.uri.Schema != "" {
                return db.uri.Schema
@@ -838,12 +874,12 @@ func (db *postgres) SQLType(c *schemas.Column) string {
        case schemas.Bit:
                res = schemas.Boolean
                return res
-       case schemas.MediumInt, schemas.Int, schemas.Integer, schemas.UnsignedInt:
+       case schemas.MediumInt, schemas.Int, schemas.Integer:
                if c.IsAutoIncrement {
                        return schemas.Serial
                }
                return schemas.Integer
-       case schemas.BigInt, schemas.UnsignedBigInt:
+       case schemas.BigInt, schemas.UnsignedBigInt, schemas.UnsignedInt:
                if c.IsAutoIncrement {
                        return schemas.BigSerial
                }
@@ -1008,12 +1044,13 @@ func (db *postgres) IsColumnExist(queryer core.Queryer, ctx context.Context, tab
 
 func (db *postgres) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
        args := []interface{}{tableName}
-       s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length,
+       s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, description,
     CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
     CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
 FROM pg_attribute f
     JOIN pg_class c ON c.oid = f.attrelid JOIN pg_type t ON t.oid = f.atttypid
     LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
+    LEFT JOIN pg_description de ON f.attrelid=de.objoid AND f.attnum=de.objsubid
     LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
     LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
     LEFT JOIN pg_class AS g ON p.confrelid = g.oid
@@ -1042,9 +1079,9 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
                col.Indexes = make(map[string]int)
 
                var colName, isNullable, dataType string
-               var maxLenStr, colDefault *string
+               var maxLenStr, colDefault, description *string
                var isPK, isUnique bool
-               err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &isPK, &isUnique)
+               err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &description, &isPK, &isUnique)
                if err != nil {
                        return nil, nil, err
                }
@@ -1090,6 +1127,10 @@ WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s A
                        col.DefaultIsEmpty = true
                }
 
+               if description != nil {
+                       col.Comment = *description
+               }
+
                if isPK {
                        col.IsPrimaryKey = true
                }
@@ -1221,7 +1262,8 @@ func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableN
                        continue
                }
                indexName = strings.Trim(indexName, `" `)
-               if strings.HasSuffix(indexName, "_pkey") {
+               // ignore primary index
+               if strings.HasSuffix(indexName, "_pkey") || strings.EqualFold(indexName, "primary") {
                        continue
                }
                if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
@@ -1241,7 +1283,9 @@ func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableN
 
                index := &schemas.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
                for _, colName := range colNames {
-                       index.Cols = append(index.Cols, strings.TrimSpace(strings.Replace(colName, `"`, "", -1)))
+                       col := strings.TrimSpace(strings.Replace(colName, `"`, "", -1))
+                       fields := strings.Split(col, " ")
+                       index.Cols = append(index.Cols, fields[0])
                }
                index.IsRegular = isRegular
                indexes[index.Name] = index
index 8268360645a0d5cbd9d9f542129e75bfe8cc2d2b..a42aad48677fec36441331a8429d8dfd0afd8294 100644 (file)
@@ -160,6 +160,27 @@ func (db *sqlite3) Init(uri *URI) error {
        return db.Base.Init(db, uri)
 }
 
+func (db *sqlite3) Version(ctx context.Context, queryer core.Queryer) (*schemas.Version, error) {
+       rows, err := queryer.QueryContext(ctx, "SELECT sqlite_version()")
+       if err != nil {
+               return nil, err
+       }
+       defer rows.Close()
+
+       var version string
+       if !rows.Next() {
+               return nil, errors.New("Unknow version")
+       }
+
+       if err := rows.Scan(&version); err != nil {
+               return nil, err
+       }
+       return &schemas.Version{
+               Number:  version,
+               Edition: "sqlite",
+       }, nil
+}
+
 func (db *sqlite3) SetQuotePolicy(quotePolicy QuotePolicy) {
        switch quotePolicy {
        case QuotePolicyNone:
index d49eea9adc8f8075ee9e03de86e57ac1a5e720fc..0eb429b148bf8b9c9b1f0dc9bc1e7f2b41c6d0e5 100644 (file)
@@ -444,7 +444,7 @@ func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
        return engine.dumpTables(tables, w, tp...)
 }
 
-func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.Column) string {
+func formatColumnValue(dbLocation *time.Location, dstDialect dialects.Dialect, d interface{}, col *schemas.Column) string {
        if d == nil {
                return "NULL"
        }
@@ -473,10 +473,8 @@ func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.
 
                return "'" + strings.Replace(v, "'", "''", -1) + "'"
        } else if col.SQLType.IsTime() {
-               if dstDialect.URI().DBType == schemas.MSSQL && col.SQLType.Name == schemas.DateTime {
-                       if t, ok := d.(time.Time); ok {
-                               return "'" + t.UTC().Format("2006-01-02 15:04:05") + "'"
-                       }
+               if t, ok := d.(time.Time); ok {
+                       return "'" + t.In(dbLocation).Format("2006-01-02 15:04:05") + "'"
                }
                var v = fmt.Sprintf("%s", d)
                if strings.HasSuffix(v, " +0000 UTC") {
@@ -652,12 +650,8 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
                                                return errors.New("unknown column error")
                                        }
 
-                                       fields := strings.Split(col.FieldName, ".")
-                                       field := dataStruct
-                                       for _, fieldName := range fields {
-                                               field = field.FieldByName(fieldName)
-                                       }
-                                       temp += "," + formatColumnValue(dstDialect, field.Interface(), col)
+                                       field := dataStruct.FieldByIndex(col.FieldIndex)
+                                       temp += "," + formatColumnValue(engine.DatabaseTZ, dstDialect, field.Interface(), col)
                                }
                                _, err = io.WriteString(w, temp[1:]+");\n")
                                if err != nil {
@@ -684,7 +678,7 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
                                                return errors.New("unknow column error")
                                        }
 
-                                       temp += "," + formatColumnValue(dstDialect, d, col)
+                                       temp += "," + formatColumnValue(engine.DatabaseTZ, dstDialect, d, col)
                                }
                                _, err = io.WriteString(w, temp[1:]+");\n")
                                if err != nil {
@@ -925,15 +919,9 @@ func (engine *Engine) Having(conditions string) *Session {
        return session.Having(conditions)
 }
 
-// Table table struct
-type Table struct {
-       *schemas.Table
-       Name string
-}
-
-// IsValid if table is valid
-func (t *Table) IsValid() bool {
-       return t.Table != nil && len(t.Name) > 0
+// DBVersion returns the database version
+func (engine *Engine) DBVersion() (*schemas.Version, error) {
+       return engine.dialect.Version(engine.defaultContext, engine.db)
 }
 
 // TableInfo get table info according to bean's content
index 5e07320747b3f8e087896d934e48f6f60866bcff..f6e4af90839345eddeea2d282224f9c0d86327e5 100644 (file)
@@ -5,6 +5,7 @@ go 1.13
 require (
        github.com/denisenkom/go-mssqldb v0.9.0
        github.com/go-sql-driver/mysql v1.5.0
+       github.com/json-iterator/go v1.1.11
        github.com/lib/pq v1.7.0
        github.com/mattn/go-sqlite3 v1.14.6
        github.com/stretchr/testify v1.4.0
index 230c16aad7e88677011bb2d7ea0c7e2273b7c1cf..3c79850cc6cf598ef805008f78f9d2672e920f74 100644 (file)
@@ -1,7 +1,8 @@
 gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
 gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
 github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
@@ -18,8 +19,11 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
 github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
@@ -28,6 +32,10 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
 github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
 github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
index 55162c8c4e009d84ac6a282a2432174a87b96e69..d31323ffd757b66a5b68cef6c97d26781f70bc06 100644 (file)
@@ -83,6 +83,7 @@ type EngineInterface interface {
        Context(context.Context) *Session
        CreateTables(...interface{}) error
        DBMetas() ([]*schemas.Table, error)
+       DBVersion() (*schemas.Version, error)
        Dialect() dialects.Dialect
        DriverName() string
        DropTables(...interface{}) error
diff --git a/vendor/xorm.io/xorm/internal/json/jsoniter.go b/vendor/xorm.io/xorm/internal/json/jsoniter.go
new file mode 100644 (file)
index 0000000..cfe7a19
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2021 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 jsoniter
+
+package json
+
+import (
+       jsoniter "github.com/json-iterator/go"
+)
+
+func init() {
+       DefaultJSONHandler = JSONiter{}
+}
+
+// JSONiter implements JSONInterface via jsoniter
+type JSONiter struct{}
+
+// Marshal implements JSONInterface
+func (JSONiter) Marshal(v interface{}) ([]byte, error) {
+       return jsoniter.Marshal(v)
+}
+
+// Unmarshal implements JSONInterface
+func (JSONiter) Unmarshal(data []byte, v interface{}) error {
+       return jsoniter.Unmarshal(data, v)
+}
diff --git a/vendor/xorm.io/xorm/internal/statements/expr.go b/vendor/xorm.io/xorm/internal/statements/expr.go
new file mode 100644 (file)
index 0000000..c2a2e1c
--- /dev/null
@@ -0,0 +1,94 @@
+// 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 statements
+
+import (
+       "fmt"
+       "strings"
+
+       "xorm.io/builder"
+       "xorm.io/xorm/schemas"
+)
+
+// ErrUnsupportedExprType represents an error with unsupported express type
+type ErrUnsupportedExprType struct {
+       tp string
+}
+
+func (err ErrUnsupportedExprType) Error() string {
+       return fmt.Sprintf("Unsupported expression type: %v", err.tp)
+}
+
+// Expr represents an SQL express
+type Expr struct {
+       ColName string
+       Arg     interface{}
+}
+
+// WriteArgs writes args to the writer
+func (expr *Expr) WriteArgs(w *builder.BytesWriter) error {
+       switch arg := expr.Arg.(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
+               }
+       case string:
+               if arg == "" {
+                       arg = "''"
+               }
+               if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil {
+                       return err
+               }
+       default:
+               if _, err := w.WriteString("?"); err != nil {
+                       return err
+               }
+               w.Append(arg)
+       }
+       return nil
+}
+
+type exprParams []Expr
+
+func (exprs exprParams) ColNames() []string {
+       var cols = make([]string, 0, len(exprs))
+       for _, expr := range exprs {
+               cols = append(cols, expr.ColName)
+       }
+       return cols
+}
+
+func (exprs *exprParams) Add(name string, arg interface{}) {
+       *exprs = append(*exprs, Expr{name, arg})
+}
+
+func (exprs exprParams) IsColExist(colName string) bool {
+       for _, expr := range exprs {
+               if strings.EqualFold(schemas.CommonQuoter.Trim(expr.ColName), schemas.CommonQuoter.Trim(colName)) {
+                       return true
+               }
+       }
+       return false
+}
+
+func (exprs exprParams) WriteArgs(w *builder.BytesWriter) error {
+       for i, expr := range exprs {
+               if err := expr.WriteArgs(w); err != nil {
+                       return err
+               }
+               if i != len(exprs)-1 {
+                       if _, err := w.WriteString(","); err != nil {
+                               return err
+                       }
+               }
+       }
+       return nil
+}
diff --git a/vendor/xorm.io/xorm/internal/statements/expr_param.go b/vendor/xorm.io/xorm/internal/statements/expr_param.go
deleted file mode 100644 (file)
index d0c355d..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-// 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 statements
-
-import (
-       "fmt"
-       "strings"
-
-       "xorm.io/builder"
-       "xorm.io/xorm/schemas"
-)
-
-// ErrUnsupportedExprType represents an error with unsupported express type
-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(schemas.CommonQuoter.Trim(name), schemas.CommonQuoter.Trim(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
-                       }
-               case string:
-                       if arg == "" {
-                               arg = "''"
-                       }
-                       if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil {
-                               return err
-                       }
-               default:
-                       if _, err := w.WriteString("?"); err != nil {
-                               return err
-                       }
-                       w.Append(arg)
-               }
-               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
-}
index 6cbbbedaad3680c05a80c9a07be964cdf7b4fa61..4e43c5bd36e6b61ba57551edbc57999b3924c838 100644 (file)
@@ -17,7 +17,7 @@ func (statement *Statement) writeInsertOutput(buf *strings.Builder, table *schem
                if _, err := buf.WriteString(" OUTPUT Inserted."); err != nil {
                        return err
                }
-               if _, err := buf.WriteString(table.AutoIncrement); err != nil {
+               if err := statement.dialect.Quoter().QuoteTo(buf, table.AutoIncrement); err != nil {
                        return err
                }
        }
@@ -59,7 +59,7 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
                        return "", nil, err
                }
 
-               if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames...), ","); err != nil {
+               if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames()...), ","); err != nil {
                        return "", nil, err
                }
 
@@ -79,7 +79,7 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
                                return "", nil, err
                        }
 
-                       if len(exprs.Args) > 0 {
+                       if len(exprs) > 0 {
                                if _, err := buf.WriteString(","); err != nil {
                                        return "", nil, err
                                }
@@ -112,7 +112,7 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{})
                                return "", nil, err
                        }
 
-                       if len(exprs.Args) > 0 {
+                       if len(exprs) > 0 {
                                if _, err := buf.WriteString(","); err != nil {
                                        return "", nil, err
                                }
@@ -152,7 +152,7 @@ func (statement *Statement) GenInsertMapSQL(columns []string, args []interface{}
                return "", nil, err
        }
 
-       if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(columns, exprs.ColNames...), ","); err != nil {
+       if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(columns, exprs.ColNames()...), ","); err != nil {
                return "", nil, err
        }
 
@@ -166,7 +166,7 @@ func (statement *Statement) GenInsertMapSQL(columns []string, args []interface{}
                        return "", nil, err
                }
 
-               if len(exprs.Args) > 0 {
+               if len(exprs) > 0 {
                        if _, err := buf.WriteString(","); err != nil {
                                return "", nil, err
                        }
@@ -190,7 +190,7 @@ func (statement *Statement) GenInsertMapSQL(columns []string, args []interface{}
                        return "", nil, err
                }
 
-               if len(exprs.Args) > 0 {
+               if len(exprs) > 0 {
                        if _, err := buf.WriteString(","); err != nil {
                                return "", nil, err
                        }
index f1b3677009563fd92fc3c4d58e9e308b9dec59f5..a972a8e07742964d6244b8e8538add49f33d86d0 100644 (file)
@@ -106,10 +106,13 @@ func (statement *Statement) GenSumSQL(bean interface{}, columns ...string) (stri
 
 // GenGetSQL generates Get SQL
 func (statement *Statement) GenGetSQL(bean interface{}) (string, []interface{}, error) {
-       v := rValue(bean)
-       isStruct := v.Kind() == reflect.Struct
-       if isStruct {
-               statement.SetRefBean(bean)
+       var isStruct bool
+       if bean != nil {
+               v := rValue(bean)
+               isStruct = v.Kind() == reflect.Struct
+               if isStruct {
+                       statement.SetRefBean(bean)
+               }
        }
 
        var columnStr = statement.ColumnStr()
@@ -181,11 +184,22 @@ func (statement *Statement) GenCountSQL(beans ...interface{}) (string, []interfa
                        selectSQL = "count(*)"
                }
        }
-       sqlStr, condArgs, err := statement.genSelectSQL(selectSQL, false, false)
+       var subQuerySelect string
+       if statement.GroupByStr != "" {
+               subQuerySelect = statement.GroupByStr
+       } else {
+               subQuerySelect = selectSQL
+       }
+
+       sqlStr, condArgs, err := statement.genSelectSQL(subQuerySelect, false, false)
        if err != nil {
                return "", nil, err
        }
 
+       if statement.GroupByStr != "" {
+               sqlStr = fmt.Sprintf("SELECT %s FROM (%s) sub", selectSQL, sqlStr)
+       }
+
        return sqlStr, append(statement.joinArgs, condArgs...), nil
 }
 
@@ -329,12 +343,25 @@ func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interfac
        var args []interface{}
        var joinStr string
        var err error
-       if len(bean) == 0 {
-               tableName := statement.TableName()
-               if len(tableName) <= 0 {
-                       return "", nil, ErrTableNotFound
+       var b interface{}
+       if len(bean) > 0 {
+               b = bean[0]
+               beanValue := reflect.ValueOf(bean[0])
+               if beanValue.Kind() != reflect.Ptr {
+                       return "", nil, errors.New("needs a pointer")
                }
 
+               if beanValue.Elem().Kind() == reflect.Struct {
+                       if err := statement.SetRefBean(bean[0]); err != nil {
+                               return "", nil, err
+                       }
+               }
+       }
+       tableName := statement.TableName()
+       if len(tableName) <= 0 {
+               return "", nil, ErrTableNotFound
+       }
+       if statement.RefTable == nil {
                tableName = statement.quote(tableName)
                if len(statement.JoinStr) > 0 {
                        joinStr = statement.JoinStr
@@ -365,22 +392,8 @@ func (statement *Statement) GenExistSQL(bean ...interface{}) (string, []interfac
                        args = []interface{}{}
                }
        } else {
-               beanValue := reflect.ValueOf(bean[0])
-               if beanValue.Kind() != reflect.Ptr {
-                       return "", nil, errors.New("needs a pointer")
-               }
-
-               if beanValue.Elem().Kind() == reflect.Struct {
-                       if err := statement.SetRefBean(bean[0]); err != nil {
-                               return "", nil, err
-                       }
-               }
-
-               if len(statement.TableName()) <= 0 {
-                       return "", nil, ErrTableNotFound
-               }
                statement.Limit(1)
-               sqlStr, args, err = statement.GenGetSQL(bean[0])
+               sqlStr, args, err = statement.GenGetSQL(b)
                if err != nil {
                        return "", nil, err
                }
index 3dd036a6cd44739d76357455efbf3b3db62a25ea..2d173b876b7f7009db6ffb8bb71728f54c754ebe 100644 (file)
@@ -208,20 +208,18 @@ func (statement *Statement) quote(s string) string {
 
 // And add Where & and statement
 func (statement *Statement) And(query interface{}, args ...interface{}) *Statement {
-       switch query.(type) {
+       switch qr := query.(type) {
        case string:
-               cond := builder.Expr(query.(string), args...)
+               cond := builder.Expr(qr, args...)
                statement.cond = statement.cond.And(cond)
        case map[string]interface{}:
-               queryMap := query.(map[string]interface{})
-               newMap := make(map[string]interface{})
-               for k, v := range queryMap {
-                       newMap[statement.quote(k)] = v
+               cond := make(builder.Eq)
+               for k, v := range qr {
+                       cond[statement.quote(k)] = v
                }
-               statement.cond = statement.cond.And(builder.Eq(newMap))
-       case builder.Cond:
-               cond := query.(builder.Cond)
                statement.cond = statement.cond.And(cond)
+       case builder.Cond:
+               statement.cond = statement.cond.And(qr)
                for _, v := range args {
                        if vv, ok := v.(builder.Cond); ok {
                                statement.cond = statement.cond.And(vv)
@@ -236,23 +234,25 @@ func (statement *Statement) And(query interface{}, args ...interface{}) *Stateme
 
 // Or add Where & Or statement
 func (statement *Statement) Or(query interface{}, args ...interface{}) *Statement {
-       switch query.(type) {
+       switch qr := query.(type) {
        case string:
-               cond := builder.Expr(query.(string), args...)
+               cond := builder.Expr(qr, args...)
                statement.cond = statement.cond.Or(cond)
        case map[string]interface{}:
-               cond := builder.Eq(query.(map[string]interface{}))
+               cond := make(builder.Eq)
+               for k, v := range qr {
+                       cond[statement.quote(k)] = v
+               }
                statement.cond = statement.cond.Or(cond)
        case builder.Cond:
-               cond := query.(builder.Cond)
-               statement.cond = statement.cond.Or(cond)
+               statement.cond = statement.cond.Or(qr)
                for _, v := range args {
                        if vv, ok := v.(builder.Cond); ok {
                                statement.cond = statement.cond.Or(vv)
                        }
                }
        default:
-               // TODO: not support condition type
+               statement.LastError = ErrConditionType
        }
        return statement
 }
@@ -324,9 +324,9 @@ func (statement *Statement) TableName() string {
 // Incr Generate  "Update ... Set column = column + arg" statement
 func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
        if len(arg) > 0 {
-               statement.IncrColumns.addParam(column, arg[0])
+               statement.IncrColumns.Add(column, arg[0])
        } else {
-               statement.IncrColumns.addParam(column, 1)
+               statement.IncrColumns.Add(column, 1)
        }
        return statement
 }
@@ -334,9 +334,9 @@ func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
 // Decr Generate  "Update ... Set column = column - arg" statement
 func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
        if len(arg) > 0 {
-               statement.DecrColumns.addParam(column, arg[0])
+               statement.DecrColumns.Add(column, arg[0])
        } else {
-               statement.DecrColumns.addParam(column, 1)
+               statement.DecrColumns.Add(column, 1)
        }
        return statement
 }
@@ -344,9 +344,9 @@ func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
 // SetExpr Generate  "Update ... Set column = {expression}" statement
 func (statement *Statement) SetExpr(column string, expression interface{}) *Statement {
        if e, ok := expression.(string); ok {
-               statement.ExprColumns.addParam(column, statement.dialect.Quoter().Replace(e))
+               statement.ExprColumns.Add(column, statement.dialect.Quoter().Replace(e))
        } else {
-               statement.ExprColumns.addParam(column, expression)
+               statement.ExprColumns.Add(column, expression)
        }
        return statement
 }
@@ -734,6 +734,8 @@ func (statement *Statement) buildConds2(table *schemas.Table, bean interface{},
                                //engine.logger.Warn(err)
                        }
                        continue
+               } else if fieldValuePtr == nil {
+                       continue
                }
 
                if col.IsDeleted && !unscoped { // tag "deleted" is enabled
@@ -976,7 +978,7 @@ func (statement *Statement) joinColumns(cols []*schemas.Column, includeTableName
 
 // CondDeleted returns the conditions whether a record is soft deleted.
 func (statement *Statement) CondDeleted(col *schemas.Column) builder.Cond {
-       var colName = col.Name
+       var colName = statement.quote(col.Name)
        if statement.JoinStr != "" {
                var prefix string
                if statement.TableAlias != "" {
index 251880b23006d65fdddeafe571989b9e098f0680..06cf0689295810308739f51b1e9cab3565bd86bf 100644 (file)
@@ -88,6 +88,9 @@ func (statement *Statement) BuildUpdates(tableValue reflect.Value,
                if err != nil {
                        return nil, nil, err
                }
+               if fieldValuePtr == nil {
+                       continue
+               }
 
                fieldValue := *fieldValuePtr
                fieldType := reflect.TypeOf(fieldValue.Interface())
index eeb63693b2ba9b3139bcffd4558b2859214fd2a6..3b6db34e95bcffb2fda089a88953b8d798c140bd 100644 (file)
@@ -132,7 +132,6 @@ func (s *SimpleLogger) Error(v ...interface{}) {
        if s.level <= LOG_ERR {
                s.ERR.Output(2, fmt.Sprintln(v...))
        }
-       return
 }
 
 // Errorf implement ILogger
@@ -140,7 +139,6 @@ func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
        if s.level <= LOG_ERR {
                s.ERR.Output(2, fmt.Sprintf(format, v...))
        }
-       return
 }
 
 // Debug implement ILogger
@@ -148,7 +146,6 @@ func (s *SimpleLogger) Debug(v ...interface{}) {
        if s.level <= LOG_DEBUG {
                s.DEBUG.Output(2, fmt.Sprintln(v...))
        }
-       return
 }
 
 // Debugf implement ILogger
@@ -156,7 +153,6 @@ func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
        if s.level <= LOG_DEBUG {
                s.DEBUG.Output(2, fmt.Sprintf(format, v...))
        }
-       return
 }
 
 // Info implement ILogger
@@ -164,7 +160,6 @@ func (s *SimpleLogger) Info(v ...interface{}) {
        if s.level <= LOG_INFO {
                s.INFO.Output(2, fmt.Sprintln(v...))
        }
-       return
 }
 
 // Infof implement ILogger
@@ -172,7 +167,6 @@ func (s *SimpleLogger) Infof(format string, v ...interface{}) {
        if s.level <= LOG_INFO {
                s.INFO.Output(2, fmt.Sprintf(format, v...))
        }
-       return
 }
 
 // Warn implement ILogger
@@ -180,7 +174,6 @@ func (s *SimpleLogger) Warn(v ...interface{}) {
        if s.level <= LOG_WARNING {
                s.WARN.Output(2, fmt.Sprintln(v...))
        }
-       return
 }
 
 // Warnf implement ILogger
@@ -188,7 +181,6 @@ func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
        if s.level <= LOG_WARNING {
                s.WARN.Output(2, fmt.Sprintf(format, v...))
        }
-       return
 }
 
 // Level implement ILogger
@@ -199,7 +191,6 @@ func (s *SimpleLogger) Level() LogLevel {
 // SetLevel implement ILogger
 func (s *SimpleLogger) SetLevel(l LogLevel) {
        s.level = l
-       return
 }
 
 // ShowSQL implement ILogger
diff --git a/vendor/xorm.io/xorm/scan.go b/vendor/xorm.io/xorm/scan.go
new file mode 100644 (file)
index 0000000..e19037a
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright 2021 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"
+
+       "xorm.io/xorm/core"
+)
+
+func (engine *Engine) row2mapStr(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string]string, error) {
+       var scanResults = make([]interface{}, len(fields))
+       for i := 0; i < len(fields); i++ {
+               var s sql.NullString
+               scanResults[i] = &s
+       }
+
+       if err := rows.Scan(scanResults...); err != nil {
+               return nil, err
+       }
+
+       result := make(map[string]string, len(fields))
+       for ii, key := range fields {
+               s := scanResults[ii].(*sql.NullString)
+               result[key] = s.String
+       }
+       return result, nil
+}
+
+func (engine *Engine) row2mapBytes(rows *core.Rows, types []*sql.ColumnType, fields []string) (map[string][]byte, error) {
+       var scanResults = make([]interface{}, len(fields))
+       for i := 0; i < len(fields); i++ {
+               var s sql.NullString
+               scanResults[i] = &s
+       }
+
+       if err := rows.Scan(scanResults...); err != nil {
+               return nil, err
+       }
+
+       result := make(map[string][]byte, len(fields))
+       for ii, key := range fields {
+               s := scanResults[ii].(*sql.NullString)
+               result[key] = []byte(s.String)
+       }
+       return result, nil
+}
+
+func (engine *Engine) row2sliceStr(rows *core.Rows, types []*sql.ColumnType, fields []string) ([]string, error) {
+       results := make([]string, 0, len(fields))
+       var scanResults = make([]interface{}, len(fields))
+       for i := 0; i < len(fields); i++ {
+               var s sql.NullString
+               scanResults[i] = &s
+       }
+
+       if err := rows.Scan(scanResults...); err != nil {
+               return nil, err
+       }
+
+       for i := 0; i < len(fields); i++ {
+               results = append(results, scanResults[i].(*sql.NullString).String)
+       }
+       return results, nil
+}
index 5808b84d2b68fd36f55ba056b8b9fc33d49bf34c..4bbb6c2db4c5fb6d4cc63786ee54e3d46d694c59 100644 (file)
@@ -6,10 +6,8 @@ package schemas
 
 import (
        "errors"
-       "fmt"
        "reflect"
        "strconv"
-       "strings"
        "time"
 )
 
@@ -24,7 +22,8 @@ const (
 type Column struct {
        Name            string
        TableName       string
-       FieldName       string // Avaiable only when parsed from a struct
+       FieldName       string // Available only when parsed from a struct
+       FieldIndex      []int  // Available only when parsed from a struct
        SQLType         SQLType
        IsJSON          bool
        Length          int
@@ -83,41 +82,17 @@ func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
 
 // ValueOfV returns column's filed of struct's value accept reflevt value
 func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
-       var fieldValue reflect.Value
-       fieldPath := strings.Split(col.FieldName, ".")
-
-       if dataStruct.Type().Kind() == reflect.Map {
-               keyValue := reflect.ValueOf(fieldPath[len(fieldPath)-1])
-               fieldValue = dataStruct.MapIndex(keyValue)
-               return &fieldValue, nil
-       } else if dataStruct.Type().Kind() == reflect.Interface {
-               structValue := reflect.ValueOf(dataStruct.Interface())
-               dataStruct = &structValue
-       }
-
-       level := len(fieldPath)
-       fieldValue = dataStruct.FieldByName(fieldPath[0])
-       for i := 0; i < level-1; i++ {
-               if !fieldValue.IsValid() {
-                       break
-               }
-               if fieldValue.Kind() == reflect.Struct {
-                       fieldValue = fieldValue.FieldByName(fieldPath[i+1])
-               } else if fieldValue.Kind() == reflect.Ptr {
-                       if fieldValue.IsNil() {
-                               fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+       var v = *dataStruct
+       for _, i := range col.FieldIndex {
+               if v.Kind() == reflect.Ptr {
+                       if v.IsNil() {
+                               v.Set(reflect.New(v.Type().Elem()))
                        }
-                       fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1])
-               } else {
-                       return nil, fmt.Errorf("field %v is not valid", col.FieldName)
+                       v = v.Elem()
                }
+               v = v.FieldByIndex([]int{i})
        }
-
-       if !fieldValue.IsValid() {
-               return nil, fmt.Errorf("field %v is not valid", col.FieldName)
-       }
-
-       return &fieldValue, nil
+       return &v, nil
 }
 
 // ConvertID converts id content to suitable type according column type
index bfa517aa2f7f0bc8d71f7c4fd640cad9c8d4949d..91b33e0621dec5fda226e9d0330a42715c22329c 100644 (file)
@@ -5,7 +5,6 @@
 package schemas
 
 import (
-       "fmt"
        "reflect"
        "strconv"
        "strings"
@@ -159,24 +158,8 @@ func (table *Table) IDOfV(rv reflect.Value) (PK, error) {
        for i, col := range table.PKColumns() {
                var err error
 
-               fieldName := col.FieldName
-               for {
-                       parts := strings.SplitN(fieldName, ".", 2)
-                       if len(parts) == 1 {
-                               break
-                       }
-
-                       v = v.FieldByName(parts[0])
-                       if v.Kind() == reflect.Ptr {
-                               v = v.Elem()
-                       }
-                       if v.Kind() != reflect.Struct {
-                               return nil, fmt.Errorf("Unsupported read value of column %s from field %s", col.Name, col.FieldName)
-                       }
-                       fieldName = parts[1]
-               }
+               pkField := v.FieldByIndex(col.FieldIndex)
 
-               pkField := v.FieldByName(fieldName)
                switch pkField.Kind() {
                case reflect.String:
                        pk[i], err = col.ConvertID(pkField.String())
diff --git a/vendor/xorm.io/xorm/schemas/version.go b/vendor/xorm.io/xorm/schemas/version.go
new file mode 100644 (file)
index 0000000..ba78967
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2021 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 schemas
+
+// Version represents a database version
+type Version struct {
+       Number  string // the version number which could be compared
+       Level   string
+       Edition string
+}
index d5ccb6dc3df896fb55bc1e40883315485e412ead..6df9e20d875d1ed5db5220f6ec84a2539211b5f8 100644 (file)
@@ -375,6 +375,9 @@ func (session *Session) getField(dataStruct *reflect.Value, key string, table *s
        if err != nil {
                return nil, err
        }
+       if fieldValue == nil {
+               return nil, ErrFieldIsNotValid{key, table.Name}
+       }
 
        if !fieldValue.IsValid() || !fieldValue.CanSet() {
                return nil, ErrFieldIsNotValid{key, table.Name}
index a6839947318e380faede3994b585b6040e4c4a1a..b8218a7749c8e4f3c16ac8cfc94563c47db3068a 100644 (file)
@@ -35,27 +35,20 @@ func (session *Session) str2Time(col *schemas.Column, data string) (outTime time
                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)
+               session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.Name, 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 == schemas.Time {
                if strings.Contains(sdata, " ") {
                        ssd := strings.Split(sdata, " ")
@@ -69,7 +62,6 @@ func (session *Session) str2Time(col *schemas.Column, data string) (outTime time
 
                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
index 5f9681512edae5261b8f7d91197ebb4ff6b38a95..e733e06e06437f03ad552089b34bdcee328921b1 100644 (file)
@@ -11,6 +11,7 @@ import (
        "sort"
        "strconv"
        "strings"
+       "time"
 
        "xorm.io/xorm/internal/utils"
        "xorm.io/xorm/schemas"
@@ -374,9 +375,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
                        return 1, nil
                }
 
-               aiValue.Set(int64ToIntValue(id, aiValue.Type()))
-
-               return 1, nil
+               return 1, convertAssignV(aiValue.Addr(), id)
        } else if len(table.AutoIncrement) > 0 && (session.engine.dialect.URI().DBType == schemas.POSTGRES ||
                session.engine.dialect.URI().DBType == schemas.MSSQL) {
                res, err := session.queryBytes(sqlStr, args...)
@@ -416,9 +415,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
                        return 1, nil
                }
 
-               aiValue.Set(int64ToIntValue(id, aiValue.Type()))
-
-               return 1, nil
+               return 1, convertAssignV(aiValue.Addr(), id)
        }
 
        res, err := session.exec(sqlStr, args...)
@@ -458,7 +455,9 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
                return res.RowsAffected()
        }
 
-       aiValue.Set(int64ToIntValue(id, aiValue.Type()))
+       if err := convertAssignV(aiValue.Addr(), id); err != nil {
+               return 0, err
+       }
 
        return res.RowsAffected()
 }
@@ -499,6 +498,16 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac
                }
 
                if col.IsDeleted {
+                       colNames = append(colNames, col.Name)
+                       if !col.Nullable {
+                               if col.SQLType.IsNumeric() {
+                                       args = append(args, 0)
+                               } else {
+                                       args = append(args, time.Time{}.Format("2006-01-02 15:04:05"))
+                               }
+                       } else {
+                               args = append(args, nil)
+                       }
                        continue
                }
 
index 121364661138be7e658eb4aa43c29727046eda0a..379ad0e1c2d4178a1ec10a6e59fff0896e1343d5 100644 (file)
@@ -75,69 +75,18 @@ func value2String(rawValue *reflect.Value) (str string, err error) {
        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 {
+func (session *Session) rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) {
+       fields, err := rows.Columns()
+       if 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()
+       types, err := rows.ColumnTypes()
        if err != nil {
                return nil, err
        }
+
        for rows.Next() {
-               result, err := row2mapStr(rows, fields)
+               result, err := session.engine.row2mapStr(rows, types, fields)
                if err != nil {
                        return nil, err
                }
@@ -147,13 +96,18 @@ func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error)
        return resultsSlice, nil
 }
 
-func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
+func (session *Session) rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) {
        fields, err := rows.Columns()
        if err != nil {
                return nil, err
        }
+       types, err := rows.ColumnTypes()
+       if err != nil {
+               return nil, err
+       }
+
        for rows.Next() {
-               record, err := row2sliceStr(rows, fields)
+               record, err := session.engine.row2sliceStr(rows, types, fields)
                if err != nil {
                        return nil, err
                }
@@ -180,7 +134,7 @@ func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]stri
        }
        defer rows.Close()
 
-       return rows2Strings(rows)
+       return session.rows2Strings(rows)
 }
 
 // QuerySliceString runs a raw sql and return records as [][]string
@@ -200,7 +154,7 @@ func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string,
        }
        defer rows.Close()
 
-       return rows2SliceString(rows)
+       return session.rows2SliceString(rows)
 }
 
 func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) {
index 4cfe297abec52c5d373cb92adf2443dd2777caff..d5c4520b97eb4f6ad5cf4449e2b20f2c197bb94d 100644 (file)
@@ -79,41 +79,17 @@ func value2Bytes(rawValue *reflect.Value) ([]byte, error) {
        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 {
+func (session *Session) rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
+       fields, err := rows.Columns()
+       if 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()
+       types, err := rows.ColumnTypes()
        if err != nil {
                return nil, err
        }
        for rows.Next() {
-               result, err := row2map(rows, fields)
+               result, err := session.engine.row2mapBytes(rows, types, fields)
                if err != nil {
                        return nil, err
                }
@@ -130,7 +106,7 @@ func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[st
        }
        defer rows.Close()
 
-       return rows2maps(rows)
+       return session.rows2maps(rows)
 }
 
 func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
index 0adac25e4381284b6ac6a063f91e79dee48c22f3..78907e431d25602a5fea64a7d83e17876365c95d 100644 (file)
@@ -17,6 +17,11 @@ import (
        "xorm.io/xorm/schemas"
 )
 
+// enumerated all errors
+var (
+       ErrNoColumnsTobeUpdated = errors.New("no columns found to be updated")
+)
+
 func (session *Session) cacheUpdate(table *schemas.Table, tableName, sqlStr string, args ...interface{}) error {
        if table == nil ||
                session.tx != nil {
@@ -144,6 +149,8 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
                defer session.Close()
        }
 
+       defer session.resetStatement()
+
        if session.statement.LastError != nil {
                return 0, session.statement.LastError
        }
@@ -224,35 +231,35 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
 
        // 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 _, expr := range incColumns {
+               colNames = append(colNames, session.engine.Quote(expr.ColName)+" = "+session.engine.Quote(expr.ColName)+" + ?")
+               args = append(args, expr.Arg)
        }
        // 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 _, expr := range decColumns {
+               colNames = append(colNames, session.engine.Quote(expr.ColName)+" = "+session.engine.Quote(expr.ColName)+" - ?")
+               args = append(args, expr.Arg)
        }
        // for update action to like "column = expression"
        exprColumns := session.statement.ExprColumns
-       for i, colName := range exprColumns.ColNames {
-               switch tp := exprColumns.Args[i].(type) {
+       for _, expr := range exprColumns {
+               switch tp := expr.Arg.(type) {
                case string:
                        if len(tp) == 0 {
                                tp = "''"
                        }
-                       colNames = append(colNames, session.engine.Quote(colName)+"="+tp)
+                       colNames = append(colNames, session.engine.Quote(expr.ColName)+"="+tp)
                case *builder.Builder:
                        subQuery, subArgs, err := session.statement.GenCondSQL(tp)
                        if err != nil {
                                return 0, err
                        }
-                       colNames = append(colNames, session.engine.Quote(colName)+"=("+subQuery+")")
+                       colNames = append(colNames, session.engine.Quote(expr.ColName)+"=("+subQuery+")")
                        args = append(args, subArgs...)
                default:
-                       colNames = append(colNames, session.engine.Quote(colName)+"=?")
-                       args = append(args, exprColumns.Args[i])
+                       colNames = append(colNames, session.engine.Quote(expr.ColName)+"=?")
+                       args = append(args, expr.Arg)
                }
        }
 
@@ -273,15 +280,12 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
                                        k = ct.Elem().Kind()
                                }
                                if k == reflect.Struct {
-                                       var refTable = session.statement.RefTable
-                                       if refTable == nil {
-                                               refTable, err = session.engine.TableInfo(condiBean[0])
-                                               if err != nil {
-                                                       return 0, err
-                                               }
+                                       condTable, err := session.engine.TableInfo(condiBean[0])
+                                       if err != nil {
+                                               return 0, err
                                        }
-                                       var err error
-                                       autoCond, err = session.statement.BuildConds(refTable, condiBean[0], true, true, false, true, false)
+
+                                       autoCond, err = session.statement.BuildConds(condTable, condiBean[0], true, true, false, true, false)
                                        if err != nil {
                                                return 0, err
                                        }
@@ -329,7 +333,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
        }
 
        if len(colNames) <= 0 {
-               return 0, errors.New("No content found to be updated")
+               return 0, ErrNoColumnsTobeUpdated
        }
 
        condSQL, condArgs, err = session.statement.GenCondSQL(cond)
@@ -450,7 +454,6 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6
                                // 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
index 5ad67b53a9a40baafa0569ec46d154763d7217ca..b793a8f1197bca1b6dd260316333696ab5c4d1ed 100644 (file)
@@ -7,11 +7,11 @@ package tags
 import (
        "encoding/gob"
        "errors"
-       "fmt"
        "reflect"
        "strings"
        "sync"
        "time"
+       "unicode"
 
        "xorm.io/xorm/caches"
        "xorm.io/xorm/convert"
@@ -22,7 +22,7 @@ import (
 
 var (
        // ErrUnsupportedType represents an unsupported type error
-       ErrUnsupportedType = errors.New("Unsupported type")
+       ErrUnsupportedType = errors.New("unsupported type")
 )
 
 // Parser represents a parser for xorm tag
@@ -124,6 +124,147 @@ func addIndex(indexName string, table *schemas.Table, col *schemas.Column, index
        }
 }
 
+var ErrIgnoreField = errors.New("field will be ignored")
+
+func (parser *Parser) parseFieldWithNoTag(fieldIndex int, field reflect.StructField, fieldValue reflect.Value) (*schemas.Column, error) {
+       var sqlType schemas.SQLType
+       if fieldValue.CanAddr() {
+               if _, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
+                       sqlType = schemas.SQLType{Name: schemas.Text}
+               }
+       }
+       if _, ok := fieldValue.Interface().(convert.Conversion); ok {
+               sqlType = schemas.SQLType{Name: schemas.Text}
+       } else {
+               sqlType = schemas.Type2SQLType(field.Type)
+       }
+       col := schemas.NewColumn(parser.columnMapper.Obj2Table(field.Name),
+               field.Name, sqlType, sqlType.DefaultLength,
+               sqlType.DefaultLength2, true)
+       col.FieldIndex = []int{fieldIndex}
+
+       if field.Type.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
+               col.IsAutoIncrement = true
+               col.IsPrimaryKey = true
+               col.Nullable = false
+       }
+       return col, nil
+}
+
+func (parser *Parser) parseFieldWithTags(table *schemas.Table, fieldIndex int, field reflect.StructField, fieldValue reflect.Value, tags []tag) (*schemas.Column, error) {
+       var col = &schemas.Column{
+               FieldName:       field.Name,
+               FieldIndex:      []int{fieldIndex},
+               Nullable:        true,
+               IsPrimaryKey:    false,
+               IsAutoIncrement: false,
+               MapType:         schemas.TWOSIDES,
+               Indexes:         make(map[string]int),
+               DefaultIsEmpty:  true,
+       }
+
+       var ctx = Context{
+               table:      table,
+               col:        col,
+               fieldValue: fieldValue,
+               indexNames: make(map[string]int),
+               parser:     parser,
+       }
+
+       for j, tag := range tags {
+               if ctx.ignoreNext {
+                       ctx.ignoreNext = false
+                       continue
+               }
+
+               ctx.tag = tag
+               ctx.tagUname = strings.ToUpper(tag.name)
+
+               if j > 0 {
+                       ctx.preTag = strings.ToUpper(tags[j-1].name)
+               }
+               if j < len(tags)-1 {
+                       ctx.nextTag = tags[j+1].name
+               } else {
+                       ctx.nextTag = ""
+               }
+
+               if h, ok := parser.handlers[ctx.tagUname]; ok {
+                       if err := h(&ctx); err != nil {
+                               return nil, err
+                       }
+               } else {
+                       if strings.HasPrefix(ctx.tag.name, "'") && strings.HasSuffix(ctx.tag.name, "'") {
+                               col.Name = ctx.tag.name[1 : len(ctx.tag.name)-1]
+                       } else {
+                               col.Name = ctx.tag.name
+                       }
+               }
+
+               if ctx.hasCacheTag {
+                       if parser.cacherMgr.GetDefaultCacher() != nil {
+                               parser.cacherMgr.SetCacher(table.Name, parser.cacherMgr.GetDefaultCacher())
+                       } else {
+                               parser.cacherMgr.SetCacher(table.Name, caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000))
+                       }
+               }
+               if ctx.hasNoCacheTag {
+                       parser.cacherMgr.SetCacher(table.Name, nil)
+               }
+       }
+
+       if col.SQLType.Name == "" {
+               col.SQLType = schemas.Type2SQLType(field.Type)
+       }
+       parser.dialect.SQLType(col)
+       if col.Length == 0 {
+               col.Length = col.SQLType.DefaultLength
+       }
+       if col.Length2 == 0 {
+               col.Length2 = col.SQLType.DefaultLength2
+       }
+       if col.Name == "" {
+               col.Name = parser.columnMapper.Obj2Table(field.Name)
+       }
+
+       if ctx.isUnique {
+               ctx.indexNames[col.Name] = schemas.UniqueType
+       } else if ctx.isIndex {
+               ctx.indexNames[col.Name] = schemas.IndexType
+       }
+
+       for indexName, indexType := range ctx.indexNames {
+               addIndex(indexName, table, col, indexType)
+       }
+
+       return col, nil
+}
+
+func (parser *Parser) parseField(table *schemas.Table, fieldIndex int, field reflect.StructField, fieldValue reflect.Value) (*schemas.Column, error) {
+       var (
+               tag       = field.Tag
+               ormTagStr = strings.TrimSpace(tag.Get(parser.identifier))
+       )
+       if ormTagStr == "-" {
+               return nil, ErrIgnoreField
+       }
+       if ormTagStr == "" {
+               return parser.parseFieldWithNoTag(fieldIndex, field, fieldValue)
+       }
+       tags, err := splitTag(ormTagStr)
+       if err != nil {
+               return nil, err
+       }
+       return parser.parseFieldWithTags(table, fieldIndex, field, fieldValue, tags)
+}
+
+func isNotTitle(n string) bool {
+       for _, c := range n {
+               return unicode.IsLower(c)
+       }
+       return true
+}
+
 // Parse parses a struct as a table information
 func (parser *Parser) Parse(v reflect.Value) (*schemas.Table, error) {
        t := v.Type()
@@ -139,185 +280,26 @@ func (parser *Parser) Parse(v reflect.Value) (*schemas.Table, error) {
        table.Type = t
        table.Name = names.GetTableName(parser.tableMapper, v)
 
-       var idFieldColName string
-       var hasCacheTag, hasNoCacheTag bool
-
        for i := 0; i < t.NumField(); i++ {
-               tag := t.Field(i).Tag
-
-               ormTagStr := tag.Get(parser.identifier)
-               var col *schemas.Column
-               fieldValue := v.Field(i)
-               fieldType := fieldValue.Type()
-
-               if ormTagStr != "" {
-                       col = &schemas.Column{
-                               FieldName:       t.Field(i).Name,
-                               Nullable:        true,
-                               IsPrimaryKey:    false,
-                               IsAutoIncrement: false,
-                               MapType:         schemas.TWOSIDES,
-                               Indexes:         make(map[string]int),
-                               DefaultIsEmpty:  true,
-                       }
-                       tags := splitTag(ormTagStr)
-
-                       if len(tags) > 0 {
-                               if tags[0] == "-" {
-                                       continue
-                               }
-
-                               var ctx = Context{
-                                       table:      table,
-                                       col:        col,
-                                       fieldValue: fieldValue,
-                                       indexNames: make(map[string]int),
-                                       parser:     parser,
-                               }
-
-                               if strings.HasPrefix(strings.ToUpper(tags[0]), "EXTENDS") {
-                                       pStart := strings.Index(tags[0], "(")
-                                       if pStart > -1 && strings.HasSuffix(tags[0], ")") {
-                                               var tagPrefix = strings.TrimFunc(tags[0][pStart+1:len(tags[0])-1], func(r rune) bool {
-                                                       return r == '\'' || r == '"'
-                                               })
-
-                                               ctx.params = []string{tagPrefix}
-                                       }
-
-                                       if err := ExtendsTagHandler(&ctx); err != nil {
-                                               return nil, err
-                                       }
-                                       continue
-                               }
-
-                               for j, key := range tags {
-                                       if ctx.ignoreNext {
-                                               ctx.ignoreNext = false
-                                               continue
-                                       }
-
-                                       k := strings.ToUpper(key)
-                                       ctx.tagName = k
-                                       ctx.params = []string{}
-
-                                       pStart := strings.Index(k, "(")
-                                       if pStart == 0 {
-                                               return nil, errors.New("( could not be the first character")
-                                       }
-                                       if pStart > -1 {
-                                               if !strings.HasSuffix(k, ")") {
-                                                       return nil, fmt.Errorf("field %s tag %s cannot match ) character", col.FieldName, key)
-                                               }
-
-                                               ctx.tagName = k[:pStart]
-                                               ctx.params = strings.Split(key[pStart+1:len(k)-1], ",")
-                                       }
-
-                                       if j > 0 {
-                                               ctx.preTag = strings.ToUpper(tags[j-1])
-                                       }
-                                       if j < len(tags)-1 {
-                                               ctx.nextTag = tags[j+1]
-                                       } else {
-                                               ctx.nextTag = ""
-                                       }
-
-                                       if h, ok := parser.handlers[ctx.tagName]; ok {
-                                               if err := h(&ctx); err != nil {
-                                                       return nil, err
-                                               }
-                                       } else {
-                                               if strings.HasPrefix(key, "'") && strings.HasSuffix(key, "'") {
-                                                       col.Name = key[1 : len(key)-1]
-                                               } else {
-                                                       col.Name = key
-                                               }
-                                       }
-
-                                       if ctx.hasCacheTag {
-                                               hasCacheTag = true
-                                       }
-                                       if ctx.hasNoCacheTag {
-                                               hasNoCacheTag = true
-                                       }
-                               }
-
-                               if col.SQLType.Name == "" {
-                                       col.SQLType = schemas.Type2SQLType(fieldType)
-                               }
-                               parser.dialect.SQLType(col)
-                               if col.Length == 0 {
-                                       col.Length = col.SQLType.DefaultLength
-                               }
-                               if col.Length2 == 0 {
-                                       col.Length2 = col.SQLType.DefaultLength2
-                               }
-                               if col.Name == "" {
-                                       col.Name = parser.columnMapper.Obj2Table(t.Field(i).Name)
-                               }
-
-                               if ctx.isUnique {
-                                       ctx.indexNames[col.Name] = schemas.UniqueType
-                               } else if ctx.isIndex {
-                                       ctx.indexNames[col.Name] = schemas.IndexType
-                               }
-
-                               for indexName, indexType := range ctx.indexNames {
-                                       addIndex(indexName, table, col, indexType)
-                               }
-                       }
-               } else if fieldValue.CanSet() {
-                       var sqlType schemas.SQLType
-                       if fieldValue.CanAddr() {
-                               if _, ok := fieldValue.Addr().Interface().(convert.Conversion); ok {
-                                       sqlType = schemas.SQLType{Name: schemas.Text}
-                               }
-                       }
-                       if _, ok := fieldValue.Interface().(convert.Conversion); ok {
-                               sqlType = schemas.SQLType{Name: schemas.Text}
-                       } else {
-                               sqlType = schemas.Type2SQLType(fieldType)
-                       }
-                       col = schemas.NewColumn(parser.columnMapper.Obj2Table(t.Field(i).Name),
-                               t.Field(i).Name, sqlType, sqlType.DefaultLength,
-                               sqlType.DefaultLength2, true)
-
-                       if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) {
-                               idFieldColName = col.Name
-                       }
-               } else {
+               var field = t.Field(i)
+               if isNotTitle(field.Name) {
                        continue
                }
-               if col.IsAutoIncrement {
-                       col.Nullable = false
+
+               col, err := parser.parseField(table, i, field, v.Field(i))
+               if err == ErrIgnoreField {
+                       continue
+               } else if err != nil {
+                       return nil, err
                }
 
                table.AddColumn(col)
-
        } // end for
 
-       if idFieldColName != "" && len(table.PrimaryKeys) == 0 {
-               col := table.GetColumn(idFieldColName)
-               col.IsPrimaryKey = true
-               col.IsAutoIncrement = true
-               col.Nullable = false
-               table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
-               table.AutoIncrement = col.Name
-       }
-
-       if hasCacheTag {
-               if parser.cacherMgr.GetDefaultCacher() != nil { // !nash! use engine's cacher if provided
-                       //engine.logger.Info("enable cache on table:", table.Name)
-                       parser.cacherMgr.SetCacher(table.Name, parser.cacherMgr.GetDefaultCacher())
-               } else {
-                       //engine.logger.Info("enable LRU cache on table:", table.Name)
-                       parser.cacherMgr.SetCacher(table.Name, caches.NewLRUCacher2(caches.NewMemoryStore(), time.Hour, 10000))
-               }
-       }
-       if hasNoCacheTag {
-               //engine.logger.Info("disable cache on table:", table.Name)
-               parser.cacherMgr.SetCacher(table.Name, nil)
+       deletedColumn := table.DeletedColumn()
+       // check columns
+       if deletedColumn != nil {
+               deletedColumn.Nullable = true
        }
 
        return table, nil
index bb5b583887bb8600d004eb59506596b1b883ba4d..641b8c529a31f59e08878cbe5844129c325b5d41 100644 (file)
@@ -14,30 +14,74 @@ import (
        "xorm.io/xorm/schemas"
 )
 
-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
+type tag struct {
+       name   string
+       params []string
+}
+
+func splitTag(tagStr string) ([]tag, error) {
+       tagStr = strings.TrimSpace(tagStr)
+       var (
+               inQuote    bool
+               inBigQuote bool
+               lastIdx    int
+               curTag     tag
+               paramStart int
+               tags       []tag
+       )
+       for i, t := range tagStr {
+               switch t {
+               case '\'':
+                       inQuote = !inQuote
+               case ' ':
+                       if !inQuote && !inBigQuote {
+                               if lastIdx < i {
+                                       if curTag.name == "" {
+                                               curTag.name = tagStr[lastIdx:i]
+                                       }
+                                       tags = append(tags, curTag)
+                                       lastIdx = i + 1
+                                       curTag = tag{}
+                               } else if lastIdx == i {
+                                       lastIdx = i + 1
+                               }
+                       } else if inBigQuote && !inQuote {
+                               paramStart = i + 1
+                       }
+               case ',':
+                       if !inQuote && !inBigQuote {
+                               return nil, fmt.Errorf("comma[%d] of %s should be in quote or big quote", i, tagStr)
+                       }
+                       if !inQuote && inBigQuote {
+                               curTag.params = append(curTag.params, strings.TrimSpace(tagStr[paramStart:i]))
+                               paramStart = i + 1
+                       }
+               case '(':
+                       inBigQuote = true
+                       if !inQuote {
+                               curTag.name = tagStr[lastIdx:i]
+                               paramStart = i + 1
+                       }
+               case ')':
+                       inBigQuote = false
+                       if !inQuote {
+                               curTag.params = append(curTag.params, tagStr[paramStart:i])
                        }
                }
        }
-       if lastIdx < len(tag) {
-               tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
+       if lastIdx < len(tagStr) {
+               if curTag.name == "" {
+                       curTag.name = tagStr[lastIdx:]
+               }
+               tags = append(tags, curTag)
        }
-       return
+       return tags, nil
 }
 
 // Context represents a context for xorm tag parse.
 type Context struct {
-       tagName         string
-       params          []string
+       tag
+       tagUname        string
        preTag, nextTag string
        table           *schemas.Table
        col             *schemas.Column
@@ -76,6 +120,7 @@ var (
                "CACHE":    CacheTagHandler,
                "NOCACHE":  NoCacheTagHandler,
                "COMMENT":  CommentTagHandler,
+               "EXTENDS":  ExtendsTagHandler,
        }
 )
 
@@ -124,6 +169,7 @@ func NotNullTagHandler(ctx *Context) error {
 // AutoIncrTagHandler describes autoincr tag handler
 func AutoIncrTagHandler(ctx *Context) error {
        ctx.col.IsAutoIncrement = true
+       ctx.col.Nullable = false
        /*
                if len(ctx.params) > 0 {
                        autoStartInt, err := strconv.Atoi(ctx.params[0])
@@ -192,6 +238,7 @@ func UpdatedTagHandler(ctx *Context) error {
 // DeletedTagHandler describes deleted tag handler
 func DeletedTagHandler(ctx *Context) error {
        ctx.col.IsDeleted = true
+       ctx.col.Nullable = true
        return nil
 }
 
@@ -225,41 +272,44 @@ func CommentTagHandler(ctx *Context) error {
 
 // SQLTypeTagHandler describes SQL Type tag handler
 func SQLTypeTagHandler(ctx *Context) error {
-       ctx.col.SQLType = schemas.SQLType{Name: ctx.tagName}
-       if strings.EqualFold(ctx.tagName, "JSON") {
+       ctx.col.SQLType = schemas.SQLType{Name: ctx.tagUname}
+       if ctx.tagUname == "JSON" {
                ctx.col.IsJSON = true
        }
-       if len(ctx.params) > 0 {
-               if ctx.tagName == schemas.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
+       if len(ctx.params) == 0 {
+               return nil
+       }
+
+       switch ctx.tagUname {
+       case schemas.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
+               }
+       case schemas.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
+               }
+       default:
+               var err error
+               if len(ctx.params) == 2 {
+                       ctx.col.Length, err = strconv.Atoi(ctx.params[0])
+                       if err != nil {
+                               return err
                        }
-               } else if ctx.tagName == schemas.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
+                       ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
+                       if err != nil {
+                               return err
                        }
-               } 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
-                               }
+               } else if len(ctx.params) == 1 {
+                       ctx.col.Length, err = strconv.Atoi(ctx.params[0])
+                       if err != nil {
+                               return err
                        }
                }
        }
@@ -289,11 +339,12 @@ func ExtendsTagHandler(ctx *Context) error {
                }
                for _, col := range parentTable.Columns() {
                        col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
+                       col.FieldIndex = append(ctx.col.FieldIndex, col.FieldIndex...)
 
                        var tagPrefix = ctx.col.FieldName
                        if len(ctx.params) > 0 {
                                col.Nullable = isPtr
-                               tagPrefix = ctx.params[0]
+                               tagPrefix = strings.Trim(ctx.params[0], "'")
                                if col.IsPrimaryKey {
                                        col.Name = ctx.col.FieldName
                                        col.IsPrimaryKey = false
@@ -315,7 +366,7 @@ func ExtendsTagHandler(ctx *Context) error {
        default:
                //TODO: warning
        }
-       return nil
+       return ErrIgnoreField
 }
 
 // CacheTagHandler describes cache tag handler