From a3412d6ba6cfdd5b11353072c6d29824f7be386d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 3 Feb 2019 18:56:45 +0800 Subject: [PATCH 01/14] add oracle tests --- dialects/oracle.go | 2 +- oracle_test.go | 11 +++++++++++ test_oracle.sh | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 oracle_test.go create mode 100755 test_oracle.sh diff --git a/dialects/oracle.go b/dialects/oracle.go index 2620b0bb..d3c889d7 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -690,7 +690,7 @@ func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableNam col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0} case "NUMBER": col.SQLType = schemas.SQLType{Name: schemas.Double, DefaultLength: len1, DefaultLength2: len2} - case "LONG", "LONG RAW": + case "LONG", "LONG RAW", "NCLOB", "CLOB": col.SQLType = schemas.SQLType{Name: schemas.Text, DefaultLength: 0, DefaultLength2: 0} case "RAW": col.SQLType = schemas.SQLType{Name: schemas.Binary, DefaultLength: 0, DefaultLength2: 0} diff --git a/oracle_test.go b/oracle_test.go new file mode 100644 index 00000000..ccebd965 --- /dev/null +++ b/oracle_test.go @@ -0,0 +1,11 @@ +// Copyright 20190 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 oracle + +package xorm + +import ( + _ "github.com/mattn/go-oci8" +) diff --git a/test_oracle.sh b/test_oracle.sh new file mode 100755 index 00000000..56bd4609 --- /dev/null +++ b/test_oracle.sh @@ -0,0 +1 @@ +go test -tags=oracle -db=oci8 -conn_str="system/oracle@localhost:1521/xe" \ No newline at end of file From fb9f6a2e13d3505e719497fdba45e02c49481480 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 21 Feb 2020 10:41:32 +0800 Subject: [PATCH 02/14] Add oracle on makefile and drone --- .drone.yml | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 18 ++++++++++ go.mod | 1 + go.sum | 2 ++ test_oracle.sh | 1 - 5 files changed, 113 insertions(+), 1 deletion(-) delete mode 100755 test_oracle.sh diff --git a/.drone.yml b/.drone.yml index 7a18e0d6..4685d50e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -109,6 +109,86 @@ steps: - push - pull_request +- name: test-oracle + pull: default + image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + TEST_ORACLE_HOST: oracle:1521 + TEST_ORACLE_DBNAME: xe + TEST_ORACLE_USERNAME: system + TEST_ORACLE_PASSWORD: oracle + TEST_CACHE_ENABLE: false + commands: + - make test-oracle + when: + event: + - push + - pull_request + +- name: test-oracle-cache + pull: default + image: golang:1.12 + depends_on: + - test-oracle + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + TEST_ORACLE_HOST: oracle:1521 + TEST_ORACLE_DBNAME: xe + TEST_ORACLE_USERNAME: system + TEST_ORACLE_PASSWORD: oracle + TEST_CACHE_ENABLE: true + commands: + - make test-oracle + when: + event: + - push + - pull_request + +- name: test-oracle-schema + pull: default + image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + TEST_ORACLE_SCHEMA: xorm + TEST_ORACLE_HOST: oracle:1521 + TEST_ORACLE_DBNAME: xe + TEST_ORACLE_USERNAME: system + TEST_ORACLE_PASSWORD: oracle + TEST_CACHE_ENABLE: false + SCHEMA: xorm + commands: + - make test-oracle + when: + event: + - push + - pull_request + +- name: test-oracle-schema-cache + pull: default + image: golang:1.12 + depends_on: + - test-oracle-schema + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + TEST_ORACLE_SCHEMA: xorm + TEST_ORACLE_HOST: oracle:1521 + TEST_ORACLE_DBNAME: xe + TEST_ORACLE_USERNAME: system + TEST_ORACLE_PASSWORD: oracle + TEST_CACHE_ENABLE: true + SCHEMA: xorm + commands: + - make test-oracle + when: + event: + - push + - pull_request + - name: test-postgres pull: default image: golang:1.12 @@ -292,6 +372,18 @@ services: - tag - pull_request +- name: oracle + pull: default + image: oracleinanutshell/oracle-xe-11g:latest + environment: + ORACLE_ALLOW_REMOTE: true + ORACLE_ENABLE_XDB: true + when: + event: + - push + - tag + - pull_request + - name: cockroach pull: default image: cockroachdb/cockroach:v19.2.4 diff --git a/Makefile b/Makefile index 4cccacd8..645baba3 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,12 @@ TEST_MYSQL_DBNAME ?= xorm_test TEST_MYSQL_USERNAME ?= root TEST_MYSQL_PASSWORD ?= +TEST_ORACLE_HOST ?= oracle:1521 +TEST_ORACLE_SCHEMA ?= +TEST_ORACLE_DBNAME ?= xe +TEST_ORACLE_USERNAME ?= system +TEST_ORACLE_PASSWORD ?= oracle + TEST_PGSQL_HOST ?= pgsql:5432 TEST_PGSQL_SCHEMA ?= TEST_PGSQL_DBNAME ?= xorm_test @@ -176,6 +182,18 @@ test-mysql\#%: go-check -conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \ -coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic +.PNONY: test-oracle +test-oracle: go-check + $(GO) test -race -tags=oracle -db=oci8 -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + -conn_str="$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ + -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic + +.PHONY: test-oracle\#% +test-oralce\#%: go-check + $(GO) test -race -run $* -tags=oracle -db=oci8 -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + -conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)" \ + -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic + .PNONY: test-postgres test-postgres: go-check $(GO) test $(INTEGRATION_PACKAGES) -v -race -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ diff --git a/go.mod b/go.mod index ff42c0f7..d5297ae7 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/go-sql-driver/mysql v1.4.1 github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.0.0 + github.com/mattn/go-oci8 v0.0.4 github.com/mattn/go-sqlite3 v1.10.0 github.com/stretchr/testify v1.4.0 github.com/syndtr/goleveldb v1.0.0 diff --git a/go.sum b/go.sum index 84f9126e..946fda21 100644 --- a/go.sum +++ b/go.sum @@ -59,6 +59,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-oci8 v0.0.4 h1:3h8d3VE8buPHoEcApdEoww7Gy3G0SWhwJ0UpniYxBJU= +github.com/mattn/go-oci8 v0.0.4/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= diff --git a/test_oracle.sh b/test_oracle.sh deleted file mode 100755 index 56bd4609..00000000 --- a/test_oracle.sh +++ /dev/null @@ -1 +0,0 @@ -go test -tags=oracle -db=oci8 -conn_str="system/oracle@localhost:1521/xe" \ No newline at end of file From 53a8ea697744c80c9ece8f3c74b4fe23c357a78e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 26 Feb 2020 10:04:04 +0800 Subject: [PATCH 03/14] move goracle to godror --- Makefile | 23 ++++++++++--- dialects/dialect.go | 2 +- dialects/oracle.go | 67 ++++++++++++++++++------------------- go.mod | 1 + go.sum | 28 ++++++---------- integrations/engine_test.go | 4 ++- 6 files changed, 67 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index 645baba3..6360b1e8 100644 --- a/Makefile +++ b/Makefile @@ -182,18 +182,33 @@ test-mysql\#%: go-check -conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \ -coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic -.PNONY: test-oracle -test-oracle: go-check +.PHONY: test-oracle +test-oracle: test-godror + +.PNONY: test-oci8 +test-oci8: go-check $(GO) test -race -tags=oracle -db=oci8 -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic -.PHONY: test-oracle\#% -test-oralce\#%: go-check +.PHONY: test-oci8\#% +test-oci8\#%: go-check $(GO) test -race -run $* -tags=oracle -db=oci8 -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic +.PHONY: test-godror +test-godror: go-check + $(GO) test -race -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ + -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic + +.PHONY: test-godror\#% +test-godror\#%: go-check + $(GO) test -race -run $* -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ + -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic + .PNONY: test-postgres test-postgres: go-check $(GO) test $(INTEGRATION_PACKAGES) -v -race -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ diff --git a/dialects/dialect.go b/dialects/dialect.go index dc96f73a..53c8cf29 100644 --- a/dialects/dialect.go +++ b/dialects/dialect.go @@ -207,7 +207,7 @@ func regDrvsNDialects() bool { "pgx": {"postgres", func() Driver { return &pqDriverPgx{} }, func() Dialect { return &postgres{} }}, "sqlite3": {"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 { diff --git a/dialects/oracle.go b/dialects/oracle.go index d3c889d7..ad7b0095 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -8,7 +8,7 @@ import ( "context" "errors" "fmt" - "regexp" + "net/url" "strconv" "strings" @@ -802,53 +802,50 @@ func (db *oracle) Filters() []Filter { } } -type goracleDriver struct { +// https://github.com/godror/godror +type godrorDriver struct { } -func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*URI, error) { - db := &URI{DBType: schemas.ORACLE} - dsnPattern := regexp.MustCompile( - `^(?:(?P.*?)(?::(?P.*))?@)?` + // [user[:password]@] - `(?:(?P[^\(]*)(?:\((?P[^\)]*)\))?)?` + // [net[(addr)]] - `\/(?P.*?)` + // /dbname - `(?:\?(?P[^\?]*))?$`) // [?param1=value1¶mN=valueN] - matches := dsnPattern.FindStringSubmatch(dataSourceName) - // tlsConfigRegister := make(map[string]*tls.Config) - names := dsnPattern.SubexpNames() - - for i, match := range matches { - switch names[i] { - case "dbname": - db.DBName = match - } +func parseOracle(driverName, dataSourceName string) (*URI, error) { + var connStr = dataSourceName + if !strings.HasPrefix(connStr, "oracle://") { + connStr = fmt.Sprintf("oracle://%s", connStr) } + + u, err := url.Parse(connStr) + if err != nil { + return nil, err + } + + db := &URI{ + DBType: schemas.ORACLE, + Host: u.Hostname(), + Port: u.Port(), + DBName: strings.TrimLeft(u.RequestURI(), "/"), + } + + if u.User != nil { + db.User = u.User.Username() + db.Passwd, _ = u.User.Password() + } + + fmt.Printf("%#v\n", db) + if db.DBName == "" { return nil, errors.New("dbname is empty") } return db, nil } +func (cfg *godrorDriver) Parse(driverName, dataSourceName string) (*URI, error) { + return parseOracle(driverName, dataSourceName) +} + type oci8Driver struct { } // dataSourceName=user/password@ipv4:port/dbname // dataSourceName=user/password@[ipv6]:port/dbname func (p *oci8Driver) Parse(driverName, dataSourceName string) (*URI, error) { - db := &URI{DBType: schemas.ORACLE} - dsnPattern := regexp.MustCompile( - `^(?P.*)\/(?P.*)@` + // user:password@ - `(?P.*)` + // ip:port - `\/(?P.*)`) // dbname - matches := dsnPattern.FindStringSubmatch(dataSourceName) - names := dsnPattern.SubexpNames() - for i, match := range matches { - switch names[i] { - case "dbname": - db.DBName = match - } - } - if db.DBName == "" && len(matches) != 0 { - return nil, errors.New("dbname is empty") - } - return db, nil + return parseOracle(driverName, dataSourceName) } diff --git a/go.mod b/go.mod index d5297ae7..5f7f9045 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.11 require ( github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 github.com/go-sql-driver/mysql v1.4.1 + github.com/godror/godror v0.12.1 github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.0.0 github.com/mattn/go-oci8 v0.0.4 diff --git a/go.sum b/go.sum index 946fda21..82d92c88 100644 --- a/go.sum +++ b/go.sum @@ -23,52 +23,52 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godror/godror v0.12.1 h1:NXKbt10PLKKsqP0GBbqXgUzE9O5SvppTeAx6jznuBE8= +github.com/godror/godror v0.12.1/go.mod h1:9MVLtu25FBJBMHkPs0m3Ngf/VmwGcLpM2HS8PlNGw9U= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-oci8 v0.0.4 h1:3h8d3VE8buPHoEcApdEoww7Gy3G0SWhwJ0UpniYxBJU= github.com/mattn/go-oci8 v0.0.4/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -87,7 +87,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -111,34 +110,32 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -147,11 +144,8 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= diff --git a/integrations/engine_test.go b/integrations/engine_test.go index 19c5285d..0b792b71 100644 --- a/integrations/engine_test.go +++ b/integrations/engine_test.go @@ -16,10 +16,12 @@ import ( _ "github.com/denisenkom/go-mssqldb" _ "github.com/go-sql-driver/mysql" + _ "github.com/godror/godror" _ "github.com/lib/pq" _ "github.com/mattn/go-sqlite3" - "github.com/stretchr/testify/assert" _ "github.com/ziutek/mymysql/godrv" + + "github.com/stretchr/testify/assert" ) func TestPing(t *testing.T) { From cb8b68e1cfddca729acaf8778c56a90958147f95 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 26 Feb 2020 13:59:33 +0800 Subject: [PATCH 04/14] Fix drone --- .drone.yml | 44 ++------------------------------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/.drone.yml b/.drone.yml index 4685d50e..d110fdef 100644 --- a/.drone.yml +++ b/.drone.yml @@ -122,26 +122,7 @@ steps: TEST_CACHE_ENABLE: false commands: - make test-oracle - when: - event: - - push - - pull_request - -- name: test-oracle-cache - pull: default - image: golang:1.12 - depends_on: - - test-oracle - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - TEST_ORACLE_HOST: oracle:1521 - TEST_ORACLE_DBNAME: xe - TEST_ORACLE_USERNAME: system - TEST_ORACLE_PASSWORD: oracle - TEST_CACHE_ENABLE: true - commands: - - make test-oracle + - TEST_CACHE_ENABLE=true make test-oracle when: event: - push @@ -162,28 +143,7 @@ steps: SCHEMA: xorm commands: - make test-oracle - when: - event: - - push - - pull_request - -- name: test-oracle-schema-cache - pull: default - image: golang:1.12 - depends_on: - - test-oracle-schema - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - TEST_ORACLE_SCHEMA: xorm - TEST_ORACLE_HOST: oracle:1521 - TEST_ORACLE_DBNAME: xe - TEST_ORACLE_USERNAME: system - TEST_ORACLE_PASSWORD: oracle - TEST_CACHE_ENABLE: true - SCHEMA: xorm - commands: - - make test-oracle + - TEST_CACHE_ENABLE=true make test-oracle when: event: - push From d7250e866b400613fd481d226b8198b4cb05322b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 4 Mar 2020 13:38:05 +0800 Subject: [PATCH 05/14] fix oracle --- dialects/oracle.go | 4 ++-- integrations/cache_test.go | 8 ++++---- session_insert.go | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/dialects/oracle.go b/dialects/oracle.go index ad7b0095..3459146a 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -725,8 +725,8 @@ func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableNam } func (db *oracle) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) { - args := []interface{}{} - s := "SELECT table_name FROM user_tables" + s := "SELECT table_name FROM user_tables WHERE TABLESPACE_NAME = :1 AND table_name NOT LIKE :2" + args := []interface{}{strings.ToUpper(db.uri.User), "%$%"} rows, err := queryer.QueryContext(ctx, s, args...) if err != nil { diff --git a/integrations/cache_test.go b/integrations/cache_test.go index 44e817b1..08f2615b 100644 --- a/integrations/cache_test.go +++ b/integrations/cache_test.go @@ -62,7 +62,7 @@ func TestCacheFind(t *testing.T) { } boxes = make([]MailBox, 0, 2) - assert.NoError(t, testEngine.Alias("a").Where("a.id > -1").Asc("a.id").Find(&boxes)) + assert.NoError(t, testEngine.Alias("a").Where("`a`.`id` > -1").Asc("`a`.`id`").Find(&boxes)) assert.EqualValues(t, 2, len(boxes)) for i, box := range boxes { assert.Equal(t, inserts[i].Id, box.Id) @@ -77,7 +77,7 @@ func TestCacheFind(t *testing.T) { } boxes2 := make([]MailBox4, 0, 2) - assert.NoError(t, testEngine.Table("mail_box").Where("mail_box.id > -1").Asc("mail_box.id").Find(&boxes2)) + assert.NoError(t, testEngine.Table("mail_box").Where("`mail_box`.`id` > -1").Asc("mail_box.id").Find(&boxes2)) assert.EqualValues(t, 2, len(boxes2)) for i, box := range boxes2 { assert.Equal(t, inserts[i].Id, box.Id) @@ -164,14 +164,14 @@ func TestCacheGet(t *testing.T) { assert.NoError(t, err) var box1 MailBox3 - has, err := testEngine.Where("id = ?", inserts[0].Id).Get(&box1) + has, err := testEngine.Where("`id` = ?", inserts[0].Id).Get(&box1) assert.NoError(t, err) assert.True(t, has) assert.EqualValues(t, "user1", box1.Username) assert.EqualValues(t, "pass1", box1.Password) var box2 MailBox3 - has, err = testEngine.Where("id = ?", inserts[0].Id).Get(&box2) + has, err = testEngine.Where("`id` = ?", inserts[0].Id).Get(&box2) assert.NoError(t, err) assert.True(t, has) assert.EqualValues(t, "user1", box2.Username) diff --git a/session_insert.go b/session_insert.go index 5f968151..3ec4e93f 100644 --- a/session_insert.go +++ b/session_insert.go @@ -337,7 +337,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { // for postgres, many of them didn't implement lastInsertId, so we should // implemented it ourself. if session.engine.dialect.URI().DBType == schemas.ORACLE && len(table.AutoIncrement) > 0 { - res, err := session.queryBytes("select seq_atable.currval from dual", args...) + _, err := session.exec(sqlStr, args...) if err != nil { return 0, err } @@ -355,6 +355,10 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } } + res, err := session.queryBytes("select seq_atable.currval from dual") + if err != nil { + return 0, err + } if len(res) < 1 { return 0, errors.New("insert no error but not returned id") } From 8b5da97cacdd3d56f0f0c4c7740897f06560b2d8 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 7 Mar 2020 18:20:05 +0800 Subject: [PATCH 06/14] Fix quoter --- dialects/oracle.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dialects/oracle.go b/dialects/oracle.go index 3459146a..d29b1535 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -500,8 +500,8 @@ var ( } oracleQuoter = schemas.Quoter{ - Prefix: '[', - Suffix: ']', + Prefix: '"', + Suffix: '"', IsReserved: schemas.AlwaysReserve, } ) From 4e99c291d8800c0c26f5064138760fac2017ffff Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 8 Mar 2020 01:06:27 +0800 Subject: [PATCH 07/14] fix bugs --- Makefile | 8 +-- core/interface.go | 1 + dialects/dialect.go | 6 +-- dialects/mssql.go | 6 +-- dialects/oracle.go | 91 +++++++++++++++++++++++++++++------ integrations/engine_test.go | 3 +- integrations/tests.go | 9 ++-- internal/statements/insert.go | 14 ++++++ session_insert.go | 20 +++----- session_schema.go | 36 ++++++++++++-- 10 files changed, 145 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 6360b1e8..2fd48527 100644 --- a/Makefile +++ b/Makefile @@ -187,25 +187,25 @@ test-oracle: test-godror .PNONY: test-oci8 test-oci8: go-check - $(GO) test -race -tags=oracle -db=oci8 -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test -v -race -tags=oracle -db=oci8 -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-oci8\#% test-oci8\#%: go-check - $(GO) test -race -run $* -tags=oracle -db=oci8 -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test -v -race -run $* -tags=oracle -db=oci8 -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-godror test-godror: go-check - $(GO) test -race -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test -v -race -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-godror\#% test-godror\#%: go-check - $(GO) test -race -run $* -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test -v -race -run $* -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic diff --git a/core/interface.go b/core/interface.go index a5c8e4e2..b2746ae0 100644 --- a/core/interface.go +++ b/core/interface.go @@ -7,6 +7,7 @@ import ( // Queryer represents an interface to query a SQL to get data from database type Queryer interface { + QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) } diff --git a/dialects/dialect.go b/dialects/dialect.go index 53c8cf29..a1299bea 100644 --- a/dialects/dialect.go +++ b/dialects/dialect.go @@ -59,7 +59,7 @@ type Dialect interface { GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) - DropTableSQL(tableName string) (string, bool) + DropTableSQL(tableName, autoincrCol string) ([]string, bool) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName string, colName string) (bool, error) @@ -100,9 +100,9 @@ func (b *Base) FormatBytes(bs []byte) string { return fmt.Sprintf("0x%x", bs) } -func (db *Base) DropTableSQL(tableName string) (string, bool) { +func (db *Base) DropTableSQL(tableName, autoincrCol string) ([]string, bool) { quote := db.dialect.Quoter().Quote - return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName)), true + return []string{fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName))}, true } func (db *Base) HasRecords(queryer core.Queryer, ctx context.Context, query string, args ...interface{}) (bool, error) { diff --git a/dialects/mssql.go b/dialects/mssql.go index 8ef924b8..3894e105 100644 --- a/dialects/mssql.go +++ b/dialects/mssql.go @@ -311,10 +311,10 @@ func (db *mssql) AutoIncrStr() string { return "IDENTITY" } -func (db *mssql) DropTableSQL(tableName string) (string, bool) { - return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+ +func (db *mssql) DropTableSQL(tableName, autoincrCol string) ([]string, bool) { + return []string{fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+ "object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+ - "DROP TABLE \"%s\"", tableName, tableName), true + "DROP TABLE \"%s\"", tableName, tableName)}, true } func (db *mssql) IndexCheckSQL(tableName, idxName string) (string, []interface{}) { diff --git a/dialects/oracle.go b/dialects/oracle.go index d29b1535..3e8b8630 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -523,9 +523,9 @@ func (db *oracle) SQLType(c *schemas.Column) string { case schemas.Binary, schemas.VarBinary, schemas.Blob, schemas.TinyBlob, schemas.MediumBlob, schemas.LongBlob, schemas.Bytea: return schemas.Blob case schemas.Time, schemas.DateTime, schemas.TimeStamp: - res = schemas.TimeStamp + res = schemas.Date case schemas.TimeStampz: - res = "TIMESTAMP WITH TIME ZONE" + res = "TIMESTAMP" case schemas.Float, schemas.Double, schemas.Numeric, schemas.Decimal: res = "NUMBER" case schemas.Text, schemas.MediumText, schemas.LongText, schemas.Json: @@ -556,8 +556,14 @@ func (db *oracle) IsReserved(name string) bool { return ok } -func (db *oracle) DropTableSQL(tableName string) (string, bool) { - return fmt.Sprintf("DROP TABLE `%s`", tableName), false +func (db *oracle) DropTableSQL(tableName, autoincrCol string) ([]string, bool) { + var sqls = []string{ + fmt.Sprintf("DROP TABLE `%s`", tableName), + } + if autoincrCol != "" { + sqls = append(sqls, fmt.Sprintf("DROP SEQUENCE %s", seqName(tableName))) + } + return sqls, false } func (db *oracle) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) { @@ -589,8 +595,19 @@ func (db *oracle) CreateTableSQL(table *schemas.Table, tableName string) ([]stri sql += " ), " } - sql = sql[:len(sql)-2] + ")" - return []string{sql}, false + var sqls = []string{sql[:len(sql)-2] + ")"} + + if table.AutoIncrColumn() != nil { + var sql2 = fmt.Sprintf(`CREATE sequence %s + minvalue 1 + nomaxvalue + start with 1 + increment by 1 + nocycle + nocache`, seqName(tableName)) + sqls = append(sqls, sql2) + } + return sqls, false } func (db *oracle) SetQuotePolicy(quotePolicy QuotePolicy) { @@ -627,12 +644,32 @@ func (db *oracle) IsColumnExist(queryer core.Queryer, ctx context.Context, table return db.HasRecords(queryer, ctx, query, args...) } -func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) { - args := []interface{}{tableName} - s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," + - "nullable FROM USER_TAB_COLUMNS WHERE table_name = :1" +func seqName(tableName string) string { + return "SEQ_" + strings.ToUpper(tableName) +} - rows, err := queryer.QueryContext(ctx, s, args...) +func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) { + //s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," + + // "nullable FROM USER_TAB_COLUMNS WHERE table_name = :1" + + s := `select column_name from user_cons_columns + where constraint_name = (select constraint_name from user_constraints + where table_name = :1 and constraint_type ='P')` + var pkName string + err := queryer.QueryRowContext(ctx, s, tableName).Scan(&pkName) + if err != nil { + return nil, nil, err + } + + s = `SELECT USER_TAB_COLS.COLUMN_NAME, USER_TAB_COLS.DATA_DEFAULT, USER_TAB_COLS.DATA_TYPE, USER_TAB_COLS.DATA_LENGTH, + USER_TAB_COLS.data_precision, USER_TAB_COLS.data_scale, USER_TAB_COLS.NULLABLE, + user_col_comments.comments + FROM USER_TAB_COLS + LEFT JOIN user_col_comments on user_col_comments.TABLE_NAME=USER_TAB_COLS.TABLE_NAME + AND user_col_comments.COLUMN_NAME=USER_TAB_COLS.COLUMN_NAME + WHERE USER_TAB_COLS.table_name = :1` + + rows, err := queryer.QueryContext(ctx, s, tableName) if err != nil { return nil, nil, err } @@ -644,11 +681,11 @@ func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableNam col := new(schemas.Column) col.Indexes = make(map[string]int) - var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string + var colName, colDefault, nullable, dataType, dataPrecision, dataScale, comment *string var dataLen int err = rows.Scan(&colName, &colDefault, &dataType, &dataLen, &dataPrecision, - &dataScale, &nullable) + &dataScale, &nullable, &comment) if err != nil { return nil, nil, err } @@ -665,10 +702,28 @@ func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableNam col.Nullable = false } - var ignore bool + if comment != nil { + col.Comment = *comment + } + if pkName != "" && pkName == col.Name { + col.IsPrimaryKey = true - var dt string - var len1, len2 int + has, err := db.HasRecords(queryer, ctx, "SELECT * FROM USER_SEQUENCES WHERE SEQUENCE_NAME = :1", seqName(tableName)) + if err != nil { + return nil, nil, err + } + if has { + col.IsAutoIncrement = true + } + + fmt.Println("-----", pkName, col.Name, col.IsPrimaryKey) + } + + var ( + ignore bool + dt string + len1, len2 int + ) dts := strings.Split(*dataType, "(") dt = dts[0] if len(dts) > 1 { @@ -721,6 +776,10 @@ func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableNam colSeq = append(colSeq, col.Name) } + /*select * + from user_tab_comments + where Table_Name='用户表' */ + return colSeq, cols, nil } diff --git a/integrations/engine_test.go b/integrations/engine_test.go index 0b792b71..646ddcdf 100644 --- a/integrations/engine_test.go +++ b/integrations/engine_test.go @@ -60,8 +60,7 @@ func TestAutoTransaction(t *testing.T) { engine.Transaction(func(session *xorm.Session) (interface{}, error) { _, err := session.Insert(TestTx{Msg: "hi"}) assert.NoError(t, err) - - return nil, nil + return nil, err }) has, err := engine.Exist(&TestTx{Msg: "hi"}) diff --git a/integrations/tests.go b/integrations/tests.go index c8219935..a4105257 100644 --- a/integrations/tests.go +++ b/integrations/tests.go @@ -146,13 +146,12 @@ func createEngine(dbType, connStr string) error { if err != nil { return err } - var tableNames = make([]interface{}, 0, len(tables)) for _, table := range tables { - tableNames = append(tableNames, table.Name) - } - if err = testEngine.DropTables(tableNames...); err != nil { - return err + if err = testEngine.DropTables(table); err != nil { + return err + } } + return nil } diff --git a/internal/statements/insert.go b/internal/statements/insert.go index 6cbbbeda..79182a63 100644 --- a/internal/statements/insert.go +++ b/internal/statements/insert.go @@ -59,6 +59,10 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) return "", nil, err } + if len(table.AutoIncrement) > 0 && statement.dialect.URI().DBType == schemas.ORACLE { + colNames = append(colNames, table.AutoIncrement) + } + if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames...), ","); err != nil { return "", nil, err } @@ -112,6 +116,16 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) return "", nil, err } + // Insert tablename (id) Values(seq_tablename.nextval) + if len(table.AutoIncrement) > 0 && statement.dialect.URI().DBType == schemas.ORACLE { + if _, err := buf.WriteString(","); err != nil { + return "", nil, err + } + if _, err := buf.WriteString("seq_" + tableName + ".nextval"); err != nil { + return "", nil, err + } + } + if len(exprs.Args) > 0 { if _, err := buf.WriteString(","); err != nil { return "", nil, err diff --git a/session_insert.go b/session_insert.go index 3ec4e93f..ffe47ef7 100644 --- a/session_insert.go +++ b/session_insert.go @@ -279,7 +279,9 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { if err := session.statement.SetRefBean(bean); err != nil { return 0, err } - if len(session.statement.TableName()) <= 0 { + + var tableName = session.statement.TableName() + if tableName == "" { return 0, ErrTableNotFound } @@ -293,7 +295,6 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { processor.BeforeInsert() } - var tableName = session.statement.TableName() table := session.statement.RefTable colNames, args, err := session.genInsertColumns(bean) @@ -355,19 +356,14 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } } - res, err := session.queryBytes("select seq_atable.currval from dual") + var id int64 + err = session.queryRow(fmt.Sprintf("select %s.currval from dual", tableName)).Scan(&id) if err != nil { - return 0, err - } - if len(res) < 1 { - return 0, errors.New("insert no error but not returned id") - } - - idByte := res[0][table.AutoIncrement] - id, err := strconv.ParseInt(string(idByte), 10, 64) - if err != nil || id <= 0 { return 1, err } + if id == 0 { + return 1, errors.New("insert no error but not returned id") + } aiValue, err := table.AutoIncrColumn().ValueOf(bean) if err != nil { diff --git a/session_schema.go b/session_schema.go index 9ccf8abe..7f02e453 100644 --- a/session_schema.go +++ b/session_schema.go @@ -131,8 +131,33 @@ func (session *Session) DropTable(beanOrTableName interface{}) error { } func (session *Session) dropTable(beanOrTableName interface{}) error { - tableName := session.engine.TableName(beanOrTableName) - sqlStr, checkIfExist := session.engine.dialect.DropTableSQL(session.engine.TableName(tableName, true)) + var tableName, autoIncrementCol string + switch beanOrTableName.(type) { + case *schemas.Table: + table := beanOrTableName.(*schemas.Table) + tableName = table.Name + if table.AutoIncrColumn() != nil { + autoIncrementCol = table.AutoIncrColumn().Name + } + case string: + tableName = beanOrTableName.(string) + default: + v := utils.ReflectValue(beanOrTableName) + table, err := session.engine.tagParser.ParseWithCache(v) + if err != nil { + return err + } + if session.statement.AltTableName != "" { + tableName = session.statement.AltTableName + } else { + tableName = table.Name + } + if table.AutoIncrColumn() != nil { + autoIncrementCol = table.AutoIncrColumn().Name + } + } + + sqlStrs, checkIfExist := session.engine.dialect.DropTableSQL(tableName, autoIncrementCol) if !checkIfExist { exist, err := session.engine.dialect.IsTableExist(session.getQueryer(), session.ctx, tableName) if err != nil { @@ -142,8 +167,11 @@ func (session *Session) dropTable(beanOrTableName interface{}) error { } if checkIfExist { - _, err := session.exec(sqlStr) - return err + for _, sqlStr := range sqlStrs { + if _, err := session.exec(sqlStr); err != nil { + return err + } + } } return nil } From 3c7daece76ab9ee97322db36b446d888c4e1ac7a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 9 Mar 2020 10:30:41 +0800 Subject: [PATCH 08/14] Fix quote --- dialects/oracle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dialects/oracle.go b/dialects/oracle.go index 3e8b8630..013de0b3 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -558,7 +558,7 @@ func (db *oracle) IsReserved(name string) bool { func (db *oracle) DropTableSQL(tableName, autoincrCol string) ([]string, bool) { var sqls = []string{ - fmt.Sprintf("DROP TABLE `%s`", tableName), + fmt.Sprintf("DROP TABLE %s", db.quoter.Quote(tableName)), } if autoincrCol != "" { sqls = append(sqls, fmt.Sprintf("DROP SEQUENCE %s", seqName(tableName))) From 095d7b9f3dbf7009e98badc0c632a1530a6a9fc7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 9 Mar 2020 17:37:13 +0800 Subject: [PATCH 09/14] Fix batch insert --- core/db_test.go | 1 - dialects/oracle.go | 8 ++++---- dialects/time.go | 6 +++++- session_insert.go | 17 ++++++++++++++--- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/core/db_test.go b/core/db_test.go index 777ab0ad..046b1e89 100644 --- a/core/db_test.go +++ b/core/db_test.go @@ -92,7 +92,6 @@ func BenchmarkOriQuery(b *testing.B) { if err != nil { b.Error(err) } - //fmt.Println(Id, Name, Title, Age, Alias, NickName) } rows.Close() } diff --git a/dialects/oracle.go b/dialects/oracle.go index 013de0b3..0c79489f 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -6,6 +6,7 @@ package dialects import ( "context" + "database/sql" "errors" "fmt" "net/url" @@ -658,6 +659,9 @@ func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableNam var pkName string err := queryer.QueryRowContext(ctx, s, tableName).Scan(&pkName) if err != nil { + if err == sql.ErrNoRows { + err = nil + } return nil, nil, err } @@ -715,8 +719,6 @@ func (db *oracle) GetColumns(queryer core.Queryer, ctx context.Context, tableNam if has { col.IsAutoIncrement = true } - - fmt.Println("-----", pkName, col.Name, col.IsPrimaryKey) } var ( @@ -888,8 +890,6 @@ func parseOracle(driverName, dataSourceName string) (*URI, error) { db.Passwd, _ = u.User.Password() } - fmt.Printf("%#v\n", db) - if db.DBName == "" { return nil, errors.New("dbname is empty") } diff --git a/dialects/time.go b/dialects/time.go index b0394745..d66dc8d5 100644 --- a/dialects/time.go +++ b/dialects/time.go @@ -17,7 +17,11 @@ func FormatTime(dialect Dialect, sqlTypeName string, t time.Time) (v interface{} s := t.Format("2006-01-02 15:04:05") // time.RFC3339 v = s[11:19] case schemas.Date: - v = t.Format("2006-01-02") + if dialect.URI().DBType == schemas.ORACLE { + v = t + } else { + v = t.Format("2006-01-02") + } case schemas.DateTime, schemas.TimeStamp, schemas.Varchar: // !DarthPestilane! format time when sqlTypeName is schemas.Varchar. v = t.Format("2006-01-02 15:04:05") case schemas.TimeStampz: diff --git a/session_insert.go b/session_insert.go index ffe47ef7..c1c8c608 100644 --- a/session_insert.go +++ b/session_insert.go @@ -150,6 +150,13 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error } fieldValue := *ptrFieldValue if col.IsAutoIncrement && utils.IsZero(fieldValue.Interface()) { + if session.engine.dialect.URI().DBType == schemas.ORACLE { + if i == 0 { + colNames = append(colNames, col.Name) + cols = append(cols, col) + } + colPlaces = append(colPlaces, "seq_"+tableName+".nextval") + } continue } if col.MapType == schemas.ONLYFROMDB { @@ -357,7 +364,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } var id int64 - err = session.queryRow(fmt.Sprintf("select %s.currval from dual", tableName)).Scan(&id) + err = session.queryRow(fmt.Sprintf("select seq_%s.currval from dual", tableName)).Scan(&id) if err != nil { return 1, err } @@ -536,10 +543,14 @@ func (session *Session) genInsertColumns(bean interface{}) ([]string, []interfac } } - if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ { + if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime { // if time is non-empty, then set to auto time val, t := session.engine.nowTime(col) - args = append(args, val) + if session.engine.dialect.URI().DBType == schemas.ORACLE { + args = append(args, t) + } else { + args = append(args, val) + } var colName = col.Name session.afterClosures = append(session.afterClosures, func(bean interface{}) { From 075293093828f220042205bab4f0e1aef0c7dad7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Mar 2020 17:28:31 +0800 Subject: [PATCH 10/14] Fix insert returnning id --- Makefile | 8 +-- go.sum | 1 + oracle_test.go => integrations/oracle_test.go | 2 +- internal/statements/insert.go | 59 +++++++-------- internal/statements/statement.go | 4 ++ session_insert.go | 71 ++++++------------- 6 files changed, 62 insertions(+), 83 deletions(-) rename oracle_test.go => integrations/oracle_test.go (91%) diff --git a/Makefile b/Makefile index 2fd48527..2551cb52 100644 --- a/Makefile +++ b/Makefile @@ -187,25 +187,25 @@ test-oracle: test-godror .PNONY: test-oci8 test-oci8: go-check - $(GO) test -v -race -tags=oracle -db=oci8 -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test $(INTEGRATION_PACKAGES) -v -race -tags=oracle -db=oci8 -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-oci8\#% test-oci8\#%: go-check - $(GO) test -v -race -run $* -tags=oracle -db=oci8 -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -tags=oracle -db=oci8 -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-godror test-godror: go-check - $(GO) test -v -race -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test $(INTEGRATION_PACKAGES) -v -race -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-godror\#% test-godror\#%: go-check - $(GO) test -v -race -run $* -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ + $(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic diff --git a/go.sum b/go.sum index 82d92c88..38567910 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-oci8 v0.0.4 h1:3h8d3VE8buPHoEcApdEoww7Gy3G0SWhwJ0UpniYxBJU= github.com/mattn/go-oci8 v0.0.4/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= diff --git a/oracle_test.go b/integrations/oracle_test.go similarity index 91% rename from oracle_test.go rename to integrations/oracle_test.go index ccebd965..56cd3b69 100644 --- a/oracle_test.go +++ b/integrations/oracle_test.go @@ -4,7 +4,7 @@ // +build oracle -package xorm +package integrations import ( _ "github.com/mattn/go-oci8" diff --git a/internal/statements/insert.go b/internal/statements/insert.go index 79182a63..3ebdc07d 100644 --- a/internal/statements/insert.go +++ b/internal/statements/insert.go @@ -25,7 +25,7 @@ func (statement *Statement) writeInsertOutput(buf *strings.Builder, table *schem } // GenInsertSQL generates insert beans SQL -func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) (string, []interface{}, error) { +func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) (*builder.BytesWriter, error) { var ( buf = builder.NewWriter() exprs = statement.ExprColumns @@ -34,29 +34,29 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) ) if _, err := buf.WriteString("INSERT INTO "); err != nil { - return "", nil, err + return nil, err } if err := statement.dialect.Quoter().QuoteTo(buf.Builder, tableName); err != nil { - return "", nil, err + return nil, err } if len(colNames) <= 0 { if statement.dialect.URI().DBType == schemas.MYSQL { if _, err := buf.WriteString(" VALUES ()"); err != nil { - return "", nil, err + return nil, err } } else { if err := statement.writeInsertOutput(buf.Builder, table); err != nil { - return "", nil, err + return nil, err } if _, err := buf.WriteString(" DEFAULT VALUES"); err != nil { - return "", nil, err + return nil, err } } } else { if _, err := buf.WriteString(" ("); err != nil { - return "", nil, err + return nil, err } if len(table.AutoIncrement) > 0 && statement.dialect.URI().DBType == schemas.ORACLE { @@ -64,94 +64,95 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) } if err := statement.dialect.Quoter().JoinWrite(buf.Builder, append(colNames, exprs.ColNames...), ","); err != nil { - return "", nil, err + return nil, err } if _, err := buf.WriteString(")"); err != nil { - return "", nil, err + return nil, err } if err := statement.writeInsertOutput(buf.Builder, table); err != nil { - return "", nil, err + return nil, err } if statement.Conds().IsValid() { if _, err := buf.WriteString(" SELECT "); err != nil { - return "", nil, err + return nil, err } if err := statement.WriteArgs(buf, args); err != nil { - return "", nil, err + return nil, err } if len(exprs.Args) > 0 { if _, err := buf.WriteString(","); err != nil { - return "", nil, err + return nil, err } } if err := exprs.WriteArgs(buf); err != nil { - return "", nil, err + return nil, err } if _, err := buf.WriteString(" FROM "); err != nil { - return "", nil, err + return nil, err } if err := statement.dialect.Quoter().QuoteTo(buf.Builder, tableName); err != nil { - return "", nil, err + return nil, err } if _, err := buf.WriteString(" WHERE "); err != nil { - return "", nil, err + return nil, err } if err := statement.Conds().WriteTo(buf); err != nil { - return "", nil, err + return nil, err } } else { if _, err := buf.WriteString(" VALUES ("); err != nil { - return "", nil, err + return nil, err } if err := statement.WriteArgs(buf, args); err != nil { - return "", nil, err + return nil, err } // Insert tablename (id) Values(seq_tablename.nextval) if len(table.AutoIncrement) > 0 && statement.dialect.URI().DBType == schemas.ORACLE { if _, err := buf.WriteString(","); err != nil { - return "", nil, err + return nil, err } if _, err := buf.WriteString("seq_" + tableName + ".nextval"); err != nil { - return "", nil, err + return nil, err } } if len(exprs.Args) > 0 { if _, err := buf.WriteString(","); err != nil { - return "", nil, err + return nil, err } } if err := exprs.WriteArgs(buf); err != nil { - return "", nil, err + return nil, err } if _, err := buf.WriteString(")"); err != nil { - return "", nil, err + return nil, err } } } - if len(table.AutoIncrement) > 0 && statement.dialect.URI().DBType == schemas.POSTGRES { + if len(table.AutoIncrement) > 0 && (statement.dialect.URI().DBType == schemas.POSTGRES || + statement.dialect.URI().DBType == schemas.ORACLE) { if _, err := buf.WriteString(" RETURNING "); err != nil { - return "", nil, err + return nil, err } if err := statement.dialect.Quoter().QuoteTo(buf.Builder, table.AutoIncrement); err != nil { - return "", nil, err + return nil, err } } - return buf.String(), buf.Args(), nil + return buf, nil } // GenInsertMapSQL generates insert map SQL diff --git a/internal/statements/statement.go b/internal/statements/statement.go index ed7bdaeb..f64fd085 100644 --- a/internal/statements/statement.go +++ b/internal/statements/statement.go @@ -90,6 +90,10 @@ func NewStatement(dialect dialects.Dialect, tagParser *tags.Parser, defaultTimeZ return statement } +func (statement *Statement) Dialect() dialects.Dialect { + return statement.dialect +} + func (statement *Statement) SetTableName(tableName string) { statement.tableName = tableName } diff --git a/session_insert.go b/session_insert.go index c1c8c608..77e36bed 100644 --- a/session_insert.go +++ b/session_insert.go @@ -309,7 +309,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { return 0, err } - sqlStr, args, err := session.statement.GenInsertSQL(colNames, args) + buf, err := session.statement.GenInsertSQL(colNames, args) if err != nil { return 0, err } @@ -342,51 +342,22 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { cleanupProcessorsClosures(&session.afterClosures) // cleanup after used } + var dialect = session.statement.Dialect() + // for postgres, many of them didn't implement lastInsertId, so we should // implemented it ourself. - if session.engine.dialect.URI().DBType == schemas.ORACLE && len(table.AutoIncrement) > 0 { - _, err := session.exec(sqlStr, args...) - if err != nil { - return 0, err - } - - defer handleAfterInsertProcessorFunc(bean) - - session.cacheInsert(tableName) - - if table.Version != "" && session.statement.CheckVersion { - verValue, err := table.VersionColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Errorf("%v", err) - } else if verValue.IsValid() && verValue.CanSet() { - session.incrVersionFieldValue(verValue) - } - } - + if len(table.AutoIncrement) > 0 && (dialect.URI().DBType == schemas.POSTGRES || + dialect.URI().DBType == schemas.MSSQL || + dialect.URI().DBType == schemas.ORACLE) { var id int64 - err = session.queryRow(fmt.Sprintf("select seq_%s.currval from dual", tableName)).Scan(&id) - if err != nil { - return 1, err - } - if id == 0 { - return 1, errors.New("insert no error but not returned id") + if dialect.URI().DBType == schemas.ORACLE { + if _, err := buf.WriteString(" INTO :var_name"); err != nil { + return 0, err + } + buf.Append(&id) } - aiValue, err := table.AutoIncrColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Errorf("%v", err) - } - - if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { - return 1, nil - } - - aiValue.Set(int64ToIntValue(id, aiValue.Type())) - - return 1, nil - } else if len(table.AutoIncrement) > 0 && (session.engine.dialect.URI().DBType == schemas.POSTGRES || - session.engine.dialect.URI().DBType == schemas.MSSQL) { - res, err := session.queryBytes(sqlStr, args...) + res, err := session.queryBytes(buf.String(), buf.Args()...) if err != nil { return 0, err @@ -404,14 +375,16 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } } - if len(res) < 1 { - return 0, errors.New("insert successfully but not returned id") - } + if dialect.URI().DBType != schemas.ORACLE { + if len(res) < 1 { + return 0, errors.New("insert successfully but not returned id") + } - idByte := res[0][table.AutoIncrement] - id, err := strconv.ParseInt(string(idByte), 10, 64) - if err != nil || id <= 0 { - return 1, err + idByte := res[0][table.AutoIncrement] + id, err = strconv.ParseInt(string(idByte), 10, 64) + if err != nil || id <= 0 { + return 1, err + } } aiValue, err := table.AutoIncrColumn().ValueOf(bean) @@ -428,7 +401,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { return 1, nil } - res, err := session.exec(sqlStr, args...) + res, err := session.exec(buf.String(), buf.Args()...) if err != nil { return 0, err } From 1891d89b6664ea71f8eb315b36a65f35d5f839de Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 27 Mar 2020 22:58:39 +0800 Subject: [PATCH 11/14] download instant client on Makefile --- Makefile | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 2551cb52..b513714b 100644 --- a/Makefile +++ b/Makefile @@ -130,6 +130,23 @@ misspell-check: fi misspell -error -i unknwon,destory $(GOFILES) +.PHONY: install-instant-client +install-instant-client: +ifeq ("$(PKG_CONFIG_PATH)", ) + wget https://download.oracle.com/otn_software/linux/instantclient/19600/instantclient-basic-linux.x64-19.6.0.0.0dbru.zip + unzip instantclient-basic-linux.x64-19.6.0.0.0dbru.zip -d /usr/local/instantclient + echo "prefixdir=/usr/local/instantclient +libdir=${prefixdir} +includedir=${prefixdir}/sdk/include + +Name: OCI +Description: Oracle database driver +Version: 11.2 +Libs: -L${libdir} -lclntsh +Cflags: -I${includedir}" > /usr/local/instantclient/oci8.pc +export PKG_CONFIG_PATH=/usr/local/instantclient/oci8.pc +endif + .PHONY: test test: go-check $(GO) test $(PACKAGES) @@ -186,25 +203,25 @@ test-mysql\#%: go-check test-oracle: test-godror .PNONY: test-oci8 -test-oci8: go-check +test-oci8: go-check install-instant-client $(GO) test $(INTEGRATION_PACKAGES) -v -race -tags=oracle -db=oci8 -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-oci8\#% -test-oci8\#%: go-check +test-oci8\#%: go-check install-instant-client $(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -tags=oracle -db=oci8 -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-godror -test-godror: go-check +test-godror: go-check install-instant-client $(GO) test $(INTEGRATION_PACKAGES) -v -race -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic .PHONY: test-godror\#% -test-godror\#%: go-check +test-godror\#%: go-check install-instant-client $(GO) test $(INTEGRATION_PACKAGES) -v -race -run $* -tags=oracle -db=godror -schema='$(TEST_ORACLE_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \ -conn_str="oracle://$(TEST_ORACLE_USERNAME):$(TEST_ORACLE_PASSWORD)@$(TEST_ORACLE_HOST)/$(TEST_ORACLE_DBNAME)" \ -coverprofile=oracle.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic From 92c475925dcf4128817973521d434e813a898b46 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 12 Apr 2020 20:39:30 +0800 Subject: [PATCH 12/14] Fix batch insert --- integrations/session_cond_test.go | 28 ++++++++++++++-------------- session_insert.go | 4 +++- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/integrations/session_cond_test.go b/integrations/session_cond_test.go index a0a91cad..493f914c 100644 --- a/integrations/session_cond_test.go +++ b/integrations/session_cond_test.go @@ -37,62 +37,62 @@ func TestBuilder(t *testing.T) { assert.NoError(t, err) var cond Condition - has, err := testEngine.Where(builder.Eq{"col_name": "col1"}).Get(&cond) + has, err := testEngine.Where(builder.Eq{"`col_name`": "col1"}).Get(&cond) assert.NoError(t, err) assert.Equal(t, true, has, "records should exist") - has, err = testEngine.Where(builder.Eq{"col_name": "col1"}. - And(builder.Eq{"op": OpEqual})). + has, err = testEngine.Where(builder.Eq{"`col_name`": "col1"}. + And(builder.Eq{"`op`": OpEqual})). NoAutoCondition(). Get(&cond) assert.NoError(t, err) assert.Equal(t, true, has, "records should exist") - has, err = testEngine.Where(builder.Eq{"col_name": "col1", "op": OpEqual, "value": "1"}). + has, err = testEngine.Where(builder.Eq{"`col_name`": "col1", "`op`": OpEqual, "`value`": "1"}). NoAutoCondition(). Get(&cond) assert.NoError(t, err) assert.Equal(t, true, has, "records should exist") - has, err = testEngine.Where(builder.Eq{"col_name": "col1"}. - And(builder.Neq{"op": OpEqual})). + has, err = testEngine.Where(builder.Eq{"`col_name`": "col1"}. + And(builder.Neq{"`op`": OpEqual})). NoAutoCondition(). Get(&cond) assert.NoError(t, err) assert.Equal(t, false, has, "records should not exist") var conds []Condition - err = testEngine.Where(builder.Eq{"col_name": "col1"}. - And(builder.Eq{"op": OpEqual})). + err = testEngine.Where(builder.Eq{"`col_name`": "col1"}. + And(builder.Eq{"`op`": OpEqual})). Find(&conds) assert.NoError(t, err) assert.EqualValues(t, 1, len(conds), "records should exist") conds = make([]Condition, 0) - err = testEngine.Where(builder.Like{"col_name", "col"}).Find(&conds) + err = testEngine.Where(builder.Like{"`col_name`", "col"}).Find(&conds) assert.NoError(t, err) assert.EqualValues(t, 1, len(conds), "records should exist") conds = make([]Condition, 0) - err = testEngine.Where(builder.Expr("col_name = ?", "col1")).Find(&conds) + err = testEngine.Where(builder.Expr("`col_name` = ?", "col1")).Find(&conds) assert.NoError(t, err) assert.EqualValues(t, 1, len(conds), "records should exist") conds = make([]Condition, 0) - err = testEngine.Where(builder.In("col_name", "col1", "col2")).Find(&conds) + err = testEngine.Where(builder.In("`col_name`", "col1", "col2")).Find(&conds) assert.NoError(t, err) assert.EqualValues(t, 1, len(conds), "records should exist") conds = make([]Condition, 0) - err = testEngine.NotIn("col_name", "col1", "col2").Find(&conds) + err = testEngine.NotIn("`col_name`", "col1", "col2").Find(&conds) assert.NoError(t, err) assert.EqualValues(t, 0, len(conds), "records should not exist") // complex condtions var where = builder.NewCond() if true { - where = where.And(builder.Eq{"col_name": "col1"}) - where = where.Or(builder.And(builder.In("col_name", "col1", "col2"), builder.Expr("col_name = ?", "col1"))) + where = where.And(builder.Eq{"`col_name`": "col1"}) + where = where.Or(builder.And(builder.In("`col_name`", "col1", "col2"), builder.Expr("`col_name` = ?", "col1"))) } conds = make([]Condition, 0) diff --git a/session_insert.go b/session_insert.go index 77e36bed..a991cac8 100644 --- a/session_insert.go +++ b/session_insert.go @@ -118,6 +118,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error colMultiPlaces []string args []interface{} cols []*schemas.Column + insertCnt int ) for i := 0; i < size; i++ { @@ -155,7 +156,8 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error colNames = append(colNames, col.Name) cols = append(cols, col) } - colPlaces = append(colPlaces, "seq_"+tableName+".nextval") + colPlaces = append(colPlaces, fmt.Sprintf("seq_"+tableName+".nextval + %d", insertCnt)) + insertCnt++ } continue } From eda3b5341896ea31f25592b38fb946f39f752c1f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 Apr 2020 15:19:41 +0800 Subject: [PATCH 13/14] Fix insert --- README.md | 5 +++-- dialects/oracle.go | 23 ++++++++++++++++++++++- internal/statements/insert.go | 10 +++++++--- session_insert.go | 4 +++- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a15be488..5681740d 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,9 @@ Drivers for Go's sql package which currently support database/sql includes: * MsSql - [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) -* Oracle - - [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment) +* Oracle (experiment) + - [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) + - [github.com/godror/godror](https://github.com/godror/godror) ## Installation diff --git a/dialects/oracle.go b/dialects/oracle.go index 0c79489f..4c6035e6 100644 --- a/dialects/oracle.go +++ b/dialects/oracle.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "net/url" + "regexp" "strconv" "strings" @@ -867,10 +868,30 @@ func (db *oracle) Filters() []Filter { type godrorDriver struct { } +func parseNoProtocol(driverName, dataSourceName string) (*URI, error) { + db := &URI{DBType: schemas.ORACLE} + dsnPattern := regexp.MustCompile( + `^(?P.*)\/(?P.*)@` + // user:password@ + `(?P.*)` + // ip:port + `\/(?P.*)`) // dbname + matches := dsnPattern.FindStringSubmatch(dataSourceName) + names := dsnPattern.SubexpNames() + for i, match := range matches { + switch names[i] { + case "dbname": + db.DBName = match + } + } + if db.DBName == "" && len(matches) != 0 { + return nil, errors.New("dbname is empty") + } + return db, nil +} + func parseOracle(driverName, dataSourceName string) (*URI, error) { var connStr = dataSourceName if !strings.HasPrefix(connStr, "oracle://") { - connStr = fmt.Sprintf("oracle://%s", connStr) + return parseNoProtocol(driverName, dataSourceName) } u, err := url.Parse(connStr) diff --git a/internal/statements/insert.go b/internal/statements/insert.go index 3ebdc07d..7e894ae2 100644 --- a/internal/statements/insert.go +++ b/internal/statements/insert.go @@ -41,7 +41,9 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) return nil, err } - if len(colNames) <= 0 { + var hasInsertColumns = len(colNames) > 0 + + if !hasInsertColumns && statement.dialect.URI().DBType != schemas.ORACLE { if statement.dialect.URI().DBType == schemas.MYSQL { if _, err := buf.WriteString(" VALUES ()"); err != nil { return nil, err @@ -118,8 +120,10 @@ func (statement *Statement) GenInsertSQL(colNames []string, args []interface{}) // Insert tablename (id) Values(seq_tablename.nextval) if len(table.AutoIncrement) > 0 && statement.dialect.URI().DBType == schemas.ORACLE { - if _, err := buf.WriteString(","); err != nil { - return nil, err + if hasInsertColumns { + if _, err := buf.WriteString(","); err != nil { + return nil, err + } } if _, err := buf.WriteString("seq_" + tableName + ".nextval"); err != nil { return nil, err diff --git a/session_insert.go b/session_insert.go index a991cac8..41f5e781 100644 --- a/session_insert.go +++ b/session_insert.go @@ -360,10 +360,12 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { } res, err := session.queryBytes(buf.String(), buf.Args()...) - if err != nil { return 0, err } + + fmt.Println("=====", id) + defer handleAfterInsertProcessorFunc(bean) session.cacheInsert(tableName) From a9510897037bab12ba7929424991b7e01aa0a5ce Mon Sep 17 00:00:00 2001 From: chendy Date: Wed, 27 May 2020 11:58:07 +0800 Subject: [PATCH 14/14] fix invalid date when update --- session_update.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/session_update.go b/session_update.go index 62116c47..7df8c752 100644 --- a/session_update.go +++ b/session_update.go @@ -206,7 +206,11 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?") col := table.UpdatedColumn() val, t := session.engine.nowTime(col) - args = append(args, val) + if session.engine.dialect.URI().DBType == schemas.ORACLE { + args = append(args, t) + } else { + args = append(args, val) + } var colName = col.Name if isStruct {