Skip to content

Commit

Permalink
✨ 支持设置 VARCHAR 类型大小是否为字符长度
Browse files Browse the repository at this point in the history
Signed-off-by: liutianqi <[email protected]>
  • Loading branch information
iTanken committed Jan 2, 2024
1 parent 8b81196 commit af80b00
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ jobs:
go run github.com/cloverstd/tcping@latest 127.0.0.1:30236
- name: Tests
run: DM_HOST=127.0.0.1 DM_PORT=30236 DM_PASSWORD=SYSDBA001 go test -v ./...
run: DM_HOST=127.0.0.1 DM_PORT=30236 DM_PASSWORD=SYSDBA001 WAIT_MIN=1 go test -timeout 20m -v ./...
42 changes: 31 additions & 11 deletions dameng_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"log"
"os"
"strconv"
"sync"
"testing"
"time"

"github.com/godoes/gorm-dameng/dm8"
"gorm.io/gorm"
Expand All @@ -18,6 +20,8 @@ var (
dmPort int

dmSchema string

waitOnce sync.Once
)

func init() {
Expand Down Expand Up @@ -48,13 +52,29 @@ func init() {
dmUsername, dmPassword, dmHost, dmPort)
}

func testWaitInit() {
waitOnce.Do(func() {
if wait := os.Getenv("WAIT_MIN"); wait != "" {
if min, e := strconv.Atoi(wait); e == nil {
log.Println("wait for dm database initialization to complete...")
time.Sleep(time.Duration(min) * time.Minute)
}
}
})
}

type Product struct {
gorm.Model
Code string
Price uint

Remark string `gorm:"column:remark;size:0"`
Remark1 string `gorm:"column:remark_1;size:-1"`
Remark2 string `gorm:"column:remark_2;size:32768"`
}

func TestGormConnExample(t *testing.T) {
testWaitInit()
options := map[string]string{
"schema": dmSchema,
"appName": "GORM 连接操作达梦数据库测试",
Expand All @@ -65,7 +85,8 @@ func TestGormConnExample(t *testing.T) {
t.Logf("连接地址: %s", dsn)

// 参考链接: https://eco.dameng.com/document/dm/zh-cn/pm/go-rogramming-guide.html#11.8%20ORM%20%E6%96%B9%E8%A8%80%E5%8C%85
db, err := gorm.Open(Open(dsn), &gorm.Config{})
dialector := New(Config{DSN: dsn, VarcharSizeIsCharLength: true})
db, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
t.Fatalf("连接数据库 [%s@%s:%d] 失败:%v", dmUsername, dmHost, dmPort, err)
} else {
Expand All @@ -80,7 +101,7 @@ func TestGormConnExample(t *testing.T) {
}

// Create
db.Create(&Product{Code: "D42", Price: 100})
db.Create(&Product{Code: "D42", Price: 100, Remark1: "VARCHAR", Remark2: "CLOB"})
if err = db.Error; err != nil {
t.Errorf("创建数据失败:%v", err)
} else {
Expand All @@ -89,26 +110,25 @@ func TestGormConnExample(t *testing.T) {

// Read
var product Product
db.First(&product, 1) // 根据整型主键查找
if err = db.Error; err != nil {
// 根据整型主键查找
if err = db.First(&product, 1).Error; err != nil {
t.Errorf("根据 ID 获取数据失败:%v", err)
} else {
t.Log("根据 ID 获取数据成功!")
t.Logf("根据 ID 获取数据成功!\n%+v", product)
}

// 若 创建数据库 初始化参数 时选中了“字符串比较大小写敏感”,则查询时 SQL 字段名要加双引号,
// 可通过 SELECT CASE_SENSITIVE() 查询数据库是否启用了大小写敏感,若未启用则引号可加可不加。
// 参考链接: https://eco.dameng.com/community/article/a9a9fab6fc1b86483e82317d1ccc1acb
db.First(&product, `"code" = ?`, "D42") // 查找 code 字段值为 D42 的记录
if err = db.Error; err != nil {
// 查找 code 字段值为 D42 的记录
if err = db.First(&product, `"code" = ?`, "D42").Error; err != nil {
t.Errorf("获取数据失败:%v", err)
} else {
t.Log("获取数据数据成功!")
t.Logf("获取数据数据成功!\n%+v", product)
}

// Update - 将 product 的 price 更新为 200
db.Model(&product).Update("Price", 200)
if err = db.Error; err != nil {
if err = db.Model(&product).Update("Price", 200).Error; err != nil {
t.Errorf("根据列名更新单个字段失败:%v", err)
} else {
t.Log("根据列名更新单个字段成功!")
Expand Down Expand Up @@ -136,7 +156,7 @@ func TestGormConnExample(t *testing.T) {
}

//goland:noinspection SqlNoDataSourceInspection
db.Exec(`DROP table "products"`)
//db.Exec(`DROP table "products"`)
if err = db.Error; err != nil {
t.Errorf("删除表结构失败:%v", err)
} else {
Expand Down
19 changes: 14 additions & 5 deletions dm.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type Config struct {
DSN string
Conn gorm.ConnPool
DefaultStringSize uint

VarcharSizeIsCharLength bool // VARCHAR 类型大小是否为字符长度(默认为字节长度)
}

type Dialector struct {
Expand Down Expand Up @@ -228,12 +230,19 @@ func (d Dialector) getSchemaStringType(field *schema.Field) string {
}
}

if size <= 0 {
return "VARCHAR"
} else if size >= 32768 {
return "CLOB"
if size > 0 && size < 32768 {
// VARCHAR 可以指定一个不超过 32767 的正整数作为字节或字符长度
if d.VarcharSizeIsCharLength {
return fmt.Sprintf("VARCHAR(%d CHAR)", size) // 字符长度(size * 4)
}
return fmt.Sprintf("VARCHAR(%d)", size) // 字节长度
} else if size == 0 {
if d.VarcharSizeIsCharLength {
return "VARCHAR(8188 CHAR)" // 字符长度(8188 * 4)
}
return "VARCHAR" // 如果未指定长度,缺省为 8188 字节
} else {
return fmt.Sprintf("VARCHAR(%d)", size)
return "CLOB" // 长度超过 32767,使用 CLOB(TEXT)
}
}

Expand Down
41 changes: 41 additions & 0 deletions dm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package dameng
import (
"bytes"
"testing"

"gorm.io/gorm"
)

func TestDialector_QuoteTo(t *testing.T) {
Expand Down Expand Up @@ -58,3 +60,42 @@ func BenchmarkDialector_QuoteTo(b *testing.B) {
buf.Reset()
}
}

func TestNew(t *testing.T) {
testWaitInit()
type args struct {
config Config
}
options := map[string]string{
"schema": dmSchema,
"appName": "dm_TestNew",
"connectTimeout": "30000",
}

tests := []struct {
name string
args args
//want gorm.Dialector
}{
{"TestNew", args{Config{
DriverName: DriverName,
DSN: BuildUrl(dmUsername, dmPassword, dmHost, dmPort, options),
VarcharSizeIsCharLength: true,
}}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotDB, gotErr := gorm.Open(New(tt.args.config))
if gotErr != nil {
t.Errorf("New() got error: %v", gotErr)
}
var version string
gotErr = gotDB.Raw("SELECT BANNER FROM V$VERSION WHERE BANNER LIKE 'DB Version:%'").Row().Scan(&version)
if gotErr == nil {
t.Log("DM Version:", version)
} else {
t.Errorf("Scan() got error: %v", gotErr)
}
})
}
}

0 comments on commit af80b00

Please sign in to comment.