Feature/oracle (#1869)

This commit is contained in:
wenzi 2022-05-25 21:55:27 +08:00 committed by GitHub
parent 0ca81bd11a
commit ef04c8a09e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 2052 additions and 56 deletions

View File

@ -97,10 +97,23 @@ jobs:
- 8090:8090
- 8091:8091
#oracle 11g server
oracle-server:
image: loads/oracle-xe-11g-r2:latest
env:
ORACLE_ALLOW_REMOTE: true
ORACLE_SID: XE
ORACLE_DB_USER_NAME: system
ORACLE_DB_PASSWORD: oracle
ports:
- 1521:1521
strategy:
matrix:
go: ["1.15", "1.16", "1.17"]
goarch: ["386", "amd64"]
go: [ "1.15", "1.16", "1.17" ]
goarch: [ "386", "amd64" ]
steps:
@ -131,7 +144,9 @@ jobs:
dirpath=$(dirname $file)
if [ "oracle" = $(basename $dirpath) ]; then
continue 1
if ! go version|grep -q "1.17"; then
continue 1
fi
fi
cd $dirpath

View File

@ -299,6 +299,7 @@ ORDER BY a.id,a.colorder`,
}
fields = make(map[string]*gdb.TableField)
for i, m := range result {
fields[m["Field"].String()] = &gdb.TableField{
Index: i,
Name: m["Field"].String(),

View File

@ -63,32 +63,42 @@ func TestTableFields(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
createTable("t_user")
defer dropTable("t_user")
var expect map[string]string = map[string]string{
"ID": "numeric(10,0)",
"PASSPORT": "VARCHAR(45)",
"PASSWORD": "CHAR(32)",
"NICKNAME": "VARCHAR(45)",
"CREATE_TIME": "time",
var expect = map[string][]interface{}{
"ID": {"numeric(10,0)", false, "PRI", "", "", ""},
"PASSPORT": {"varchar(45)", true, "", "", "", ""},
"PASSWORD": {"varchar(32)", true, "", "", "", ""},
"NICKNAME": {"varchar(45)", true, "", "", "", ""},
"CREATE_TIME": {"datetime", true, "", "", "", ""},
}
res, err := db.TableFields(context.Background(), "t_user")
gtest.Assert(err, nil)
for k, _ := range expect {
for k, v := range expect {
_, ok := res[k]
gtest.AssertEQ(ok, true)
gtest.AssertEQ(res[k].Name, k)
gtest.AssertEQ(res[k].Type, v[0])
gtest.AssertEQ(res[k].Null, v[1])
gtest.AssertEQ(res[k].Key, v[2])
gtest.AssertEQ(res[k].Default, v[3])
gtest.AssertEQ(res[k].Extra, v[4])
gtest.AssertEQ(res[k].Comment, v[5])
}
res, err = db.TableFields(context.Background(), "t_user", "test")
gtest.Assert(err, nil)
for k, _ := range expect {
for k, v := range expect {
_, ok := res[k]
gtest.AssertEQ(ok, true)
gtest.AssertEQ(res[k].Name, k)
gtest.AssertEQ(res[k].Type, v[0])
gtest.AssertEQ(res[k].Null, v[1])
gtest.AssertEQ(res[k].Key, v[2])
gtest.AssertEQ(res[k].Default, v[3])
gtest.AssertEQ(res[k].Extra, v[4])
gtest.AssertEQ(res[k].Comment, v[5])
}
})

View File

@ -1,10 +1,36 @@
module github.com/gogf/gf/contrib/drivers/oracle/v2
go 1.15
go 1.17
require (
github.com/gogf/gf/v2 v2.0.0
github.com/mattn/go-oci8 v0.1.1
github.com/sijms/go-ora/v2 v2.4.20
)
require (
github.com/BurntSushi/toml v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
replace github.com/gogf/gf/v2 => ../../../

View File

@ -34,7 +34,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -56,8 +55,6 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-oci8 v0.1.1 h1:aEUDxNAyDG0tv8CA3TArnDQNyc4EhnWlsfxRgDHABHM=
github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@ -70,7 +67,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
@ -79,6 +75,8 @@ github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sijms/go-ora/v2 v2.4.20 h1:9e3z7VLBQXRAHGiIda1GEFtRhfxata0LghyMZqvLKew=
github.com/sijms/go-ora/v2 v2.4.20/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
@ -142,7 +140,6 @@ golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -151,7 +148,6 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -5,7 +5,7 @@
// You can obtain one at https://github.com/gogf/gf.
//
// Note:
// 1. It needs manually import: _ "github.com/mattn/go-oci8"
// 1. It needs manually import: _ "github.com/sijms/go-ora/v2"
// 2. It does not support Save/Replace features.
// 3. It does not support LastInsertId.
@ -16,12 +16,7 @@ import (
"context"
"database/sql"
"fmt"
"reflect"
"strconv"
"strings"
"time"
_ "github.com/mattn/go-oci8"
gora "github.com/sijms/go-ora/v2"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/database/gdb"
@ -30,6 +25,8 @@ import (
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"strconv"
"strings"
)
// Driver is the driver for oracle database.
@ -65,9 +62,18 @@ func (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {
func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {
var (
source string
underlyingDriverName = "oci8"
underlyingDriverName = "oracle"
)
// [username/[password]@]host[:port][/service_name][?param1=value1&...&paramN=valueN]
options := map[string]string{
"CONNECTION TIMEOUT": "60",
"PREFETCH_ROWS": "25",
}
if config.Debug {
options["TRACE FILE"] = "oracle_trace.log"
}
// [username:[password]@]host[:port][/service_name][?param1=value1&...&paramN=valueN]
if config.Link != "" {
source = config.Link
// Custom changing the schema in runtime.
@ -75,10 +81,7 @@ func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {
source, _ = gregex.ReplaceString(`@(.+?)/([\w\.\-]+)+`, "@$1/"+config.Name, source)
}
} else {
source = fmt.Sprintf(
"%s/%s@%s:%s/%s",
config.User, config.Pass, config.Host, config.Port, config.Name,
)
source = gora.BuildUrl(config.Host, gconv.Int(config.Port), config.Name, config.User, config.Pass, options)
}
if db, err = sql.Open(underlyingDriverName, source); err != nil {
@ -99,8 +102,8 @@ func (d *Driver) FilteredLink() string {
return ""
}
s, _ := gregex.ReplaceString(
`(.+?)\s*/\s*(.+)\s*@\s*(.+)\s*:\s*(\d+)\s*/\s*(.+)`,
`$1/xxx@$3:$4/$5`,
`(.+?)\s*:\s*(.+)\s*@\s*(.+)\s*:\s*(\d+)\s*/\s*(.+)`,
`$1:xxx@$3:$4/$5`,
linkInfo,
)
return s
@ -124,16 +127,7 @@ func (d *Driver) DoFilter(ctx context.Context, link gdb.Link, sql string, args [
return fmt.Sprintf(":v%d", index)
})
newSql, _ = gregex.ReplaceString("\"", "", newSql)
// Handle string datetime argument.
for i, v := range args {
if reflect.TypeOf(v).Kind() == reflect.String {
valueStr := gconv.String(v)
if gregex.IsMatchString(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$`, valueStr) {
// args[i] = fmt.Sprintf(`TO_DATE('%s','yyyy-MM-dd HH:MI:SS')`, valueStr)
args[i], _ = time.ParseInLocation("2006-01-02 15:04:05", valueStr, time.Local)
}
}
}
newSql = d.parseSql(newSql)
newArgs = args
return
@ -168,7 +162,7 @@ func (d *Driver) parseSql(sql string) string {
strings.EqualFold(queryExpr[3], "LIMIT") == false {
break
}
first, limit := 0, 0
page, limit := 0, 0
for i := 1; i < len(allMatch[index]); i++ {
if len(strings.TrimSpace(allMatch[index][i])) == 0 {
continue
@ -176,8 +170,16 @@ func (d *Driver) parseSql(sql string) string {
if strings.HasPrefix(allMatch[index][i], "LIMIT") {
if allMatch[index][i+2] != "" {
first, _ = strconv.Atoi(allMatch[index][i+1])
page, _ = strconv.Atoi(allMatch[index][i+1])
limit, _ = strconv.Atoi(allMatch[index][i+2])
if page <= 0 {
page = 1
}
limit = (page/limit + 1) * limit
page, _ = strconv.Atoi(allMatch[index][i+1])
} else {
limit, _ = strconv.Atoi(allMatch[index][i+1])
}
@ -187,8 +189,8 @@ func (d *Driver) parseSql(sql string) string {
sql = fmt.Sprintf(
"SELECT * FROM "+
"(SELECT GFORM.*, ROWNUM ROWNUM_ FROM (%s %s) GFORM WHERE ROWNUM <= %d)"+
" WHERE ROWNUM_ >= %d",
queryExpr[1], queryExpr[2], limit, first,
" WHERE ROWNUM_ > %d",
queryExpr[1], queryExpr[2], limit, page,
)
}
return sql
@ -241,7 +243,7 @@ SELECT
CASE DATA_TYPE
WHEN 'NUMBER' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
WHEN 'FLOAT' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
ELSE DATA_TYPE||'('||DATA_LENGTH||')' END AS TYPE
ELSE DATA_TYPE||'('||DATA_LENGTH||')' END AS TYPE,NULLABLE
FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`,
strings.ToUpper(table),
)
@ -256,10 +258,16 @@ FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`,
}
fields = make(map[string]*gdb.TableField)
for i, m := range result {
fields[strings.ToLower(m["FIELD"].String())] = &gdb.TableField{
isNull := false
if m["NULLABLE"].String() == "Y" {
isNull = true
}
fields[m["FIELD"].String()] = &gdb.TableField{
Index: i,
Name: strings.ToLower(m["FIELD"].String()),
Type: strings.ToLower(m["TYPE"].String()),
Name: m["FIELD"].String(),
Type: m["TYPE"].String(),
Null: isNull,
}
}
return fields
@ -288,10 +296,10 @@ func (d *Driver) DoInsert(
) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionSave:
return nil, gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by mssql driver`)
return nil, gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by oracle driver`)
case gdb.InsertOptionReplace:
return nil, gerror.NewCode(gcode.CodeNotSupported, `Replace operation is not supported by mssql driver`)
return nil, gerror.NewCode(gcode.CodeNotSupported, `Replace operation is not supported by oracle driver`)
}
var (

View File

@ -0,0 +1,162 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package oracle_test
import (
"context"
"fmt"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/test/gtest"
_ "github.com/sijms/go-ora/v2"
"strings"
)
var (
db gdb.DB
dblink gdb.DB
dbErr gdb.DB
ctx context.Context
)
const (
TableSize = 10
TableName = "t_user"
TestSchema1 = "test1"
TestSchema2 = "test2"
TableNamePrefix1 = "gf_"
TestSchema = "XE"
)
const (
TestDbIP = "127.0.0.1"
TestDbPort = "1521"
TestDbUser = "system"
TestDbPass = "oracle"
TestDbName = "XE"
TestDbType = "oracle"
)
func init() {
node := gdb.ConfigNode{
Host: TestDbIP,
Port: TestDbPort,
User: TestDbUser,
Pass: TestDbPass,
Name: TestDbName,
Type: TestDbType,
Role: "master",
Charset: "utf8",
Weight: 1,
MaxIdleConnCount: 10,
MaxOpenConnCount: 10,
}
nodeLink := gdb.ConfigNode{
Type: TestDbType,
Name: TestDbName,
Link: fmt.Sprintf("%s://%s:%s@%s:%s/%s",
TestDbType, TestDbUser, TestDbPass, TestDbIP, TestDbPort, TestDbName),
}
nodeErr := gdb.ConfigNode{
Host: TestDbIP,
Port: TestDbPort,
User: TestDbUser,
Pass: "1234",
Name: TestDbName,
Type: TestDbType,
Role: "master",
Charset: "utf8",
Weight: 1,
}
gdb.AddConfigNode(gdb.DefaultGroupName, node)
if r, err := gdb.New(node); err != nil {
gtest.Fatal(err)
} else {
db = r
}
gdb.AddConfigNode("dblink", nodeLink)
if r, err := gdb.New(nodeLink); err != nil {
gtest.Fatal(err)
} else {
dblink = r
}
gdb.AddConfigNode("dbErr", nodeErr)
if r, err := gdb.New(nodeErr); err != nil {
gtest.Fatal(err)
} else {
dbErr = r
}
ctx = context.Background()
}
func createTable(table ...string) (name string) {
if len(table) > 0 {
name = table[0]
} else {
name = fmt.Sprintf("user_%d", gtime.Timestamp())
}
dropTable(name)
if _, err := db.Exec(ctx, fmt.Sprintf(`
CREATE TABLE %s (
ID NUMBER(10) NOT NULL,
PASSPORT VARCHAR(45) NOT NULL,
PASSWORD CHAR(32) NOT NULL,
NICKNAME VARCHAR(45) NOT NULL,
CREATE_TIME varchar(45),
PRIMARY KEY (ID))
`, name)); err != nil {
gtest.Fatal(err)
}
//db.Schema("test")
return
}
func createInitTable(table ...string) (name string) {
name = createTable(table...)
array := garray.New(true)
for i := 1; i <= TableSize; i++ {
array.Append(g.Map{
"id": i,
"passport": fmt.Sprintf(`user_%d`, i),
"password": fmt.Sprintf(`pass_%d`, i),
"nickname": fmt.Sprintf(`name_%d`, i),
"create_time": gtime.Now().String(),
})
}
result, err := db.Insert(context.Background(), name, array.Slice())
gtest.Assert(err, nil)
n, e := result.RowsAffected()
gtest.Assert(e, nil)
gtest.Assert(n, TableSize)
return
}
func dropTable(table string) {
count, err := db.GetCount(ctx, "SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = ?", strings.ToUpper(table))
if err != nil {
gtest.Fatal(err)
}
if count == 0 {
return
}
if _, err := db.Exec(ctx, fmt.Sprintf("DROP TABLE %s", table)); err != nil {
gtest.Fatal(err)
}
}

View File

@ -0,0 +1,665 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package oracle_test
import (
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/test/gtest"
"strings"
"testing"
)
func TestTables(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
tables := []string{"t_user1", "pop", "haha"}
for _, v := range tables {
createTable(v)
}
result, err := db.Tables(ctx)
gtest.Assert(err, nil)
for i := 0; i < len(tables); i++ {
find := false
for j := 0; j < len(result); j++ {
if strings.ToUpper(tables[i]) == result[j] {
find = true
break
}
}
gtest.AssertEQ(find, true)
}
result, err = db.Tables(ctx, TestSchema)
gtest.Assert(err, nil)
for i := 0; i < len(tables); i++ {
find := false
for j := 0; j < len(result); j++ {
if strings.ToUpper(tables[i]) == result[j] {
find = true
break
}
}
gtest.AssertEQ(find, true)
}
for _, v := range tables {
dropTable(v)
}
})
}
func TestTableFields(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
createTable("t_user")
defer dropTable("t_user")
var expect = map[string][]interface{}{
"ID": {"NUMBER(10,0)", false},
"PASSPORT": {"VARCHAR2(45)", false},
"PASSWORD": {"CHAR(32)", false},
"NICKNAME": {"VARCHAR2(45)", false},
"CREATE_TIME": {"VARCHAR2(45)", true},
}
_, err := dbErr.TableFields(ctx, "t_user")
gtest.AssertNE(err, nil)
res, err := db.TableFields(ctx, "t_user")
gtest.Assert(err, nil)
for k, v := range expect {
_, ok := res[k]
gtest.AssertEQ(ok, true)
gtest.AssertEQ(res[k].Name, k)
gtest.Assert(res[k].Type, v[0])
gtest.Assert(res[k].Null, v[1])
}
res, err = db.TableFields(ctx, "t_user", TestSchema)
gtest.Assert(err, nil)
for k, v := range expect {
_, ok := res[k]
gtest.AssertEQ(ok, true)
gtest.AssertEQ(res[k].Name, k)
gtest.Assert(res[k].Type, v[0])
gtest.Assert(res[k].Null, v[1])
}
})
gtest.C(t, func(t *gtest.T) {
_, err := db.TableFields(ctx, "t_user t_user2")
gtest.AssertNE(err, nil)
})
}
func TestFilteredLink(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := dblink.FilteredLink()
gtest.AssertEQ(s, "oracle:xxx@127.0.0.1:1521/XE")
})
}
func TestDoInsert(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
createTable("t_user")
defer dropTable("t_user")
i := 10
data := g.Map{
"ID": i,
"PASSPORT": fmt.Sprintf(`t%d`, i),
"PASSWORD": fmt.Sprintf(`p%d`, i),
"NICKNAME": fmt.Sprintf(`T%d`, i),
"CREATE_TIME": gtime.Now().String(),
}
_, err := db.Insert(ctx, "t_user", data)
gtest.Assert(err, nil)
})
gtest.C(t, func(t *gtest.T) {
createTable("t_user")
defer dropTable("t_user")
i := 10
data := g.Map{
"ID": i,
"PASSPORT": fmt.Sprintf(`t%d`, i),
"PASSWORD": fmt.Sprintf(`p%d`, i),
"NICKNAME": fmt.Sprintf(`T%d`, i),
"CREATE_TIME": gtime.Now().String(),
}
_, err := db.Save(ctx, "t_user", data, 10)
gtest.AssertNE(err, nil)
_, err = db.Replace(ctx, "t_user", data, 10)
gtest.AssertNE(err, nil)
})
}
func Test_DB_Ping(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
err1 := db.PingMaster()
err2 := db.PingSlave()
t.Assert(err1, nil)
t.Assert(err2, nil)
})
}
func Test_DB_Query(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
_, err := db.Query(ctx, "SELECT ? from dual", 1)
t.AssertNil(err)
_, err = db.Query(ctx, "SELECT ?+? from dual", 1, 2)
t.AssertNil(err)
_, err = db.Query(ctx, "SELECT ?+? from dual", g.Slice{1, 2})
t.AssertNil(err)
_, err = db.Query(ctx, "ERROR")
t.AssertNE(err, nil)
})
}
func Test_DB_Exec(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
_, err := db.Exec(ctx, "SELECT ? from dual", 1)
t.AssertNil(err)
_, err = db.Exec(ctx, "ERROR")
t.AssertNE(err, nil)
})
}
func Test_DB_Insert(t *testing.T) {
table := createTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
_, err := db.Insert(ctx, table, g.Map{
"ID": 1,
"PASSPORT": "t1",
"PASSWORD": "25d55ad283aa400af464c76d713c07ad",
"NICKNAME": "T1",
"CREATE_TIME": gtime.Now().String(),
})
t.AssertNil(err)
// normal map
result, err := db.Insert(ctx, table, g.Map{
"ID": "2",
"PASSPORT": "t2",
"PASSWORD": "25d55ad283aa400af464c76d713c07ad",
"NICKNAME": "name_2",
"CREATE_TIME": gtime.Now().String(),
})
t.AssertNil(err)
n, _ := result.RowsAffected()
t.Assert(n, 1)
// struct
type User struct {
Id int `gconv:"ID"`
Passport string `json:"PASSPORT"`
Password string `gconv:"PASSWORD"`
Nickname string `gconv:"NICKNAME"`
CreateTime string `json:"CREATE_TIME"`
}
timeStr := gtime.Now().String()
result, err = db.Insert(ctx, table, User{
Id: 3,
Passport: "user_3",
Password: "25d55ad283aa400af464c76d713c07ad",
Nickname: "name_3",
CreateTime: timeStr,
})
t.AssertNil(err)
n, _ = result.RowsAffected()
t.Assert(n, 1)
one, err := db.Model(table).Where("ID", 3).One()
t.AssertNil(err)
fmt.Println(one)
t.Assert(one["ID"].Int(), 3)
t.Assert(one["PASSPORT"].String(), "user_3")
t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d713c07ad")
t.Assert(one["NICKNAME"].String(), "name_3")
t.Assert(one["CREATE_TIME"].GTime().String(), timeStr)
// *struct
timeStr = gtime.Now().String()
result, err = db.Insert(ctx, table, &User{
Id: 4,
Passport: "t4",
Password: "25d55ad283aa400af464c76d713c07ad",
Nickname: "name_4",
CreateTime: timeStr,
})
t.AssertNil(err)
n, _ = result.RowsAffected()
t.Assert(n, 1)
one, err = db.Model(table).Where("ID", 4).One()
t.AssertNil(err)
t.Assert(one["ID"].Int(), 4)
t.Assert(one["PASSPORT"].String(), "t4")
t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d713c07ad")
t.Assert(one["NICKNAME"].String(), "name_4")
t.Assert(one["CREATE_TIME"].GTime().String(), timeStr)
// batch with Insert
timeStr = gtime.Now().String()
r, err := db.Insert(ctx, table, g.Slice{
g.Map{
"ID": 200,
"PASSPORT": "t200",
"PASSWORD": "25d55ad283aa400af464c76d71qw07ad",
"NICKNAME": "T200",
"CREATE_TIME": timeStr,
},
g.Map{
"ID": 300,
"PASSPORT": "t300",
"PASSWORD": "25d55ad283aa400af464c76d713c07ad",
"NICKNAME": "T300",
"CREATE_TIME": timeStr,
},
})
t.AssertNil(err)
n, _ = r.RowsAffected()
t.Assert(n, 2)
one, err = db.Model(table).Where("ID", 200).One()
t.AssertNil(err)
t.Assert(one["ID"].Int(), 200)
t.Assert(one["PASSPORT"].String(), "t200")
t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d71qw07ad")
t.Assert(one["NICKNAME"].String(), "T200")
t.Assert(one["CREATE_TIME"].GTime().String(), timeStr)
})
}
func Test_DB_BatchInsert(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
table := createTable()
defer dropTable(table)
r, err := db.Insert(ctx, table, g.List{
{
"ID": 2,
"PASSPORT": "t2",
"PASSWORD": "25d55ad283aa400af464c76d713c07ad",
"NICKNAME": "name_2",
"CREATE_TIME": gtime.Now().String(),
},
{
"ID": 3,
"PASSPORT": "user_3",
"PASSWORD": "25d55ad283aa400af464c76d713c07ad",
"NICKNAME": "name_3",
"CREATE_TIME": gtime.Now().String(),
},
}, 1)
t.AssertNil(err)
n, _ := r.RowsAffected()
t.Assert(n, 2)
})
gtest.C(t, func(t *gtest.T) {
table := createTable()
defer dropTable(table)
// []interface{}
r, err := db.Insert(ctx, table, g.Slice{
g.Map{
"ID": 2,
"PASSPORT": "t2",
"PASSWORD": "25d55ad283aa400af464c76d713c07ad",
"NICKNAME": "name_2",
"CREATE_TIME": gtime.Now().String(),
},
g.Map{
"ID": 3,
"PASSPORT": "user_3",
"PASSWORD": "25d55ad283aa400af464c76d713c07ad",
"NICKNAME": "name_3",
"CREATE_TIME": gtime.Now().String(),
},
}, 1)
t.AssertNil(err)
n, _ := r.RowsAffected()
t.Assert(n, 2)
})
// batch insert map
gtest.C(t, func(t *gtest.T) {
table := createTable()
defer dropTable(table)
result, err := db.Insert(ctx, table, g.Map{
"ID": 1,
"PASSPORT": "t1",
"PASSWORD": "p1",
"NICKNAME": "T1",
"CREATE_TIME": gtime.Now().String(),
})
t.AssertNil(err)
n, _ := result.RowsAffected()
t.Assert(n, 1)
})
}
func Test_DB_BatchInsert_Struct(t *testing.T) {
// batch insert struct
gtest.C(t, func(t *gtest.T) {
table := createTable()
defer dropTable(table)
type User struct {
Id int `c:"ID"`
Passport string `c:"PASSPORT"`
Password string `c:"PASSWORD"`
NickName string `c:"NICKNAME"`
CreateTime *gtime.Time `c:"CREATE_TIME"`
}
user := &User{
Id: 1,
Passport: "t1",
Password: "p1",
NickName: "T1",
CreateTime: gtime.Now(),
}
result, err := db.Insert(ctx, table, user)
t.AssertNil(err)
n, _ := result.RowsAffected()
t.Assert(n, 1)
})
}
func Test_DB_Update(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
result, err := db.Update(ctx, table, "password='987654321'", "id=3")
t.AssertNil(err)
n, _ := result.RowsAffected()
t.Assert(n, 1)
one, err := db.Model(table).Where("ID", 3).One()
t.AssertNil(err)
t.Assert(one["ID"].Int(), 3)
t.Assert(one["PASSPORT"].String(), "user_3")
t.Assert(strings.TrimSpace(one["PASSWORD"].String()), "987654321")
t.Assert(one["NICKNAME"].String(), "name_3")
})
}
func Test_DB_GetAll(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 1)
t.AssertNil(err)
t.Assert(len(result), 1)
t.Assert(result[0]["ID"].Int(), 1)
})
gtest.C(t, func(t *gtest.T) {
result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), g.Slice{1})
t.AssertNil(err)
t.Assert(len(result), 1)
t.Assert(result[0]["ID"].Int(), 1)
})
gtest.C(t, func(t *gtest.T) {
result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id in(?)", table), g.Slice{1, 2, 3})
t.AssertNil(err)
t.Assert(len(result), 3)
t.Assert(result[0]["ID"].Int(), 1)
t.Assert(result[1]["ID"].Int(), 2)
t.Assert(result[2]["ID"].Int(), 3)
})
gtest.C(t, func(t *gtest.T) {
result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id in(?,?,?)", table), g.Slice{1, 2, 3})
t.AssertNil(err)
t.Assert(len(result), 3)
t.Assert(result[0]["ID"].Int(), 1)
t.Assert(result[1]["ID"].Int(), 2)
t.Assert(result[2]["ID"].Int(), 3)
})
gtest.C(t, func(t *gtest.T) {
result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id in(?,?,?)", table), g.Slice{1, 2, 3}...)
t.AssertNil(err)
t.Assert(len(result), 3)
t.Assert(result[0]["ID"].Int(), 1)
t.Assert(result[1]["ID"].Int(), 2)
t.Assert(result[2]["ID"].Int(), 3)
})
gtest.C(t, func(t *gtest.T) {
result, err := db.GetAll(ctx, fmt.Sprintf("SELECT * FROM %s WHERE id>=? AND id <=?", table), g.Slice{1, 3})
t.AssertNil(err)
t.Assert(len(result), 3)
t.Assert(result[0]["ID"].Int(), 1)
t.Assert(result[1]["ID"].Int(), 2)
t.Assert(result[2]["ID"].Int(), 3)
})
}
func Test_DB_GetOne(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
record, err := db.GetOne(ctx, fmt.Sprintf("SELECT * FROM %s WHERE passport=?", table), "user_1")
t.AssertNil(err)
t.Assert(record["NICKNAME"].String(), "name_1")
})
}
func Test_DB_GetValue(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
value, err := db.GetValue(ctx, fmt.Sprintf("SELECT id FROM %s WHERE passport=?", table), "user_3")
t.AssertNil(err)
t.Assert(value.Int(), 3)
})
}
func Test_DB_GetCount(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
count, err := db.GetCount(ctx, fmt.Sprintf("SELECT * FROM %s", table))
t.AssertNil(err)
t.Assert(count, TableSize)
})
}
func Test_DB_GetStruct(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime gtime.Time
}
user := new(User)
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
t.AssertNil(err)
t.Assert(user.NickName, "name_3")
})
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime *gtime.Time
}
user := new(User)
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
t.AssertNil(err)
t.Assert(user.NickName, "name_3")
})
}
func Test_DB_GetStructs(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime gtime.Time
}
var users []User
err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1)
t.AssertNil(err)
t.Assert(len(users), TableSize-1)
t.Assert(users[0].Id, 2)
t.Assert(users[1].Id, 3)
t.Assert(users[2].Id, 4)
t.Assert(users[0].NickName, "name_2")
t.Assert(users[1].NickName, "name_3")
t.Assert(users[2].NickName, "name_4")
})
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime *gtime.Time
}
var users []User
err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1)
t.AssertNil(err)
t.Assert(len(users), TableSize-1)
t.Assert(users[0].Id, 2)
t.Assert(users[1].Id, 3)
t.Assert(users[2].Id, 4)
t.Assert(users[0].NickName, "name_2")
t.Assert(users[1].NickName, "name_3")
t.Assert(users[2].NickName, "name_4")
})
}
func Test_DB_GetScan(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime gtime.Time
}
user := new(User)
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
t.AssertNil(err)
t.Assert(user.NickName, "name_3")
})
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime gtime.Time
}
var user *User
err := db.GetScan(ctx, &user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
t.AssertNil(err)
t.Assert(user.NickName, "name_3")
})
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime *gtime.Time
}
user := new(User)
err := db.GetScan(ctx, user, fmt.Sprintf("SELECT * FROM %s WHERE id=?", table), 3)
t.AssertNil(err)
t.Assert(user.NickName, "name_3")
})
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime gtime.Time
}
var users []User
err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1)
t.AssertNil(err)
t.Assert(len(users), TableSize-1)
t.Assert(users[0].Id, 2)
t.Assert(users[1].Id, 3)
t.Assert(users[2].Id, 4)
t.Assert(users[0].NickName, "name_2")
t.Assert(users[1].NickName, "name_3")
t.Assert(users[2].NickName, "name_4")
})
gtest.C(t, func(t *gtest.T) {
type User struct {
Id int
Passport string
Password string
NickName string
CreateTime *gtime.Time
}
var users []User
err := db.GetScan(ctx, &users, fmt.Sprintf("SELECT * FROM %s WHERE id>?", table), 1)
t.AssertNil(err)
t.Assert(len(users), TableSize-1)
t.Assert(users[0].Id, 2)
t.Assert(users[1].Id, 3)
t.Assert(users[2].Id, 4)
t.Assert(users[0].NickName, "name_2")
t.Assert(users[1].NickName, "name_3")
t.Assert(users[2].NickName, "name_4")
})
}
func Test_DB_Delete(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
result, err := db.Delete(ctx, table, "1=1")
t.AssertNil(err)
n, _ := result.RowsAffected()
t.Assert(n, TableSize)
})
}
func Test_Empty_Slice_Argument(t *testing.T) {
table := createInitTable()
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
result, err := db.GetAll(ctx, fmt.Sprintf(`select * from %s where id in(?)`, table), g.Slice{})
t.AssertNil(err)
t.Assert(len(result), 0)
})
}

File diff suppressed because it is too large Load Diff