feat(db): 添加对达梦数据库的支持
- 在应用程序中新增对达梦数据库(DM)的配置和连接支持 - 实现 SetDmDB 函数以配置达梦数据库连接 - 更新数据库操作逻辑,支持达梦特有的 SQL 语法和功能 - 在相关文件中添加达梦数据库的处理逻辑,包括表创建、数据插入和查询 - 更新 go.mod 和 go.sum 文件以引入达梦数据库驱动 - 增强文档,详细说明达梦数据库的配置和使用方法
This commit is contained in:
+43
@@ -0,0 +1,43 @@
|
||||
# Change Logs
|
||||
|
||||
*你可以在文件p.go中的发版标记里找到当前驱动的svn号
|
||||
|
||||
## svn 31633
|
||||
修复了带ipv6地址的服务名无法连接数据库的问题
|
||||
dm.DmError输出不再附加堆栈信息,如需要则调用dm.DmError.Stack()方法单独获取
|
||||
服务器开启常量参数化优化时,go驱动出现一些报错问题
|
||||
|
||||
## svn 16752
|
||||
支持在连接串上直接配置动态服务名,使用示例:
|
||||
dm://user:password@GroupName?GroupName=(host1:port1,host2:port2,...)
|
||||
|
||||
## svn 16505
|
||||
新增连接串属性driverReconnect,配合doSwitch=1或2使用,表示连接重连是否使用驱动自身的重连机制,否则在连接失效时返回sql标准错误driver.ErrBadConn,由go来处理重连
|
||||
|
||||
## svn 16258
|
||||
重连逻辑修改,当连接失效时,返回driver.ErrBadConn而不是驱动自己管理重连,连接串参数doSwitch默认值改为1
|
||||
驱动接口方法同步锁改到连接网络请求的总入口处,解决一些panic和数组越界问题
|
||||
日志优化,去除遍历结果集时因io.EOF错误记录的日志
|
||||
|
||||
## svn 15619
|
||||
驱动接口方法添加同步锁
|
||||
驱动日志修改bug,可以记录SQL语句和参数值了
|
||||
|
||||
## svn 15357
|
||||
发布方言包,支持gorm v1和v2框架,方言包位于达梦安装目录的drivers/go目录中,详细使用说明参考《DM8程序员手册》
|
||||
|
||||
## svn 15157
|
||||
修复了字符大字段(Clob)中存在乱码字符时,读取结果会漏读一些字符的问题
|
||||
修复了开启SSL后并发创建连接导致panic的问题
|
||||
|
||||
## svn 15035
|
||||
修复了连接串属性doSwitch=1时,语句不会自动切换和重连的问题
|
||||
修复了连接重置后,可能出现的空指针问题
|
||||
|
||||
## svn 14992
|
||||
修复了连接串属性doSwitch=1时,连接不会自动切换和重连的问题
|
||||
修复了连接串属性loginMode=默认值4时,备库可能会被优先连接的问题
|
||||
|
||||
## svn 14589
|
||||
sql.Result.LastInsertId()函数能优先返回自增列的值,如果没有则返回数据库表内部的rowid
|
||||
修复了开启事务时指定只读不生效的问题
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
# dm
|
||||
|
||||
### 介绍
|
||||
```
|
||||
go get gitee.com/chunanyong/dm
|
||||
```
|
||||
达梦数据库官方Go驱动,本项目和官方驱动版本同步,方便go mod 使用.
|
||||
安装达梦数据库(版本>=8.1.1.126),安装目录下 drivers/go/dm-go-driver.zip
|
||||
达梦官方文档:https://eco.dameng.com/docs/zh-cn/app-dev/go-go.html
|
||||
资源下载:https://eco.dameng.com/download/
|
||||
达梦官方Go驱动包:https://package.dameng.com/eco/adapter/resource/go/dm-go-driver.zip
|
||||
达梦官方论坛(提交bug):https://eco.dameng.com/community/question
|
||||
|
||||
### zorm
|
||||
Go轻量ORM https://gitee.com/chunanyong/zorm 原生支持达梦数据库
|
||||
|
||||
### DSN
|
||||
dm://userName:password@127.0.0.1:5236?schema=DBName
|
||||
用户名(userName)默认就是数据库的名称,达梦用户模式和数据库名称是对应的,也可以通过schema参数指定数据库
|
||||
建议达梦使用UTF-8字符编码,不区分大小写,建表语句的字段名不要带""双引号
|
||||
密码中包含特殊字符时,密码使用url.PathEscape进行Escape处理,并在DSN中加入&escapeProcess=true 参见:https://eco.dameng.com/community/question/d152258b30bd0fc030d15e6a4afd5fc2
|
||||
|
||||
### bug
|
||||
- 达梦开启等保参数 COMM_ENCRYPT_NAME = AES128_ECB,导致连接异常
|
||||
|
||||
### 版本号
|
||||
Go三段位版本号和达梦四段位版本号不兼容,统一使用1.达梦主版本号.发布的小版本号,具体查看标签的备注
|
||||
|
||||
* v1.8.22 来自 达梦8.1.4.170
|
||||
* v1.8.21 来自 达梦8.1.4.116
|
||||
* v1.8.20 来自 达梦8.1.4.80
|
||||
* v1.8.19 来自 达梦8.1.4.48
|
||||
* v1.8.18 来自 达梦8.1.4.6
|
||||
* v1.8.17 来自 达梦8.1.4.6
|
||||
* v1.8.16 来自 达梦8.1.3.162
|
||||
* v1.8.15 来自 达梦8.1.3.140
|
||||
* v1.8.14 来自 达梦8.1.3.100
|
||||
* v1.8.13 来自 达梦8.1.3.62
|
||||
* v1.8.12 来自 达梦8.1.3.12
|
||||
* v1.8.11 来自 达梦8.1.2.192
|
||||
* v1.8.10 来自 达梦8.1.2.174
|
||||
* v1.8.9 来自 达梦8.1.2.162
|
||||
* v1.8.8 来自 达梦8.1.2.138
|
||||
* v1.8.7 来自 达梦8.1.2.128
|
||||
* v1.8.6 来自 达梦8.1.2.114
|
||||
* v1.8.5 来自 达梦8.1.2.94
|
||||
* v1.8.4 来自 达梦8.1.2.84
|
||||
* v1.8.3 来自 达梦8.1.2.38
|
||||
* v1.8.2 来自 达梦8.1.2.18
|
||||
* v1.8.1 来自 达梦8.1.1.190
|
||||
* v1.8.0 来自 达梦8.1.1.126
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#8.1.4.170
|
||||
#2025.11.21
|
||||
#43114
|
||||
+863
@@ -0,0 +1,863 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"gitee.com/chunanyong/dm/security"
|
||||
)
|
||||
|
||||
const (
|
||||
Dm_build_412 = 8192
|
||||
Dm_build_413 = 2 * time.Second
|
||||
)
|
||||
|
||||
type dm_build_414 struct {
|
||||
dm_build_415 net.Conn
|
||||
dm_build_416 *tls.Conn
|
||||
dm_build_417 *Dm_build_78
|
||||
dm_build_418 *DmConnection
|
||||
dm_build_419 security.Cipher
|
||||
dm_build_420 bool
|
||||
dm_build_421 bool
|
||||
dm_build_422 *security.DhKey
|
||||
|
||||
dm_build_423 bool
|
||||
dm_build_424 string
|
||||
dm_build_425 bool
|
||||
}
|
||||
|
||||
func dm_build_426(dm_build_427 context.Context, dm_build_428 *DmConnection) (*dm_build_414, error) {
|
||||
var dm_build_429 net.Conn
|
||||
var dm_build_430 error
|
||||
|
||||
dialsLock.RLock()
|
||||
dm_build_431, dm_build_432 := dials[dm_build_428.dmConnector.dialName]
|
||||
dialsLock.RUnlock()
|
||||
if dm_build_432 {
|
||||
dm_build_429, dm_build_430 = dm_build_431(dm_build_427, dm_build_428.dmConnector.host+":"+strconv.Itoa(int(dm_build_428.dmConnector.port)))
|
||||
} else {
|
||||
dm_build_429, dm_build_430 = dm_build_434(dm_build_428.dmConnector.host+":"+strconv.Itoa(int(dm_build_428.dmConnector.port)), time.Duration(dm_build_428.dmConnector.socketTimeout)*time.Second)
|
||||
}
|
||||
if dm_build_430 != nil {
|
||||
return nil, dm_build_430
|
||||
}
|
||||
|
||||
dm_build_433 := dm_build_414{}
|
||||
dm_build_433.dm_build_415 = dm_build_429
|
||||
dm_build_433.dm_build_417 = Dm_build_81(Dm_build_707)
|
||||
dm_build_433.dm_build_418 = dm_build_428
|
||||
dm_build_433.dm_build_420 = false
|
||||
dm_build_433.dm_build_421 = false
|
||||
dm_build_433.dm_build_423 = false
|
||||
dm_build_433.dm_build_424 = ""
|
||||
dm_build_433.dm_build_425 = false
|
||||
dm_build_428.Access = &dm_build_433
|
||||
|
||||
return &dm_build_433, nil
|
||||
}
|
||||
|
||||
func dm_build_434(dm_build_435 string, dm_build_436 time.Duration) (net.Conn, error) {
|
||||
dm_build_437, dm_build_438 := net.DialTimeout("tcp", dm_build_435, dm_build_436)
|
||||
if dm_build_438 != nil {
|
||||
return &net.TCPConn{}, ECGO_COMMUNITION_ERROR.addDetail("\tdial address: " + dm_build_435).throw()
|
||||
}
|
||||
|
||||
if tcpConn, ok := dm_build_437.(*net.TCPConn); ok {
|
||||
tcpConn.SetKeepAlive(true)
|
||||
tcpConn.SetKeepAlivePeriod(Dm_build_413)
|
||||
tcpConn.SetNoDelay(true)
|
||||
|
||||
}
|
||||
return dm_build_437, nil
|
||||
}
|
||||
|
||||
func (dm_build_440 *dm_build_414) dm_build_439(dm_build_441 dm_build_828) bool {
|
||||
var dm_build_442 = dm_build_440.dm_build_418.dmConnector.compress
|
||||
if dm_build_441.dm_build_843() == Dm_build_735 || dm_build_442 == Dm_build_784 {
|
||||
return false
|
||||
}
|
||||
|
||||
if dm_build_442 == Dm_build_782 {
|
||||
return true
|
||||
} else if dm_build_442 == Dm_build_783 {
|
||||
return !dm_build_440.dm_build_418.Local && dm_build_441.dm_build_841() > Dm_build_781
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (dm_build_444 *dm_build_414) dm_build_443(dm_build_445 dm_build_828) bool {
|
||||
var dm_build_446 = dm_build_444.dm_build_418.dmConnector.compress
|
||||
if dm_build_445.dm_build_843() == Dm_build_735 || dm_build_446 == Dm_build_784 {
|
||||
return false
|
||||
}
|
||||
|
||||
if dm_build_446 == Dm_build_782 {
|
||||
return true
|
||||
} else if dm_build_446 == Dm_build_783 {
|
||||
return dm_build_444.dm_build_417.Dm_build_345(Dm_build_743) == 1
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (dm_build_448 *dm_build_414) dm_build_447(dm_build_449 dm_build_828) (err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
if _, ok := p.(string); ok {
|
||||
err = ECGO_COMMUNITION_ERROR.addDetail("\t" + p.(string)).throw()
|
||||
} else {
|
||||
err = fmt.Errorf("internal error: %v", p)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
dm_build_451 := dm_build_449.dm_build_841()
|
||||
|
||||
if dm_build_451 > 0 {
|
||||
|
||||
if dm_build_448.dm_build_439(dm_build_449) {
|
||||
var retBytes, err = Compress(dm_build_448.dm_build_417, Dm_build_736, int(dm_build_451), int(dm_build_448.dm_build_418.dmConnector.compressID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dm_build_448.dm_build_417.Dm_build_92(Dm_build_736)
|
||||
|
||||
dm_build_448.dm_build_417.Dm_build_133(dm_build_451)
|
||||
|
||||
dm_build_448.dm_build_417.Dm_build_161(retBytes)
|
||||
|
||||
dm_build_449.dm_build_842(int32(len(retBytes)) + ULINT_SIZE)
|
||||
|
||||
dm_build_448.dm_build_417.Dm_build_265(Dm_build_743, 1)
|
||||
}
|
||||
|
||||
if dm_build_448.dm_build_421 {
|
||||
dm_build_451 = dm_build_449.dm_build_841()
|
||||
var retBytes = dm_build_448.dm_build_419.Encrypt(dm_build_448.dm_build_417.Dm_build_372(Dm_build_736, int(dm_build_451)), true)
|
||||
|
||||
dm_build_448.dm_build_417.Dm_build_92(Dm_build_736)
|
||||
|
||||
dm_build_448.dm_build_417.Dm_build_161(retBytes)
|
||||
|
||||
dm_build_449.dm_build_842(int32(len(retBytes)))
|
||||
}
|
||||
}
|
||||
|
||||
if dm_build_448.dm_build_417.Dm_build_90() > Dm_build_708 {
|
||||
return ECGO_MSG_TOO_LONG.throw()
|
||||
}
|
||||
|
||||
dm_build_449.dm_build_837()
|
||||
if dm_build_448.dm_build_690(dm_build_449) {
|
||||
if dm_build_448.dm_build_416 != nil {
|
||||
dm_build_448.dm_build_417.Dm_build_95(0)
|
||||
if _, err := dm_build_448.dm_build_417.Dm_build_114(dm_build_448.dm_build_416); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dm_build_448.dm_build_417.Dm_build_95(0)
|
||||
if _, err := dm_build_448.dm_build_417.Dm_build_114(dm_build_448.dm_build_415); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_453 *dm_build_414) dm_build_452(dm_build_454 dm_build_828) (err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
if _, ok := p.(string); ok {
|
||||
err = ECGO_COMMUNITION_ERROR.addDetail("\t" + p.(string)).throw()
|
||||
} else {
|
||||
err = fmt.Errorf("internal error: %v", p)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
dm_build_456 := int32(0)
|
||||
if dm_build_453.dm_build_690(dm_build_454) {
|
||||
if dm_build_453.dm_build_416 != nil {
|
||||
dm_build_453.dm_build_417.Dm_build_92(0)
|
||||
if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_416, Dm_build_736); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dm_build_456 = dm_build_454.dm_build_841()
|
||||
if dm_build_456 > 0 {
|
||||
if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_416, int(dm_build_456)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
dm_build_453.dm_build_417.Dm_build_92(0)
|
||||
if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_415, Dm_build_736); err != nil {
|
||||
return err
|
||||
}
|
||||
dm_build_456 = dm_build_454.dm_build_841()
|
||||
|
||||
if dm_build_456 > 0 {
|
||||
if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_415, int(dm_build_456)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dm_build_454.dm_build_838()
|
||||
|
||||
dm_build_456 = dm_build_454.dm_build_841()
|
||||
if dm_build_456 <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dm_build_453.dm_build_421 {
|
||||
ebytes := dm_build_453.dm_build_417.Dm_build_372(Dm_build_736, int(dm_build_456))
|
||||
bytes, err := dm_build_453.dm_build_419.Decrypt(ebytes, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dm_build_453.dm_build_417.Dm_build_92(Dm_build_736)
|
||||
dm_build_453.dm_build_417.Dm_build_161(bytes)
|
||||
dm_build_454.dm_build_842(int32(len(bytes)))
|
||||
}
|
||||
|
||||
if dm_build_453.dm_build_443(dm_build_454) {
|
||||
|
||||
dm_build_456 = dm_build_454.dm_build_841()
|
||||
cbytes := dm_build_453.dm_build_417.Dm_build_372(Dm_build_736+ULINT_SIZE, int(dm_build_456-ULINT_SIZE))
|
||||
bytes, err := UnCompress(cbytes, int(dm_build_453.dm_build_418.dmConnector.compressID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dm_build_453.dm_build_417.Dm_build_92(Dm_build_736)
|
||||
dm_build_453.dm_build_417.Dm_build_161(bytes)
|
||||
dm_build_454.dm_build_842(int32(len(bytes)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_458 *dm_build_414) dm_build_457(dm_build_459 dm_build_828) (dm_build_460 interface{}, dm_build_461 error) {
|
||||
if dm_build_458.dm_build_425 {
|
||||
return nil, ECGO_CONNECTION_CLOSED.throw()
|
||||
}
|
||||
dm_build_462 := dm_build_458.dm_build_418
|
||||
dm_build_462.mu.Lock()
|
||||
defer dm_build_462.mu.Unlock()
|
||||
dm_build_461 = dm_build_459.dm_build_832(dm_build_459)
|
||||
if dm_build_461 != nil {
|
||||
return nil, dm_build_461
|
||||
}
|
||||
|
||||
dm_build_461 = dm_build_458.dm_build_447(dm_build_459)
|
||||
if dm_build_461 != nil {
|
||||
return nil, dm_build_461
|
||||
}
|
||||
|
||||
dm_build_461 = dm_build_458.dm_build_452(dm_build_459)
|
||||
if dm_build_461 != nil {
|
||||
return nil, dm_build_461
|
||||
}
|
||||
|
||||
return dm_build_459.dm_build_836(dm_build_459)
|
||||
}
|
||||
|
||||
func (dm_build_464 *dm_build_414) dm_build_463() (*dm_build_1287, error) {
|
||||
|
||||
Dm_build_465 := dm_build_1293(dm_build_464)
|
||||
_, dm_build_466 := dm_build_464.dm_build_457(Dm_build_465)
|
||||
if dm_build_466 != nil {
|
||||
return nil, dm_build_466
|
||||
}
|
||||
|
||||
return Dm_build_465, nil
|
||||
}
|
||||
|
||||
func (dm_build_468 *dm_build_414) dm_build_467() error {
|
||||
|
||||
dm_build_469 := dm_build_1152(dm_build_468)
|
||||
_, dm_build_470 := dm_build_468.dm_build_457(dm_build_469)
|
||||
if dm_build_470 != nil {
|
||||
return dm_build_470
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_472 *dm_build_414) dm_build_471() error {
|
||||
|
||||
var dm_build_473 *dm_build_1287
|
||||
var err error
|
||||
if dm_build_473, err = dm_build_472.dm_build_463(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dm_build_472.dm_build_418.sslEncrypt == 2 {
|
||||
if err = dm_build_472.dm_build_686(false); err != nil {
|
||||
return ECGO_INIT_SSL_FAILED.addDetail("\n" + err.Error()).throw()
|
||||
}
|
||||
} else if dm_build_472.dm_build_418.sslEncrypt == 1 {
|
||||
if err = dm_build_472.dm_build_686(true); err != nil {
|
||||
return ECGO_INIT_SSL_FAILED.addDetail("\n" + err.Error()).throw()
|
||||
}
|
||||
}
|
||||
|
||||
if dm_build_472.dm_build_421 || dm_build_472.dm_build_420 {
|
||||
k, err := dm_build_472.dm_build_676()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sessionKey := security.ComputeSessionKey(k, dm_build_473.Dm_build_1291)
|
||||
encryptType := dm_build_473.dm_build_1289
|
||||
hashType := int(dm_build_473.Dm_build_1290)
|
||||
if encryptType == -1 {
|
||||
encryptType = security.DES_CFB
|
||||
}
|
||||
if hashType == -1 {
|
||||
hashType = security.MD5
|
||||
}
|
||||
err = dm_build_472.dm_build_679(encryptType, sessionKey, dm_build_472.dm_build_418.dmConnector.cipherPath, hashType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := dm_build_472.dm_build_467(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_476 *dm_build_414) Dm_build_475(dm_build_477 *DmStatement) error {
|
||||
dm_build_478 := dm_build_1317(dm_build_476, dm_build_477)
|
||||
_, dm_build_479 := dm_build_476.dm_build_457(dm_build_478)
|
||||
if dm_build_479 != nil {
|
||||
return dm_build_479
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_481 *dm_build_414) Dm_build_480(dm_build_482 int32) error {
|
||||
dm_build_483 := dm_build_1327(dm_build_481, dm_build_482)
|
||||
_, dm_build_484 := dm_build_481.dm_build_457(dm_build_483)
|
||||
if dm_build_484 != nil {
|
||||
return dm_build_484
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_486 *dm_build_414) Dm_build_485(dm_build_487 *DmStatement, dm_build_488 bool, dm_build_489 int16) (*execRetInfo, error) {
|
||||
dm_build_490 := dm_build_1193(dm_build_486, dm_build_487, dm_build_488, dm_build_489)
|
||||
dm_build_491, dm_build_492 := dm_build_486.dm_build_457(dm_build_490)
|
||||
if dm_build_492 != nil {
|
||||
return nil, dm_build_492
|
||||
}
|
||||
return dm_build_491.(*execRetInfo), nil
|
||||
}
|
||||
|
||||
func (dm_build_494 *dm_build_414) Dm_build_493(dm_build_495 *DmStatement, dm_build_496 int16) (*execRetInfo, error) {
|
||||
return dm_build_494.Dm_build_485(dm_build_495, false, Dm_build_788)
|
||||
}
|
||||
|
||||
func (dm_build_498 *dm_build_414) Dm_build_497(dm_build_499 *DmStatement, dm_build_500 []OptParameter) (*execRetInfo, error) {
|
||||
dm_build_501, dm_build_502 := dm_build_498.dm_build_457(dm_build_931(dm_build_498, dm_build_499, dm_build_500))
|
||||
if dm_build_502 != nil {
|
||||
return nil, dm_build_502
|
||||
}
|
||||
|
||||
return dm_build_501.(*execRetInfo), nil
|
||||
}
|
||||
|
||||
func (dm_build_504 *dm_build_414) Dm_build_503(dm_build_505 *DmStatement, dm_build_506 int16) (*execRetInfo, error) {
|
||||
return dm_build_504.Dm_build_485(dm_build_505, true, dm_build_506)
|
||||
}
|
||||
|
||||
func (dm_build_508 *dm_build_414) Dm_build_507(dm_build_509 *DmStatement, dm_build_510 [][]interface{}) (*execRetInfo, error) {
|
||||
dm_build_511 := dm_build_963(dm_build_508, dm_build_509, dm_build_510)
|
||||
dm_build_512, dm_build_513 := dm_build_508.dm_build_457(dm_build_511)
|
||||
if dm_build_513 != nil {
|
||||
return nil, dm_build_513
|
||||
}
|
||||
return dm_build_512.(*execRetInfo), nil
|
||||
}
|
||||
|
||||
func (dm_build_515 *dm_build_414) Dm_build_514(dm_build_516 *DmStatement, dm_build_517 [][]interface{}, dm_build_518 bool) (*execRetInfo, error) {
|
||||
var dm_build_519, dm_build_520 = 0, 0
|
||||
var dm_build_521 = len(dm_build_517)
|
||||
var dm_build_522 [][]interface{}
|
||||
var dm_build_523 = NewExceInfo()
|
||||
dm_build_523.updateCounts = make([]int64, dm_build_521)
|
||||
var dm_build_524 = false
|
||||
for dm_build_519 < dm_build_521 {
|
||||
for dm_build_520 = dm_build_519; dm_build_520 < dm_build_521; dm_build_520++ {
|
||||
paramData := dm_build_517[dm_build_520]
|
||||
bindData := make([]interface{}, dm_build_516.paramCount)
|
||||
dm_build_524 = false
|
||||
for icol := 0; icol < int(dm_build_516.paramCount); icol++ {
|
||||
if dm_build_516.bindParams[icol].ioType == IO_TYPE_OUT {
|
||||
continue
|
||||
}
|
||||
if dm_build_515.dm_build_659(bindData, paramData, icol) {
|
||||
dm_build_524 = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if dm_build_524 {
|
||||
break
|
||||
}
|
||||
dm_build_522 = append(dm_build_522, bindData)
|
||||
}
|
||||
|
||||
if dm_build_520 != dm_build_519 {
|
||||
tmpExecInfo, err := dm_build_515.Dm_build_507(dm_build_516, dm_build_522)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dm_build_522 = dm_build_522[0:0]
|
||||
dm_build_523.union(tmpExecInfo, dm_build_519, dm_build_520-dm_build_519)
|
||||
}
|
||||
|
||||
if dm_build_520 < dm_build_521 {
|
||||
tmpExecInfo, err := dm_build_515.Dm_build_533(dm_build_516, dm_build_517[dm_build_520], dm_build_518)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dm_build_518 = true
|
||||
dm_build_523.union(tmpExecInfo, dm_build_520, 1)
|
||||
}
|
||||
|
||||
dm_build_519 = dm_build_520 + 1
|
||||
}
|
||||
for _, i := range dm_build_523.updateCounts {
|
||||
if i > 0 {
|
||||
dm_build_523.updateCount += i
|
||||
}
|
||||
}
|
||||
return dm_build_523, nil
|
||||
}
|
||||
|
||||
func (dm_build_526 *dm_build_414) dm_build_525(dm_build_527 *DmStatement, dm_build_528 []parameter) error {
|
||||
if !dm_build_527.prepared {
|
||||
retInfo, err := dm_build_526.Dm_build_485(dm_build_527, false, Dm_build_788)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
dm_build_527.serverParams = retInfo.serverParams
|
||||
dm_build_527.paramCount = int32(len(dm_build_527.serverParams))
|
||||
dm_build_527.prepared = true
|
||||
}
|
||||
|
||||
dm_build_529 := dm_build_1182(dm_build_526, dm_build_527, dm_build_527.bindParams)
|
||||
dm_build_530, err := dm_build_526.dm_build_457(dm_build_529)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
retInfo := dm_build_530.(*execRetInfo)
|
||||
if retInfo.serverParams != nil && len(retInfo.serverParams) > 0 {
|
||||
dm_build_527.serverParams = retInfo.serverParams
|
||||
dm_build_527.paramCount = int32(len(dm_build_527.serverParams))
|
||||
}
|
||||
dm_build_527.preExec = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_534 *dm_build_414) Dm_build_533(dm_build_535 *DmStatement, dm_build_536 []interface{}, dm_build_537 bool) (*execRetInfo, error) {
|
||||
|
||||
var dm_build_538 = make([]interface{}, dm_build_535.paramCount)
|
||||
for icol := 0; icol < int(dm_build_535.paramCount); icol++ {
|
||||
if dm_build_535.bindParams[icol].ioType == IO_TYPE_OUT {
|
||||
continue
|
||||
}
|
||||
if dm_build_534.dm_build_659(dm_build_538, dm_build_536, icol) {
|
||||
|
||||
if !dm_build_537 {
|
||||
dm_build_534.dm_build_525(dm_build_535, dm_build_535.bindParams)
|
||||
|
||||
dm_build_537 = true
|
||||
}
|
||||
|
||||
dm_build_534.dm_build_665(dm_build_535, dm_build_535.bindParams[icol], icol, dm_build_536[icol].(iOffRowBinder))
|
||||
dm_build_538[icol] = ParamDataEnum_OFF_ROW
|
||||
}
|
||||
}
|
||||
|
||||
var dm_build_539 = make([][]interface{}, 1, 1)
|
||||
dm_build_539[0] = dm_build_538
|
||||
|
||||
dm_build_540 := dm_build_963(dm_build_534, dm_build_535, dm_build_539)
|
||||
dm_build_541, dm_build_542 := dm_build_534.dm_build_457(dm_build_540)
|
||||
if dm_build_542 != nil {
|
||||
return nil, dm_build_542
|
||||
}
|
||||
return dm_build_541.(*execRetInfo), nil
|
||||
}
|
||||
|
||||
func (dm_build_544 *dm_build_414) Dm_build_543(dm_build_545 *DmStatement, dm_build_546 int16) (*execRetInfo, error) {
|
||||
dm_build_547 := dm_build_1169(dm_build_544, dm_build_545, dm_build_546)
|
||||
|
||||
dm_build_548, dm_build_549 := dm_build_544.dm_build_457(dm_build_547)
|
||||
if dm_build_549 != nil {
|
||||
return nil, dm_build_549
|
||||
}
|
||||
return dm_build_548.(*execRetInfo), nil
|
||||
}
|
||||
|
||||
func (dm_build_551 *dm_build_414) Dm_build_550(dm_build_552 *innerRows, dm_build_553 int64) (*execRetInfo, error) {
|
||||
dm_build_554 := dm_build_1070(dm_build_551, dm_build_552, dm_build_553, INT64_MAX)
|
||||
dm_build_555, dm_build_556 := dm_build_551.dm_build_457(dm_build_554)
|
||||
if dm_build_556 != nil {
|
||||
return nil, dm_build_556
|
||||
}
|
||||
return dm_build_555.(*execRetInfo), nil
|
||||
}
|
||||
|
||||
func (dm_build_558 *dm_build_414) Commit() error {
|
||||
dm_build_559 := dm_build_916(dm_build_558)
|
||||
_, dm_build_560 := dm_build_558.dm_build_457(dm_build_559)
|
||||
if dm_build_560 != nil {
|
||||
return dm_build_560
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_562 *dm_build_414) Rollback() error {
|
||||
dm_build_563 := dm_build_1231(dm_build_562)
|
||||
_, dm_build_564 := dm_build_562.dm_build_457(dm_build_563)
|
||||
if dm_build_564 != nil {
|
||||
return dm_build_564
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_566 *dm_build_414) Dm_build_565(dm_build_567 *DmConnection) error {
|
||||
dm_build_568 := dm_build_1236(dm_build_566, dm_build_567.IsoLevel)
|
||||
_, dm_build_569 := dm_build_566.dm_build_457(dm_build_568)
|
||||
if dm_build_569 != nil {
|
||||
return dm_build_569
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_571 *dm_build_414) Dm_build_570(dm_build_572 *DmStatement, dm_build_573 string) error {
|
||||
dm_build_574 := dm_build_921(dm_build_571, dm_build_572, dm_build_573)
|
||||
_, dm_build_575 := dm_build_571.dm_build_457(dm_build_574)
|
||||
if dm_build_575 != nil {
|
||||
return dm_build_575
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_577 *dm_build_414) Dm_build_576(dm_build_578 []uint32) ([]int64, error) {
|
||||
dm_build_579 := dm_build_1335(dm_build_577, dm_build_578)
|
||||
dm_build_580, dm_build_581 := dm_build_577.dm_build_457(dm_build_579)
|
||||
if dm_build_581 != nil {
|
||||
return nil, dm_build_581
|
||||
}
|
||||
return dm_build_580.([]int64), nil
|
||||
}
|
||||
|
||||
func (dm_build_583 *dm_build_414) Close() error {
|
||||
if dm_build_583.dm_build_425 {
|
||||
return nil
|
||||
}
|
||||
|
||||
dm_build_584 := dm_build_583.dm_build_415.Close()
|
||||
if dm_build_584 != nil {
|
||||
return dm_build_584
|
||||
}
|
||||
|
||||
dm_build_583.dm_build_418 = nil
|
||||
dm_build_583.dm_build_425 = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_586 *dm_build_414) dm_build_585(dm_build_587 *lob) (int64, error) {
|
||||
dm_build_588 := dm_build_1103(dm_build_586, dm_build_587)
|
||||
dm_build_589, dm_build_590 := dm_build_586.dm_build_457(dm_build_588)
|
||||
if dm_build_590 != nil {
|
||||
return 0, dm_build_590
|
||||
}
|
||||
return dm_build_589.(int64), nil
|
||||
}
|
||||
|
||||
func (dm_build_592 *dm_build_414) dm_build_591(dm_build_593 *lob, dm_build_594 int32, dm_build_595 int32) (*lobRetInfo, error) {
|
||||
dm_build_596 := dm_build_1088(dm_build_592, dm_build_593, int(dm_build_594), int(dm_build_595))
|
||||
dm_build_597, dm_build_598 := dm_build_592.dm_build_457(dm_build_596)
|
||||
if dm_build_598 != nil {
|
||||
return nil, dm_build_598
|
||||
}
|
||||
return dm_build_597.(*lobRetInfo), nil
|
||||
}
|
||||
|
||||
func (dm_build_600 *dm_build_414) dm_build_599(dm_build_601 *DmBlob, dm_build_602 int32, dm_build_603 int32) ([]byte, error) {
|
||||
var dm_build_604 = make([]byte, dm_build_603)
|
||||
var dm_build_605 int32 = 0
|
||||
var dm_build_606 int32 = 0
|
||||
var dm_build_607 *lobRetInfo
|
||||
var dm_build_608 []byte
|
||||
var dm_build_609 error
|
||||
for dm_build_605 < dm_build_603 {
|
||||
dm_build_606 = dm_build_603 - dm_build_605
|
||||
if dm_build_606 > Dm_build_821 {
|
||||
dm_build_606 = Dm_build_821
|
||||
}
|
||||
dm_build_607, dm_build_609 = dm_build_600.dm_build_591(&dm_build_601.lob, dm_build_602+dm_build_605, dm_build_606)
|
||||
if dm_build_609 != nil {
|
||||
return nil, dm_build_609
|
||||
}
|
||||
dm_build_608 = dm_build_607.data
|
||||
if dm_build_608 == nil || len(dm_build_608) == 0 {
|
||||
break
|
||||
}
|
||||
Dm_build_1346.Dm_build_1402(dm_build_604, int(dm_build_605), dm_build_608, 0, len(dm_build_608))
|
||||
dm_build_605 += int32(len(dm_build_608))
|
||||
if dm_build_601.readOver {
|
||||
break
|
||||
}
|
||||
}
|
||||
return dm_build_604, nil
|
||||
}
|
||||
|
||||
func (dm_build_611 *dm_build_414) dm_build_610(dm_build_612 *DmClob, dm_build_613 int32, dm_build_614 int32) (string, error) {
|
||||
var dm_build_615 bytes.Buffer
|
||||
var dm_build_616 int32 = 0
|
||||
var dm_build_617 int32 = 0
|
||||
var dm_build_618 *lobRetInfo
|
||||
var dm_build_619 []byte
|
||||
var dm_build_620 string
|
||||
var dm_build_621 error
|
||||
for dm_build_616 < dm_build_614 {
|
||||
dm_build_617 = dm_build_614 - dm_build_616
|
||||
if dm_build_617 > Dm_build_821/2 {
|
||||
dm_build_617 = Dm_build_821 / 2
|
||||
}
|
||||
dm_build_618, dm_build_621 = dm_build_611.dm_build_591(&dm_build_612.lob, dm_build_613+dm_build_616, dm_build_617)
|
||||
if dm_build_621 != nil {
|
||||
return "", dm_build_621
|
||||
}
|
||||
dm_build_619 = dm_build_618.data
|
||||
if dm_build_619 == nil || len(dm_build_619) == 0 {
|
||||
break
|
||||
}
|
||||
dm_build_620 = Dm_build_1346.Dm_build_1503(dm_build_619, 0, len(dm_build_619), dm_build_612.serverEncoding, dm_build_611.dm_build_418)
|
||||
|
||||
dm_build_615.WriteString(dm_build_620)
|
||||
var strLen = dm_build_618.charLen
|
||||
if strLen == -1 {
|
||||
strLen = int64(utf8.RuneCountInString(dm_build_620))
|
||||
}
|
||||
dm_build_616 += int32(strLen)
|
||||
if dm_build_612.readOver {
|
||||
break
|
||||
}
|
||||
}
|
||||
return dm_build_615.String(), nil
|
||||
}
|
||||
|
||||
func (dm_build_623 *dm_build_414) dm_build_622(dm_build_624 *DmClob, dm_build_625 int, dm_build_626 string, dm_build_627 string) (int, error) {
|
||||
var dm_build_628 = Dm_build_1346.Dm_build_1562(dm_build_626, dm_build_627, dm_build_623.dm_build_418)
|
||||
var dm_build_629 = 0
|
||||
var dm_build_630 = len(dm_build_628)
|
||||
var dm_build_631 = 0
|
||||
var dm_build_632 = 0
|
||||
var dm_build_633 = 0
|
||||
var dm_build_634 = dm_build_630/Dm_build_820 + 1
|
||||
var dm_build_635 byte = 0
|
||||
var dm_build_636 byte = 0x01
|
||||
var dm_build_637 byte = 0x02
|
||||
for i := 0; i < dm_build_634; i++ {
|
||||
dm_build_635 = 0
|
||||
if i == 0 {
|
||||
dm_build_635 |= dm_build_636
|
||||
}
|
||||
if i == dm_build_634-1 {
|
||||
dm_build_635 |= dm_build_637
|
||||
}
|
||||
dm_build_633 = dm_build_630 - dm_build_632
|
||||
if dm_build_633 > Dm_build_820 {
|
||||
dm_build_633 = Dm_build_820
|
||||
}
|
||||
|
||||
setLobData := dm_build_1250(dm_build_623, &dm_build_624.lob, dm_build_635, dm_build_625, dm_build_628, dm_build_629, dm_build_633)
|
||||
ret, err := dm_build_623.dm_build_457(setLobData)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
tmp := ret.(int32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if tmp <= 0 {
|
||||
return dm_build_631, nil
|
||||
} else {
|
||||
dm_build_625 += int(tmp)
|
||||
dm_build_631 += int(tmp)
|
||||
dm_build_632 += dm_build_633
|
||||
dm_build_629 += dm_build_633
|
||||
}
|
||||
}
|
||||
return dm_build_631, nil
|
||||
}
|
||||
|
||||
func (dm_build_639 *dm_build_414) dm_build_638(dm_build_640 *DmBlob, dm_build_641 int, dm_build_642 []byte) (int, error) {
|
||||
var dm_build_643 = 0
|
||||
var dm_build_644 = len(dm_build_642)
|
||||
var dm_build_645 = 0
|
||||
var dm_build_646 = 0
|
||||
var dm_build_647 = 0
|
||||
var dm_build_648 = dm_build_644/Dm_build_820 + 1
|
||||
var dm_build_649 byte = 0
|
||||
var dm_build_650 byte = 0x01
|
||||
var dm_build_651 byte = 0x02
|
||||
for i := 0; i < dm_build_648; i++ {
|
||||
dm_build_649 = 0
|
||||
if i == 0 {
|
||||
dm_build_649 |= dm_build_650
|
||||
}
|
||||
if i == dm_build_648-1 {
|
||||
dm_build_649 |= dm_build_651
|
||||
}
|
||||
dm_build_647 = dm_build_644 - dm_build_646
|
||||
if dm_build_647 > Dm_build_820 {
|
||||
dm_build_647 = Dm_build_820
|
||||
}
|
||||
|
||||
setLobData := dm_build_1250(dm_build_639, &dm_build_640.lob, dm_build_649, dm_build_641, dm_build_642, dm_build_643, dm_build_647)
|
||||
ret, err := dm_build_639.dm_build_457(setLobData)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
tmp := ret.(int32)
|
||||
if tmp <= 0 {
|
||||
return dm_build_645, nil
|
||||
} else {
|
||||
dm_build_641 += int(tmp)
|
||||
dm_build_645 += int(tmp)
|
||||
dm_build_646 += dm_build_647
|
||||
dm_build_643 += dm_build_647
|
||||
}
|
||||
}
|
||||
return dm_build_645, nil
|
||||
}
|
||||
|
||||
func (dm_build_653 *dm_build_414) dm_build_652(dm_build_654 *lob, dm_build_655 int) (int64, error) {
|
||||
dm_build_656 := dm_build_1114(dm_build_653, dm_build_654, dm_build_655)
|
||||
dm_build_657, dm_build_658 := dm_build_653.dm_build_457(dm_build_656)
|
||||
if dm_build_658 != nil {
|
||||
return dm_build_654.length, dm_build_658
|
||||
}
|
||||
return dm_build_657.(int64), nil
|
||||
}
|
||||
|
||||
func (dm_build_660 *dm_build_414) dm_build_659(dm_build_661 []interface{}, dm_build_662 []interface{}, dm_build_663 int) bool {
|
||||
var dm_build_664 = false
|
||||
dm_build_661[dm_build_663] = dm_build_662[dm_build_663]
|
||||
|
||||
if binder, ok := dm_build_662[dm_build_663].(iOffRowBinder); ok {
|
||||
dm_build_664 = true
|
||||
dm_build_661[dm_build_663] = make([]byte, 0)
|
||||
var lob lob
|
||||
if l, ok := binder.getObj().(DmBlob); ok {
|
||||
lob = l.lob
|
||||
} else if l, ok := binder.getObj().(DmClob); ok {
|
||||
lob = l.lob
|
||||
}
|
||||
if &lob != nil && lob.canOptimized(dm_build_660.dm_build_418) {
|
||||
dm_build_661[dm_build_663] = &lobCtl{lob.buildCtlData()}
|
||||
dm_build_664 = false
|
||||
}
|
||||
} else {
|
||||
dm_build_661[dm_build_663] = dm_build_662[dm_build_663]
|
||||
}
|
||||
return dm_build_664
|
||||
}
|
||||
|
||||
func (dm_build_666 *dm_build_414) dm_build_665(dm_build_667 *DmStatement, dm_build_668 parameter, dm_build_669 int, dm_build_670 iOffRowBinder) error {
|
||||
var dm_build_671 = Dm_build_4()
|
||||
dm_build_670.read(dm_build_671)
|
||||
var dm_build_672 = 0
|
||||
for !dm_build_670.isReadOver() || dm_build_671.Dm_build_5() > 0 {
|
||||
if !dm_build_670.isReadOver() && dm_build_671.Dm_build_5() < Dm_build_820 {
|
||||
dm_build_670.read(dm_build_671)
|
||||
}
|
||||
if dm_build_671.Dm_build_5() > Dm_build_820 {
|
||||
dm_build_672 = Dm_build_820
|
||||
} else {
|
||||
dm_build_672 = dm_build_671.Dm_build_5()
|
||||
}
|
||||
|
||||
putData := dm_build_1221(dm_build_666, dm_build_667, int16(dm_build_669), dm_build_671, int32(dm_build_672))
|
||||
_, err := dm_build_666.dm_build_457(putData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dm_build_674 *dm_build_414) dm_build_673() ([]byte, error) {
|
||||
var dm_build_675 error
|
||||
if dm_build_674.dm_build_422 == nil {
|
||||
if dm_build_674.dm_build_422, dm_build_675 = security.NewClientKeyPair(); dm_build_675 != nil {
|
||||
return nil, dm_build_675
|
||||
}
|
||||
}
|
||||
return security.Bn2Bytes(dm_build_674.dm_build_422.GetY(), security.DH_KEY_LENGTH), nil
|
||||
}
|
||||
|
||||
func (dm_build_677 *dm_build_414) dm_build_676() (*security.DhKey, error) {
|
||||
var dm_build_678 error
|
||||
if dm_build_677.dm_build_422 == nil {
|
||||
if dm_build_677.dm_build_422, dm_build_678 = security.NewClientKeyPair(); dm_build_678 != nil {
|
||||
return nil, dm_build_678
|
||||
}
|
||||
}
|
||||
return dm_build_677.dm_build_422, nil
|
||||
}
|
||||
|
||||
func (dm_build_680 *dm_build_414) dm_build_679(dm_build_681 int, dm_build_682 []byte, dm_build_683 string, dm_build_684 int) (dm_build_685 error) {
|
||||
if dm_build_681 > 0 && dm_build_681 < security.MIN_EXTERNAL_CIPHER_ID && dm_build_682 != nil {
|
||||
dm_build_680.dm_build_419, dm_build_685 = security.NewSymmCipher(dm_build_681, dm_build_682)
|
||||
} else if dm_build_681 >= security.MIN_EXTERNAL_CIPHER_ID {
|
||||
if dm_build_680.dm_build_419, dm_build_685 = security.NewThirdPartCipher(dm_build_681, dm_build_682, dm_build_683, dm_build_684); dm_build_685 != nil {
|
||||
dm_build_685 = THIRD_PART_CIPHER_INIT_FAILED.addDetailln(dm_build_685.Error()).throw()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dm_build_687 *dm_build_414) dm_build_686(dm_build_688 bool) (dm_build_689 error) {
|
||||
if dm_build_687.dm_build_416, dm_build_689 = security.NewTLSFromTCP(dm_build_687.dm_build_415, dm_build_687.dm_build_418.dmConnector.sslCertPath, dm_build_687.dm_build_418.dmConnector.sslKeyPath, dm_build_687.dm_build_418.dmConnector.user); dm_build_689 != nil {
|
||||
return
|
||||
}
|
||||
if !dm_build_688 {
|
||||
dm_build_687.dm_build_416 = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dm_build_691 *dm_build_414) dm_build_690(dm_build_692 dm_build_828) bool {
|
||||
return dm_build_692.dm_build_843() != Dm_build_735 && dm_build_691.dm_build_418.sslEncrypt == 1
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
type ArrayDescriptor struct {
|
||||
m_typeDesc *TypeDescriptor
|
||||
}
|
||||
|
||||
func newArrayDescriptor(fulName string, conn *DmConnection) (*ArrayDescriptor, error) {
|
||||
|
||||
ad := new(ArrayDescriptor)
|
||||
|
||||
if fulName == "" {
|
||||
return nil, ECGO_INVALID_COMPLEX_TYPE_NAME.throw()
|
||||
}
|
||||
|
||||
ad.m_typeDesc = newTypeDescriptorWithFulName(fulName, conn)
|
||||
err := ad.m_typeDesc.parseDescByName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ad, nil
|
||||
}
|
||||
|
||||
func newArrayDescriptorByTypeDescriptor(desc *TypeDescriptor) *ArrayDescriptor {
|
||||
ad := new(ArrayDescriptor)
|
||||
ad.m_typeDesc = desc
|
||||
return ad
|
||||
}
|
||||
|
||||
func (ad *ArrayDescriptor) getMDesc() *TypeDescriptor {
|
||||
return ad.m_typeDesc
|
||||
}
|
||||
|
||||
func (ad *ArrayDescriptor) getItemDesc() *TypeDescriptor {
|
||||
return ad.m_typeDesc.m_arrObj
|
||||
}
|
||||
|
||||
func (ad *ArrayDescriptor) getLength() int {
|
||||
return ad.m_typeDesc.m_length
|
||||
}
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
)
|
||||
|
||||
type Dm_build_78 struct {
|
||||
dm_build_79 []byte
|
||||
dm_build_80 int
|
||||
}
|
||||
|
||||
func Dm_build_81(dm_build_82 int) *Dm_build_78 {
|
||||
return &Dm_build_78{make([]byte, 0, dm_build_82), 0}
|
||||
}
|
||||
|
||||
func Dm_build_83(dm_build_84 []byte) *Dm_build_78 {
|
||||
return &Dm_build_78{dm_build_84, 0}
|
||||
}
|
||||
|
||||
func (dm_build_86 *Dm_build_78) dm_build_85(dm_build_87 int) *Dm_build_78 {
|
||||
|
||||
dm_build_88 := len(dm_build_86.dm_build_79)
|
||||
dm_build_89 := cap(dm_build_86.dm_build_79)
|
||||
|
||||
if dm_build_88+dm_build_87 <= dm_build_89 {
|
||||
dm_build_86.dm_build_79 = dm_build_86.dm_build_79[:dm_build_88+dm_build_87]
|
||||
} else {
|
||||
|
||||
var calCap = int64(math.Max(float64(2*dm_build_89), float64(dm_build_87+dm_build_88)))
|
||||
|
||||
nbuf := make([]byte, dm_build_87+dm_build_88, calCap)
|
||||
copy(nbuf, dm_build_86.dm_build_79)
|
||||
dm_build_86.dm_build_79 = nbuf
|
||||
}
|
||||
|
||||
return dm_build_86
|
||||
}
|
||||
|
||||
func (dm_build_91 *Dm_build_78) Dm_build_90() int {
|
||||
return len(dm_build_91.dm_build_79)
|
||||
}
|
||||
|
||||
func (dm_build_93 *Dm_build_78) Dm_build_92(dm_build_94 int) *Dm_build_78 {
|
||||
for i := dm_build_94; i < len(dm_build_93.dm_build_79); i++ {
|
||||
dm_build_93.dm_build_79[i] = 0
|
||||
}
|
||||
dm_build_93.dm_build_79 = dm_build_93.dm_build_79[:dm_build_94]
|
||||
return dm_build_93
|
||||
}
|
||||
|
||||
func (dm_build_96 *Dm_build_78) Dm_build_95(dm_build_97 int) *Dm_build_78 {
|
||||
dm_build_96.dm_build_80 = dm_build_97
|
||||
return dm_build_96
|
||||
}
|
||||
|
||||
func (dm_build_99 *Dm_build_78) Dm_build_98() int {
|
||||
return dm_build_99.dm_build_80
|
||||
}
|
||||
|
||||
func (dm_build_101 *Dm_build_78) Dm_build_100(dm_build_102 bool) int {
|
||||
return len(dm_build_101.dm_build_79) - dm_build_101.dm_build_80
|
||||
}
|
||||
|
||||
func (dm_build_104 *Dm_build_78) Dm_build_103(dm_build_105 int, dm_build_106 bool, dm_build_107 bool) *Dm_build_78 {
|
||||
|
||||
if dm_build_106 {
|
||||
if dm_build_107 {
|
||||
dm_build_104.dm_build_85(dm_build_105)
|
||||
} else {
|
||||
dm_build_104.dm_build_79 = dm_build_104.dm_build_79[:len(dm_build_104.dm_build_79)-dm_build_105]
|
||||
}
|
||||
} else {
|
||||
if dm_build_107 {
|
||||
dm_build_104.dm_build_80 += dm_build_105
|
||||
} else {
|
||||
dm_build_104.dm_build_80 -= dm_build_105
|
||||
}
|
||||
}
|
||||
|
||||
return dm_build_104
|
||||
}
|
||||
|
||||
func (dm_build_109 *Dm_build_78) Dm_build_108(dm_build_110 io.Reader, dm_build_111 int) (int, error) {
|
||||
dm_build_112 := len(dm_build_109.dm_build_79)
|
||||
dm_build_109.dm_build_85(dm_build_111)
|
||||
dm_build_113 := 0
|
||||
for dm_build_111 > 0 {
|
||||
n, err := dm_build_110.Read(dm_build_109.dm_build_79[dm_build_112+dm_build_113:])
|
||||
if n > 0 && err == io.EOF {
|
||||
dm_build_113 += n
|
||||
dm_build_109.dm_build_79 = dm_build_109.dm_build_79[:dm_build_112+dm_build_113]
|
||||
return dm_build_113, nil
|
||||
} else if n > 0 && err == nil {
|
||||
dm_build_111 -= n
|
||||
dm_build_113 += n
|
||||
} else if n == 0 && err != nil {
|
||||
return -1, ECGO_COMMUNITION_ERROR.addDetailln(err.Error()).throw()
|
||||
}
|
||||
}
|
||||
|
||||
return dm_build_113, nil
|
||||
}
|
||||
|
||||
func (dm_build_115 *Dm_build_78) Dm_build_114(dm_build_116 io.Writer) (*Dm_build_78, error) {
|
||||
if _, err := dm_build_116.Write(dm_build_115.dm_build_79); err != nil {
|
||||
return nil, ECGO_COMMUNITION_ERROR.addDetailln(err.Error()).throw()
|
||||
}
|
||||
return dm_build_115, nil
|
||||
}
|
||||
|
||||
func (dm_build_118 *Dm_build_78) Dm_build_117(dm_build_119 bool) int {
|
||||
dm_build_120 := len(dm_build_118.dm_build_79)
|
||||
dm_build_118.dm_build_85(1)
|
||||
|
||||
if dm_build_119 {
|
||||
return copy(dm_build_118.dm_build_79[dm_build_120:], []byte{1})
|
||||
} else {
|
||||
return copy(dm_build_118.dm_build_79[dm_build_120:], []byte{0})
|
||||
}
|
||||
}
|
||||
|
||||
func (dm_build_122 *Dm_build_78) Dm_build_121(dm_build_123 byte) int {
|
||||
dm_build_124 := len(dm_build_122.dm_build_79)
|
||||
dm_build_122.dm_build_85(1)
|
||||
|
||||
return copy(dm_build_122.dm_build_79[dm_build_124:], Dm_build_1346.Dm_build_1524(dm_build_123))
|
||||
}
|
||||
|
||||
func (dm_build_126 *Dm_build_78) Dm_build_125(dm_build_127 int8) int {
|
||||
dm_build_128 := len(dm_build_126.dm_build_79)
|
||||
dm_build_126.dm_build_85(1)
|
||||
|
||||
return copy(dm_build_126.dm_build_79[dm_build_128:], Dm_build_1346.Dm_build_1527(dm_build_127))
|
||||
}
|
||||
|
||||
func (dm_build_130 *Dm_build_78) Dm_build_129(dm_build_131 int16) int {
|
||||
dm_build_132 := len(dm_build_130.dm_build_79)
|
||||
dm_build_130.dm_build_85(2)
|
||||
|
||||
return copy(dm_build_130.dm_build_79[dm_build_132:], Dm_build_1346.Dm_build_1530(dm_build_131))
|
||||
}
|
||||
|
||||
func (dm_build_134 *Dm_build_78) Dm_build_133(dm_build_135 int32) int {
|
||||
dm_build_136 := len(dm_build_134.dm_build_79)
|
||||
dm_build_134.dm_build_85(4)
|
||||
|
||||
return copy(dm_build_134.dm_build_79[dm_build_136:], Dm_build_1346.Dm_build_1533(dm_build_135))
|
||||
}
|
||||
|
||||
func (dm_build_138 *Dm_build_78) Dm_build_137(dm_build_139 uint8) int {
|
||||
dm_build_140 := len(dm_build_138.dm_build_79)
|
||||
dm_build_138.dm_build_85(1)
|
||||
|
||||
return copy(dm_build_138.dm_build_79[dm_build_140:], Dm_build_1346.Dm_build_1545(dm_build_139))
|
||||
}
|
||||
|
||||
func (dm_build_142 *Dm_build_78) Dm_build_141(dm_build_143 uint16) int {
|
||||
dm_build_144 := len(dm_build_142.dm_build_79)
|
||||
dm_build_142.dm_build_85(2)
|
||||
|
||||
return copy(dm_build_142.dm_build_79[dm_build_144:], Dm_build_1346.Dm_build_1548(dm_build_143))
|
||||
}
|
||||
|
||||
func (dm_build_146 *Dm_build_78) Dm_build_145(dm_build_147 uint32) int {
|
||||
dm_build_148 := len(dm_build_146.dm_build_79)
|
||||
dm_build_146.dm_build_85(4)
|
||||
|
||||
return copy(dm_build_146.dm_build_79[dm_build_148:], Dm_build_1346.Dm_build_1551(dm_build_147))
|
||||
}
|
||||
|
||||
func (dm_build_150 *Dm_build_78) Dm_build_149(dm_build_151 uint64) int {
|
||||
dm_build_152 := len(dm_build_150.dm_build_79)
|
||||
dm_build_150.dm_build_85(8)
|
||||
|
||||
return copy(dm_build_150.dm_build_79[dm_build_152:], Dm_build_1346.Dm_build_1554(dm_build_151))
|
||||
}
|
||||
|
||||
func (dm_build_154 *Dm_build_78) Dm_build_153(dm_build_155 float32) int {
|
||||
dm_build_156 := len(dm_build_154.dm_build_79)
|
||||
dm_build_154.dm_build_85(4)
|
||||
|
||||
return copy(dm_build_154.dm_build_79[dm_build_156:], Dm_build_1346.Dm_build_1551(math.Float32bits(dm_build_155)))
|
||||
}
|
||||
|
||||
func (dm_build_158 *Dm_build_78) Dm_build_157(dm_build_159 float64) int {
|
||||
dm_build_160 := len(dm_build_158.dm_build_79)
|
||||
dm_build_158.dm_build_85(8)
|
||||
|
||||
return copy(dm_build_158.dm_build_79[dm_build_160:], Dm_build_1346.Dm_build_1554(math.Float64bits(dm_build_159)))
|
||||
}
|
||||
|
||||
func (dm_build_162 *Dm_build_78) Dm_build_161(dm_build_163 []byte) int {
|
||||
dm_build_164 := len(dm_build_162.dm_build_79)
|
||||
dm_build_162.dm_build_85(len(dm_build_163))
|
||||
return copy(dm_build_162.dm_build_79[dm_build_164:], dm_build_163)
|
||||
}
|
||||
|
||||
func (dm_build_166 *Dm_build_78) Dm_build_165(dm_build_167 []byte) int {
|
||||
return dm_build_166.Dm_build_133(int32(len(dm_build_167))) + dm_build_166.Dm_build_161(dm_build_167)
|
||||
}
|
||||
|
||||
func (dm_build_169 *Dm_build_78) Dm_build_168(dm_build_170 []byte) int {
|
||||
return dm_build_169.Dm_build_137(uint8(len(dm_build_170))) + dm_build_169.Dm_build_161(dm_build_170)
|
||||
}
|
||||
|
||||
func (dm_build_172 *Dm_build_78) Dm_build_171(dm_build_173 []byte) int {
|
||||
return dm_build_172.Dm_build_141(uint16(len(dm_build_173))) + dm_build_172.Dm_build_161(dm_build_173)
|
||||
}
|
||||
|
||||
func (dm_build_175 *Dm_build_78) Dm_build_174(dm_build_176 []byte) int {
|
||||
return dm_build_175.Dm_build_161(dm_build_176) + dm_build_175.Dm_build_121(0)
|
||||
}
|
||||
|
||||
func (dm_build_178 *Dm_build_78) Dm_build_177(dm_build_179 string, dm_build_180 string, dm_build_181 *DmConnection) int {
|
||||
dm_build_182 := Dm_build_1346.Dm_build_1562(dm_build_179, dm_build_180, dm_build_181)
|
||||
return dm_build_178.Dm_build_165(dm_build_182)
|
||||
}
|
||||
|
||||
func (dm_build_184 *Dm_build_78) Dm_build_183(dm_build_185 string, dm_build_186 string, dm_build_187 *DmConnection) int {
|
||||
dm_build_188 := Dm_build_1346.Dm_build_1562(dm_build_185, dm_build_186, dm_build_187)
|
||||
return dm_build_184.Dm_build_168(dm_build_188)
|
||||
}
|
||||
|
||||
func (dm_build_190 *Dm_build_78) Dm_build_189(dm_build_191 string, dm_build_192 string, dm_build_193 *DmConnection) int {
|
||||
dm_build_194 := Dm_build_1346.Dm_build_1562(dm_build_191, dm_build_192, dm_build_193)
|
||||
return dm_build_190.Dm_build_171(dm_build_194)
|
||||
}
|
||||
|
||||
func (dm_build_196 *Dm_build_78) Dm_build_195(dm_build_197 string, dm_build_198 string, dm_build_199 *DmConnection) int {
|
||||
dm_build_200 := Dm_build_1346.Dm_build_1562(dm_build_197, dm_build_198, dm_build_199)
|
||||
return dm_build_196.Dm_build_174(dm_build_200)
|
||||
}
|
||||
|
||||
func (dm_build_202 *Dm_build_78) Dm_build_201() byte {
|
||||
dm_build_203 := Dm_build_1346.Dm_build_1439(dm_build_202.dm_build_79, dm_build_202.dm_build_80)
|
||||
dm_build_202.dm_build_80++
|
||||
return dm_build_203
|
||||
}
|
||||
|
||||
func (dm_build_205 *Dm_build_78) Dm_build_204() int16 {
|
||||
dm_build_206 := Dm_build_1346.Dm_build_1443(dm_build_205.dm_build_79, dm_build_205.dm_build_80)
|
||||
dm_build_205.dm_build_80 += 2
|
||||
return dm_build_206
|
||||
}
|
||||
|
||||
func (dm_build_208 *Dm_build_78) Dm_build_207() int32 {
|
||||
dm_build_209 := Dm_build_1346.Dm_build_1448(dm_build_208.dm_build_79, dm_build_208.dm_build_80)
|
||||
dm_build_208.dm_build_80 += 4
|
||||
return dm_build_209
|
||||
}
|
||||
|
||||
func (dm_build_211 *Dm_build_78) Dm_build_210() int64 {
|
||||
dm_build_212 := Dm_build_1346.Dm_build_1453(dm_build_211.dm_build_79, dm_build_211.dm_build_80)
|
||||
dm_build_211.dm_build_80 += 8
|
||||
return dm_build_212
|
||||
}
|
||||
|
||||
func (dm_build_214 *Dm_build_78) Dm_build_213() float32 {
|
||||
dm_build_215 := Dm_build_1346.Dm_build_1458(dm_build_214.dm_build_79, dm_build_214.dm_build_80)
|
||||
dm_build_214.dm_build_80 += 4
|
||||
return dm_build_215
|
||||
}
|
||||
|
||||
func (dm_build_217 *Dm_build_78) Dm_build_216() float64 {
|
||||
dm_build_218 := Dm_build_1346.Dm_build_1462(dm_build_217.dm_build_79, dm_build_217.dm_build_80)
|
||||
dm_build_217.dm_build_80 += 8
|
||||
return dm_build_218
|
||||
}
|
||||
|
||||
func (dm_build_220 *Dm_build_78) Dm_build_219() uint8 {
|
||||
dm_build_221 := Dm_build_1346.Dm_build_1466(dm_build_220.dm_build_79, dm_build_220.dm_build_80)
|
||||
dm_build_220.dm_build_80 += 1
|
||||
return dm_build_221
|
||||
}
|
||||
|
||||
func (dm_build_223 *Dm_build_78) Dm_build_222() uint16 {
|
||||
dm_build_224 := Dm_build_1346.Dm_build_1470(dm_build_223.dm_build_79, dm_build_223.dm_build_80)
|
||||
dm_build_223.dm_build_80 += 2
|
||||
return dm_build_224
|
||||
}
|
||||
|
||||
func (dm_build_226 *Dm_build_78) Dm_build_225() uint32 {
|
||||
dm_build_227 := Dm_build_1346.Dm_build_1475(dm_build_226.dm_build_79, dm_build_226.dm_build_80)
|
||||
dm_build_226.dm_build_80 += 4
|
||||
return dm_build_227
|
||||
}
|
||||
|
||||
func (dm_build_229 *Dm_build_78) Dm_build_228(dm_build_230 int) []byte {
|
||||
dm_build_231 := Dm_build_1346.Dm_build_1497(dm_build_229.dm_build_79, dm_build_229.dm_build_80, dm_build_230)
|
||||
dm_build_229.dm_build_80 += dm_build_230
|
||||
return dm_build_231
|
||||
}
|
||||
|
||||
func (dm_build_233 *Dm_build_78) Dm_build_232() []byte {
|
||||
return dm_build_233.Dm_build_228(int(dm_build_233.Dm_build_207()))
|
||||
}
|
||||
|
||||
func (dm_build_235 *Dm_build_78) Dm_build_234() []byte {
|
||||
return dm_build_235.Dm_build_228(int(dm_build_235.Dm_build_201()))
|
||||
}
|
||||
|
||||
func (dm_build_237 *Dm_build_78) Dm_build_236() []byte {
|
||||
return dm_build_237.Dm_build_228(int(dm_build_237.Dm_build_204()))
|
||||
}
|
||||
|
||||
func (dm_build_239 *Dm_build_78) Dm_build_238(dm_build_240 int) []byte {
|
||||
return dm_build_239.Dm_build_228(dm_build_240)
|
||||
}
|
||||
|
||||
func (dm_build_242 *Dm_build_78) Dm_build_241() []byte {
|
||||
dm_build_243 := 0
|
||||
for dm_build_242.Dm_build_201() != 0 {
|
||||
dm_build_243++
|
||||
}
|
||||
dm_build_242.Dm_build_103(dm_build_243, false, false)
|
||||
return dm_build_242.Dm_build_228(dm_build_243)
|
||||
}
|
||||
|
||||
func (dm_build_245 *Dm_build_78) Dm_build_244(dm_build_246 int, dm_build_247 string, dm_build_248 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_245.Dm_build_228(dm_build_246), dm_build_247, dm_build_248)
|
||||
}
|
||||
|
||||
func (dm_build_250 *Dm_build_78) Dm_build_249(dm_build_251 string, dm_build_252 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_250.Dm_build_232(), dm_build_251, dm_build_252)
|
||||
}
|
||||
|
||||
func (dm_build_254 *Dm_build_78) Dm_build_253(dm_build_255 string, dm_build_256 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_254.Dm_build_234(), dm_build_255, dm_build_256)
|
||||
}
|
||||
|
||||
func (dm_build_258 *Dm_build_78) Dm_build_257(dm_build_259 string, dm_build_260 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_258.Dm_build_236(), dm_build_259, dm_build_260)
|
||||
}
|
||||
|
||||
func (dm_build_262 *Dm_build_78) Dm_build_261(dm_build_263 string, dm_build_264 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_262.Dm_build_241(), dm_build_263, dm_build_264)
|
||||
}
|
||||
|
||||
func (dm_build_266 *Dm_build_78) Dm_build_265(dm_build_267 int, dm_build_268 byte) int {
|
||||
return dm_build_266.Dm_build_301(dm_build_267, Dm_build_1346.Dm_build_1524(dm_build_268))
|
||||
}
|
||||
|
||||
func (dm_build_270 *Dm_build_78) Dm_build_269(dm_build_271 int, dm_build_272 int16) int {
|
||||
return dm_build_270.Dm_build_301(dm_build_271, Dm_build_1346.Dm_build_1530(dm_build_272))
|
||||
}
|
||||
|
||||
func (dm_build_274 *Dm_build_78) Dm_build_273(dm_build_275 int, dm_build_276 int32) int {
|
||||
return dm_build_274.Dm_build_301(dm_build_275, Dm_build_1346.Dm_build_1533(dm_build_276))
|
||||
}
|
||||
|
||||
func (dm_build_278 *Dm_build_78) Dm_build_277(dm_build_279 int, dm_build_280 int64) int {
|
||||
return dm_build_278.Dm_build_301(dm_build_279, Dm_build_1346.Dm_build_1536(dm_build_280))
|
||||
}
|
||||
|
||||
func (dm_build_282 *Dm_build_78) Dm_build_281(dm_build_283 int, dm_build_284 float32) int {
|
||||
return dm_build_282.Dm_build_301(dm_build_283, Dm_build_1346.Dm_build_1539(dm_build_284))
|
||||
}
|
||||
|
||||
func (dm_build_286 *Dm_build_78) Dm_build_285(dm_build_287 int, dm_build_288 float64) int {
|
||||
return dm_build_286.Dm_build_301(dm_build_287, Dm_build_1346.Dm_build_1542(dm_build_288))
|
||||
}
|
||||
|
||||
func (dm_build_290 *Dm_build_78) Dm_build_289(dm_build_291 int, dm_build_292 uint8) int {
|
||||
return dm_build_290.Dm_build_301(dm_build_291, Dm_build_1346.Dm_build_1545(dm_build_292))
|
||||
}
|
||||
|
||||
func (dm_build_294 *Dm_build_78) Dm_build_293(dm_build_295 int, dm_build_296 uint16) int {
|
||||
return dm_build_294.Dm_build_301(dm_build_295, Dm_build_1346.Dm_build_1548(dm_build_296))
|
||||
}
|
||||
|
||||
func (dm_build_298 *Dm_build_78) Dm_build_297(dm_build_299 int, dm_build_300 uint32) int {
|
||||
return dm_build_298.Dm_build_301(dm_build_299, Dm_build_1346.Dm_build_1551(dm_build_300))
|
||||
}
|
||||
|
||||
func (dm_build_302 *Dm_build_78) Dm_build_301(dm_build_303 int, dm_build_304 []byte) int {
|
||||
return copy(dm_build_302.dm_build_79[dm_build_303:], dm_build_304)
|
||||
}
|
||||
|
||||
func (dm_build_306 *Dm_build_78) Dm_build_305(dm_build_307 int, dm_build_308 []byte) int {
|
||||
return dm_build_306.Dm_build_273(dm_build_307, int32(len(dm_build_308))) + dm_build_306.Dm_build_301(dm_build_307+4, dm_build_308)
|
||||
}
|
||||
|
||||
func (dm_build_310 *Dm_build_78) Dm_build_309(dm_build_311 int, dm_build_312 []byte) int {
|
||||
return dm_build_310.Dm_build_265(dm_build_311, byte(len(dm_build_312))) + dm_build_310.Dm_build_301(dm_build_311+1, dm_build_312)
|
||||
}
|
||||
|
||||
func (dm_build_314 *Dm_build_78) Dm_build_313(dm_build_315 int, dm_build_316 []byte) int {
|
||||
return dm_build_314.Dm_build_269(dm_build_315, int16(len(dm_build_316))) + dm_build_314.Dm_build_301(dm_build_315+2, dm_build_316)
|
||||
}
|
||||
|
||||
func (dm_build_318 *Dm_build_78) Dm_build_317(dm_build_319 int, dm_build_320 []byte) int {
|
||||
return dm_build_318.Dm_build_301(dm_build_319, dm_build_320) + dm_build_318.Dm_build_265(dm_build_319+len(dm_build_320), 0)
|
||||
}
|
||||
|
||||
func (dm_build_322 *Dm_build_78) Dm_build_321(dm_build_323 int, dm_build_324 string, dm_build_325 string, dm_build_326 *DmConnection) int {
|
||||
return dm_build_322.Dm_build_305(dm_build_323, Dm_build_1346.Dm_build_1562(dm_build_324, dm_build_325, dm_build_326))
|
||||
}
|
||||
|
||||
func (dm_build_328 *Dm_build_78) Dm_build_327(dm_build_329 int, dm_build_330 string, dm_build_331 string, dm_build_332 *DmConnection) int {
|
||||
return dm_build_328.Dm_build_309(dm_build_329, Dm_build_1346.Dm_build_1562(dm_build_330, dm_build_331, dm_build_332))
|
||||
}
|
||||
|
||||
func (dm_build_334 *Dm_build_78) Dm_build_333(dm_build_335 int, dm_build_336 string, dm_build_337 string, dm_build_338 *DmConnection) int {
|
||||
return dm_build_334.Dm_build_313(dm_build_335, Dm_build_1346.Dm_build_1562(dm_build_336, dm_build_337, dm_build_338))
|
||||
}
|
||||
|
||||
func (dm_build_340 *Dm_build_78) Dm_build_339(dm_build_341 int, dm_build_342 string, dm_build_343 string, dm_build_344 *DmConnection) int {
|
||||
return dm_build_340.Dm_build_317(dm_build_341, Dm_build_1346.Dm_build_1562(dm_build_342, dm_build_343, dm_build_344))
|
||||
}
|
||||
|
||||
func (dm_build_346 *Dm_build_78) Dm_build_345(dm_build_347 int) byte {
|
||||
return Dm_build_1346.Dm_build_1567(dm_build_346.Dm_build_372(dm_build_347, 1))
|
||||
}
|
||||
|
||||
func (dm_build_349 *Dm_build_78) Dm_build_348(dm_build_350 int) int16 {
|
||||
return Dm_build_1346.Dm_build_1570(dm_build_349.Dm_build_372(dm_build_350, 2))
|
||||
}
|
||||
|
||||
func (dm_build_352 *Dm_build_78) Dm_build_351(dm_build_353 int) int32 {
|
||||
return Dm_build_1346.Dm_build_1573(dm_build_352.Dm_build_372(dm_build_353, 4))
|
||||
}
|
||||
|
||||
func (dm_build_355 *Dm_build_78) Dm_build_354(dm_build_356 int) int64 {
|
||||
return Dm_build_1346.Dm_build_1576(dm_build_355.Dm_build_372(dm_build_356, 8))
|
||||
}
|
||||
|
||||
func (dm_build_358 *Dm_build_78) Dm_build_357(dm_build_359 int) float32 {
|
||||
return Dm_build_1346.Dm_build_1579(dm_build_358.Dm_build_372(dm_build_359, 4))
|
||||
}
|
||||
|
||||
func (dm_build_361 *Dm_build_78) Dm_build_360(dm_build_362 int) float64 {
|
||||
return Dm_build_1346.Dm_build_1582(dm_build_361.Dm_build_372(dm_build_362, 8))
|
||||
}
|
||||
|
||||
func (dm_build_364 *Dm_build_78) Dm_build_363(dm_build_365 int) uint8 {
|
||||
return Dm_build_1346.Dm_build_1585(dm_build_364.Dm_build_372(dm_build_365, 1))
|
||||
}
|
||||
|
||||
func (dm_build_367 *Dm_build_78) Dm_build_366(dm_build_368 int) uint16 {
|
||||
return Dm_build_1346.Dm_build_1588(dm_build_367.Dm_build_372(dm_build_368, 2))
|
||||
}
|
||||
|
||||
func (dm_build_370 *Dm_build_78) Dm_build_369(dm_build_371 int) uint32 {
|
||||
return Dm_build_1346.Dm_build_1591(dm_build_370.Dm_build_372(dm_build_371, 4))
|
||||
}
|
||||
|
||||
func (dm_build_373 *Dm_build_78) Dm_build_372(dm_build_374 int, dm_build_375 int) []byte {
|
||||
return dm_build_373.dm_build_79[dm_build_374 : dm_build_374+dm_build_375]
|
||||
}
|
||||
|
||||
func (dm_build_377 *Dm_build_78) Dm_build_376(dm_build_378 int) []byte {
|
||||
dm_build_379 := dm_build_377.Dm_build_351(dm_build_378)
|
||||
return dm_build_377.Dm_build_372(dm_build_378+4, int(dm_build_379))
|
||||
}
|
||||
|
||||
func (dm_build_381 *Dm_build_78) Dm_build_380(dm_build_382 int) []byte {
|
||||
dm_build_383 := dm_build_381.Dm_build_345(dm_build_382)
|
||||
return dm_build_381.Dm_build_372(dm_build_382+1, int(dm_build_383))
|
||||
}
|
||||
|
||||
func (dm_build_385 *Dm_build_78) Dm_build_384(dm_build_386 int) []byte {
|
||||
dm_build_387 := dm_build_385.Dm_build_348(dm_build_386)
|
||||
return dm_build_385.Dm_build_372(dm_build_386+2, int(dm_build_387))
|
||||
}
|
||||
|
||||
func (dm_build_389 *Dm_build_78) Dm_build_388(dm_build_390 int) []byte {
|
||||
dm_build_391 := 0
|
||||
for dm_build_389.Dm_build_345(dm_build_390) != 0 {
|
||||
dm_build_390++
|
||||
dm_build_391++
|
||||
}
|
||||
|
||||
return dm_build_389.Dm_build_372(dm_build_390-dm_build_391, int(dm_build_391))
|
||||
}
|
||||
|
||||
func (dm_build_393 *Dm_build_78) Dm_build_392(dm_build_394 int, dm_build_395 string, dm_build_396 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_393.Dm_build_376(dm_build_394), dm_build_395, dm_build_396)
|
||||
}
|
||||
|
||||
func (dm_build_398 *Dm_build_78) Dm_build_397(dm_build_399 int, dm_build_400 string, dm_build_401 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_398.Dm_build_380(dm_build_399), dm_build_400, dm_build_401)
|
||||
}
|
||||
|
||||
func (dm_build_403 *Dm_build_78) Dm_build_402(dm_build_404 int, dm_build_405 string, dm_build_406 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_403.Dm_build_384(dm_build_404), dm_build_405, dm_build_406)
|
||||
}
|
||||
|
||||
func (dm_build_408 *Dm_build_78) Dm_build_407(dm_build_409 int, dm_build_410 string, dm_build_411 *DmConnection) string {
|
||||
return Dm_build_1346.Dm_build_1598(dm_build_408.Dm_build_388(dm_build_409), dm_build_410, dm_build_411)
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"io"
|
||||
)
|
||||
|
||||
type Dm_build_0 struct {
|
||||
dm_build_1 *list.List
|
||||
dm_build_2 *dm_build_54
|
||||
dm_build_3 int
|
||||
}
|
||||
|
||||
func Dm_build_4() *Dm_build_0 {
|
||||
return &Dm_build_0{
|
||||
dm_build_1: list.New(),
|
||||
dm_build_3: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (dm_build_6 *Dm_build_0) Dm_build_5() int {
|
||||
return dm_build_6.dm_build_3
|
||||
}
|
||||
|
||||
func (dm_build_8 *Dm_build_0) Dm_build_7(dm_build_9 *Dm_build_78, dm_build_10 int) int {
|
||||
var dm_build_11 = 0
|
||||
var dm_build_12 = 0
|
||||
for dm_build_11 < dm_build_10 && dm_build_8.dm_build_2 != nil {
|
||||
dm_build_12 = dm_build_8.dm_build_2.dm_build_62(dm_build_9, dm_build_10-dm_build_11)
|
||||
if dm_build_8.dm_build_2.dm_build_57 == 0 {
|
||||
dm_build_8.dm_build_44()
|
||||
}
|
||||
dm_build_11 += dm_build_12
|
||||
dm_build_8.dm_build_3 -= dm_build_12
|
||||
}
|
||||
return dm_build_11
|
||||
}
|
||||
|
||||
func (dm_build_14 *Dm_build_0) Dm_build_13(dm_build_15 []byte, dm_build_16 int, dm_build_17 int) int {
|
||||
var dm_build_18 = 0
|
||||
var dm_build_19 = 0
|
||||
for dm_build_18 < dm_build_17 && dm_build_14.dm_build_2 != nil {
|
||||
dm_build_19 = dm_build_14.dm_build_2.dm_build_66(dm_build_15, dm_build_16, dm_build_17-dm_build_18)
|
||||
if dm_build_14.dm_build_2.dm_build_57 == 0 {
|
||||
dm_build_14.dm_build_44()
|
||||
}
|
||||
dm_build_18 += dm_build_19
|
||||
dm_build_14.dm_build_3 -= dm_build_19
|
||||
dm_build_16 += dm_build_19
|
||||
}
|
||||
return dm_build_18
|
||||
}
|
||||
|
||||
func (dm_build_21 *Dm_build_0) Dm_build_20(dm_build_22 io.Writer, dm_build_23 int) int {
|
||||
var dm_build_24 = 0
|
||||
var dm_build_25 = 0
|
||||
for dm_build_24 < dm_build_23 && dm_build_21.dm_build_2 != nil {
|
||||
dm_build_25 = dm_build_21.dm_build_2.dm_build_71(dm_build_22, dm_build_23-dm_build_24)
|
||||
if dm_build_21.dm_build_2.dm_build_57 == 0 {
|
||||
dm_build_21.dm_build_44()
|
||||
}
|
||||
dm_build_24 += dm_build_25
|
||||
dm_build_21.dm_build_3 -= dm_build_25
|
||||
}
|
||||
return dm_build_24
|
||||
}
|
||||
|
||||
func (dm_build_27 *Dm_build_0) Dm_build_26(dm_build_28 []byte, dm_build_29 int, dm_build_30 int) {
|
||||
if dm_build_30 == 0 {
|
||||
return
|
||||
}
|
||||
var dm_build_31 = dm_build_58(dm_build_28, dm_build_29, dm_build_30)
|
||||
if dm_build_27.dm_build_2 == nil {
|
||||
dm_build_27.dm_build_2 = dm_build_31
|
||||
} else {
|
||||
dm_build_27.dm_build_1.PushBack(dm_build_31)
|
||||
}
|
||||
dm_build_27.dm_build_3 += dm_build_30
|
||||
}
|
||||
|
||||
func (dm_build_33 *Dm_build_0) dm_build_32(dm_build_34 int) byte {
|
||||
var dm_build_35 = dm_build_34
|
||||
var dm_build_36 = dm_build_33.dm_build_2
|
||||
for dm_build_35 > 0 && dm_build_36 != nil {
|
||||
if dm_build_36.dm_build_57 == 0 {
|
||||
continue
|
||||
}
|
||||
if dm_build_35 > dm_build_36.dm_build_57-1 {
|
||||
dm_build_35 -= dm_build_36.dm_build_57
|
||||
dm_build_36 = dm_build_33.dm_build_1.Front().Value.(*dm_build_54)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return dm_build_36.dm_build_75(dm_build_35)
|
||||
}
|
||||
func (dm_build_38 *Dm_build_0) Dm_build_37(dm_build_39 *Dm_build_0) {
|
||||
if dm_build_39.dm_build_3 == 0 {
|
||||
return
|
||||
}
|
||||
var dm_build_40 = dm_build_39.dm_build_2
|
||||
for dm_build_40 != nil {
|
||||
dm_build_38.dm_build_41(dm_build_40)
|
||||
dm_build_39.dm_build_44()
|
||||
dm_build_40 = dm_build_39.dm_build_2
|
||||
}
|
||||
dm_build_39.dm_build_3 = 0
|
||||
}
|
||||
func (dm_build_42 *Dm_build_0) dm_build_41(dm_build_43 *dm_build_54) {
|
||||
if dm_build_43.dm_build_57 == 0 {
|
||||
return
|
||||
}
|
||||
if dm_build_42.dm_build_2 == nil {
|
||||
dm_build_42.dm_build_2 = dm_build_43
|
||||
} else {
|
||||
dm_build_42.dm_build_1.PushBack(dm_build_43)
|
||||
}
|
||||
dm_build_42.dm_build_3 += dm_build_43.dm_build_57
|
||||
}
|
||||
|
||||
func (dm_build_45 *Dm_build_0) dm_build_44() {
|
||||
var dm_build_46 = dm_build_45.dm_build_1.Front()
|
||||
if dm_build_46 == nil {
|
||||
dm_build_45.dm_build_2 = nil
|
||||
} else {
|
||||
dm_build_45.dm_build_2 = dm_build_46.Value.(*dm_build_54)
|
||||
dm_build_45.dm_build_1.Remove(dm_build_46)
|
||||
}
|
||||
}
|
||||
|
||||
func (dm_build_48 *Dm_build_0) Dm_build_47() []byte {
|
||||
var dm_build_49 = make([]byte, dm_build_48.dm_build_3)
|
||||
var dm_build_50 = dm_build_48.dm_build_2
|
||||
var dm_build_51 = 0
|
||||
var dm_build_52 = len(dm_build_49)
|
||||
var dm_build_53 = 0
|
||||
for dm_build_50 != nil {
|
||||
if dm_build_50.dm_build_57 > 0 {
|
||||
if dm_build_52 > dm_build_50.dm_build_57 {
|
||||
dm_build_53 = dm_build_50.dm_build_57
|
||||
} else {
|
||||
dm_build_53 = dm_build_52
|
||||
}
|
||||
copy(dm_build_49[dm_build_51:dm_build_51+dm_build_53], dm_build_50.dm_build_55[dm_build_50.dm_build_56:dm_build_50.dm_build_56+dm_build_53])
|
||||
dm_build_51 += dm_build_53
|
||||
dm_build_52 -= dm_build_53
|
||||
}
|
||||
if dm_build_48.dm_build_1.Front() == nil {
|
||||
dm_build_50 = nil
|
||||
} else {
|
||||
dm_build_50 = dm_build_48.dm_build_1.Front().Value.(*dm_build_54)
|
||||
}
|
||||
}
|
||||
return dm_build_49
|
||||
}
|
||||
|
||||
type dm_build_54 struct {
|
||||
dm_build_55 []byte
|
||||
dm_build_56 int
|
||||
dm_build_57 int
|
||||
}
|
||||
|
||||
func dm_build_58(dm_build_59 []byte, dm_build_60 int, dm_build_61 int) *dm_build_54 {
|
||||
return &dm_build_54{
|
||||
dm_build_59,
|
||||
dm_build_60,
|
||||
dm_build_61,
|
||||
}
|
||||
}
|
||||
|
||||
func (dm_build_63 *dm_build_54) dm_build_62(dm_build_64 *Dm_build_78, dm_build_65 int) int {
|
||||
if dm_build_63.dm_build_57 <= dm_build_65 {
|
||||
dm_build_65 = dm_build_63.dm_build_57
|
||||
}
|
||||
dm_build_64.Dm_build_161(dm_build_63.dm_build_55[dm_build_63.dm_build_56 : dm_build_63.dm_build_56+dm_build_65])
|
||||
dm_build_63.dm_build_56 += dm_build_65
|
||||
dm_build_63.dm_build_57 -= dm_build_65
|
||||
return dm_build_65
|
||||
}
|
||||
|
||||
func (dm_build_67 *dm_build_54) dm_build_66(dm_build_68 []byte, dm_build_69 int, dm_build_70 int) int {
|
||||
if dm_build_67.dm_build_57 <= dm_build_70 {
|
||||
dm_build_70 = dm_build_67.dm_build_57
|
||||
}
|
||||
copy(dm_build_68[dm_build_69:dm_build_69+dm_build_70], dm_build_67.dm_build_55[dm_build_67.dm_build_56:dm_build_67.dm_build_56+dm_build_70])
|
||||
dm_build_67.dm_build_56 += dm_build_70
|
||||
dm_build_67.dm_build_57 -= dm_build_70
|
||||
return dm_build_70
|
||||
}
|
||||
|
||||
func (dm_build_72 *dm_build_54) dm_build_71(dm_build_73 io.Writer, dm_build_74 int) int {
|
||||
if dm_build_72.dm_build_57 <= dm_build_74 {
|
||||
dm_build_74 = dm_build_72.dm_build_57
|
||||
}
|
||||
dm_build_73.Write(dm_build_72.dm_build_55[dm_build_72.dm_build_56 : dm_build_72.dm_build_56+dm_build_74])
|
||||
dm_build_72.dm_build_56 += dm_build_74
|
||||
dm_build_72.dm_build_57 -= dm_build_74
|
||||
return dm_build_74
|
||||
}
|
||||
func (dm_build_76 *dm_build_54) dm_build_75(dm_build_77 int) byte {
|
||||
return dm_build_76.dm_build_55[dm_build_76.dm_build_56+dm_build_77]
|
||||
}
|
||||
+522
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/ianaindex"
|
||||
"golang.org/x/text/transform"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
)
|
||||
|
||||
type dm_build_1345 struct{}
|
||||
|
||||
var Dm_build_1346 = &dm_build_1345{}
|
||||
|
||||
func (Dm_build_1348 *dm_build_1345) Dm_build_1347(dm_build_1349 []byte, dm_build_1350 int, dm_build_1351 byte) int {
|
||||
dm_build_1349[dm_build_1350] = dm_build_1351
|
||||
return 1
|
||||
}
|
||||
|
||||
func (Dm_build_1353 *dm_build_1345) Dm_build_1352(dm_build_1354 []byte, dm_build_1355 int, dm_build_1356 int8) int {
|
||||
dm_build_1354[dm_build_1355] = byte(dm_build_1356)
|
||||
return 1
|
||||
}
|
||||
|
||||
func (Dm_build_1358 *dm_build_1345) Dm_build_1357(dm_build_1359 []byte, dm_build_1360 int, dm_build_1361 int16) int {
|
||||
dm_build_1359[dm_build_1360] = byte(dm_build_1361)
|
||||
dm_build_1360++
|
||||
dm_build_1359[dm_build_1360] = byte(dm_build_1361 >> 8)
|
||||
return 2
|
||||
}
|
||||
|
||||
func (Dm_build_1363 *dm_build_1345) Dm_build_1362(dm_build_1364 []byte, dm_build_1365 int, dm_build_1366 int32) int {
|
||||
dm_build_1364[dm_build_1365] = byte(dm_build_1366)
|
||||
dm_build_1365++
|
||||
dm_build_1364[dm_build_1365] = byte(dm_build_1366 >> 8)
|
||||
dm_build_1365++
|
||||
dm_build_1364[dm_build_1365] = byte(dm_build_1366 >> 16)
|
||||
dm_build_1365++
|
||||
dm_build_1364[dm_build_1365] = byte(dm_build_1366 >> 24)
|
||||
dm_build_1365++
|
||||
return 4
|
||||
}
|
||||
|
||||
func (Dm_build_1368 *dm_build_1345) Dm_build_1367(dm_build_1369 []byte, dm_build_1370 int, dm_build_1371 int64) int {
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371)
|
||||
dm_build_1370++
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 8)
|
||||
dm_build_1370++
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 16)
|
||||
dm_build_1370++
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 24)
|
||||
dm_build_1370++
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 32)
|
||||
dm_build_1370++
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 40)
|
||||
dm_build_1370++
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 48)
|
||||
dm_build_1370++
|
||||
dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 56)
|
||||
return 8
|
||||
}
|
||||
|
||||
func (Dm_build_1373 *dm_build_1345) Dm_build_1372(dm_build_1374 []byte, dm_build_1375 int, dm_build_1376 float32) int {
|
||||
return Dm_build_1373.Dm_build_1392(dm_build_1374, dm_build_1375, math.Float32bits(dm_build_1376))
|
||||
}
|
||||
|
||||
func (Dm_build_1378 *dm_build_1345) Dm_build_1377(dm_build_1379 []byte, dm_build_1380 int, dm_build_1381 float64) int {
|
||||
return Dm_build_1378.Dm_build_1397(dm_build_1379, dm_build_1380, math.Float64bits(dm_build_1381))
|
||||
}
|
||||
|
||||
func (Dm_build_1383 *dm_build_1345) Dm_build_1382(dm_build_1384 []byte, dm_build_1385 int, dm_build_1386 uint8) int {
|
||||
dm_build_1384[dm_build_1385] = byte(dm_build_1386)
|
||||
return 1
|
||||
}
|
||||
|
||||
func (Dm_build_1388 *dm_build_1345) Dm_build_1387(dm_build_1389 []byte, dm_build_1390 int, dm_build_1391 uint16) int {
|
||||
dm_build_1389[dm_build_1390] = byte(dm_build_1391)
|
||||
dm_build_1390++
|
||||
dm_build_1389[dm_build_1390] = byte(dm_build_1391 >> 8)
|
||||
return 2
|
||||
}
|
||||
|
||||
func (Dm_build_1393 *dm_build_1345) Dm_build_1392(dm_build_1394 []byte, dm_build_1395 int, dm_build_1396 uint32) int {
|
||||
dm_build_1394[dm_build_1395] = byte(dm_build_1396)
|
||||
dm_build_1395++
|
||||
dm_build_1394[dm_build_1395] = byte(dm_build_1396 >> 8)
|
||||
dm_build_1395++
|
||||
dm_build_1394[dm_build_1395] = byte(dm_build_1396 >> 16)
|
||||
dm_build_1395++
|
||||
dm_build_1394[dm_build_1395] = byte(dm_build_1396 >> 24)
|
||||
return 3
|
||||
}
|
||||
|
||||
func (Dm_build_1398 *dm_build_1345) Dm_build_1397(dm_build_1399 []byte, dm_build_1400 int, dm_build_1401 uint64) int {
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401)
|
||||
dm_build_1400++
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 8)
|
||||
dm_build_1400++
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 16)
|
||||
dm_build_1400++
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 24)
|
||||
dm_build_1400++
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 32)
|
||||
dm_build_1400++
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 40)
|
||||
dm_build_1400++
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 48)
|
||||
dm_build_1400++
|
||||
dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 56)
|
||||
return 3
|
||||
}
|
||||
|
||||
func (Dm_build_1403 *dm_build_1345) Dm_build_1402(dm_build_1404 []byte, dm_build_1405 int, dm_build_1406 []byte, dm_build_1407 int, dm_build_1408 int) int {
|
||||
copy(dm_build_1404[dm_build_1405:dm_build_1405+dm_build_1408], dm_build_1406[dm_build_1407:dm_build_1407+dm_build_1408])
|
||||
return dm_build_1408
|
||||
}
|
||||
|
||||
func (Dm_build_1410 *dm_build_1345) Dm_build_1409(dm_build_1411 []byte, dm_build_1412 int, dm_build_1413 []byte, dm_build_1414 int, dm_build_1415 int) int {
|
||||
dm_build_1412 += Dm_build_1410.Dm_build_1392(dm_build_1411, dm_build_1412, uint32(dm_build_1415))
|
||||
return 4 + Dm_build_1410.Dm_build_1402(dm_build_1411, dm_build_1412, dm_build_1413, dm_build_1414, dm_build_1415)
|
||||
}
|
||||
|
||||
func (Dm_build_1417 *dm_build_1345) Dm_build_1416(dm_build_1418 []byte, dm_build_1419 int, dm_build_1420 []byte, dm_build_1421 int, dm_build_1422 int) int {
|
||||
dm_build_1419 += Dm_build_1417.Dm_build_1387(dm_build_1418, dm_build_1419, uint16(dm_build_1422))
|
||||
return 2 + Dm_build_1417.Dm_build_1402(dm_build_1418, dm_build_1419, dm_build_1420, dm_build_1421, dm_build_1422)
|
||||
}
|
||||
|
||||
func (Dm_build_1424 *dm_build_1345) Dm_build_1423(dm_build_1425 []byte, dm_build_1426 int, dm_build_1427 string, dm_build_1428 string, dm_build_1429 *DmConnection) int {
|
||||
dm_build_1430 := Dm_build_1424.Dm_build_1562(dm_build_1427, dm_build_1428, dm_build_1429)
|
||||
dm_build_1426 += Dm_build_1424.Dm_build_1392(dm_build_1425, dm_build_1426, uint32(len(dm_build_1430)))
|
||||
return 4 + Dm_build_1424.Dm_build_1402(dm_build_1425, dm_build_1426, dm_build_1430, 0, len(dm_build_1430))
|
||||
}
|
||||
|
||||
func (Dm_build_1432 *dm_build_1345) Dm_build_1431(dm_build_1433 []byte, dm_build_1434 int, dm_build_1435 string, dm_build_1436 string, dm_build_1437 *DmConnection) int {
|
||||
dm_build_1438 := Dm_build_1432.Dm_build_1562(dm_build_1435, dm_build_1436, dm_build_1437)
|
||||
|
||||
dm_build_1434 += Dm_build_1432.Dm_build_1387(dm_build_1433, dm_build_1434, uint16(len(dm_build_1438)))
|
||||
return 2 + Dm_build_1432.Dm_build_1402(dm_build_1433, dm_build_1434, dm_build_1438, 0, len(dm_build_1438))
|
||||
}
|
||||
|
||||
func (Dm_build_1440 *dm_build_1345) Dm_build_1439(dm_build_1441 []byte, dm_build_1442 int) byte {
|
||||
return dm_build_1441[dm_build_1442]
|
||||
}
|
||||
|
||||
func (Dm_build_1444 *dm_build_1345) Dm_build_1443(dm_build_1445 []byte, dm_build_1446 int) int16 {
|
||||
var dm_build_1447 int16
|
||||
dm_build_1447 = int16(dm_build_1445[dm_build_1446] & 0xff)
|
||||
dm_build_1446++
|
||||
dm_build_1447 |= int16(dm_build_1445[dm_build_1446]&0xff) << 8
|
||||
return dm_build_1447
|
||||
}
|
||||
|
||||
func (Dm_build_1449 *dm_build_1345) Dm_build_1448(dm_build_1450 []byte, dm_build_1451 int) int32 {
|
||||
var dm_build_1452 int32
|
||||
dm_build_1452 = int32(dm_build_1450[dm_build_1451] & 0xff)
|
||||
dm_build_1451++
|
||||
dm_build_1452 |= int32(dm_build_1450[dm_build_1451]&0xff) << 8
|
||||
dm_build_1451++
|
||||
dm_build_1452 |= int32(dm_build_1450[dm_build_1451]&0xff) << 16
|
||||
dm_build_1451++
|
||||
dm_build_1452 |= int32(dm_build_1450[dm_build_1451]&0xff) << 24
|
||||
return dm_build_1452
|
||||
}
|
||||
|
||||
func (Dm_build_1454 *dm_build_1345) Dm_build_1453(dm_build_1455 []byte, dm_build_1456 int) int64 {
|
||||
var dm_build_1457 int64
|
||||
dm_build_1457 = int64(dm_build_1455[dm_build_1456] & 0xff)
|
||||
dm_build_1456++
|
||||
dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 8
|
||||
dm_build_1456++
|
||||
dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 16
|
||||
dm_build_1456++
|
||||
dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 24
|
||||
dm_build_1456++
|
||||
dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 32
|
||||
dm_build_1456++
|
||||
dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 40
|
||||
dm_build_1456++
|
||||
dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 48
|
||||
dm_build_1456++
|
||||
dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 56
|
||||
return dm_build_1457
|
||||
}
|
||||
|
||||
func (Dm_build_1459 *dm_build_1345) Dm_build_1458(dm_build_1460 []byte, dm_build_1461 int) float32 {
|
||||
return math.Float32frombits(Dm_build_1459.Dm_build_1475(dm_build_1460, dm_build_1461))
|
||||
}
|
||||
|
||||
func (Dm_build_1463 *dm_build_1345) Dm_build_1462(dm_build_1464 []byte, dm_build_1465 int) float64 {
|
||||
return math.Float64frombits(Dm_build_1463.Dm_build_1480(dm_build_1464, dm_build_1465))
|
||||
}
|
||||
|
||||
func (Dm_build_1467 *dm_build_1345) Dm_build_1466(dm_build_1468 []byte, dm_build_1469 int) uint8 {
|
||||
return uint8(dm_build_1468[dm_build_1469] & 0xff)
|
||||
}
|
||||
|
||||
func (Dm_build_1471 *dm_build_1345) Dm_build_1470(dm_build_1472 []byte, dm_build_1473 int) uint16 {
|
||||
var dm_build_1474 uint16
|
||||
dm_build_1474 = uint16(dm_build_1472[dm_build_1473] & 0xff)
|
||||
dm_build_1473++
|
||||
dm_build_1474 |= uint16(dm_build_1472[dm_build_1473]&0xff) << 8
|
||||
return dm_build_1474
|
||||
}
|
||||
|
||||
func (Dm_build_1476 *dm_build_1345) Dm_build_1475(dm_build_1477 []byte, dm_build_1478 int) uint32 {
|
||||
var dm_build_1479 uint32
|
||||
dm_build_1479 = uint32(dm_build_1477[dm_build_1478] & 0xff)
|
||||
dm_build_1478++
|
||||
dm_build_1479 |= uint32(dm_build_1477[dm_build_1478]&0xff) << 8
|
||||
dm_build_1478++
|
||||
dm_build_1479 |= uint32(dm_build_1477[dm_build_1478]&0xff) << 16
|
||||
dm_build_1478++
|
||||
dm_build_1479 |= uint32(dm_build_1477[dm_build_1478]&0xff) << 24
|
||||
return dm_build_1479
|
||||
}
|
||||
|
||||
func (Dm_build_1481 *dm_build_1345) Dm_build_1480(dm_build_1482 []byte, dm_build_1483 int) uint64 {
|
||||
var dm_build_1484 uint64
|
||||
dm_build_1484 = uint64(dm_build_1482[dm_build_1483] & 0xff)
|
||||
dm_build_1483++
|
||||
dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 8
|
||||
dm_build_1483++
|
||||
dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 16
|
||||
dm_build_1483++
|
||||
dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 24
|
||||
dm_build_1483++
|
||||
dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 32
|
||||
dm_build_1483++
|
||||
dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 40
|
||||
dm_build_1483++
|
||||
dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 48
|
||||
dm_build_1483++
|
||||
dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 56
|
||||
return dm_build_1484
|
||||
}
|
||||
|
||||
func (Dm_build_1486 *dm_build_1345) Dm_build_1485(dm_build_1487 []byte, dm_build_1488 int) []byte {
|
||||
dm_build_1489 := Dm_build_1486.Dm_build_1475(dm_build_1487, dm_build_1488)
|
||||
|
||||
dm_build_1490 := make([]byte, dm_build_1489)
|
||||
copy(dm_build_1490[:int(dm_build_1489)], dm_build_1487[dm_build_1488+4:dm_build_1488+4+int(dm_build_1489)])
|
||||
return dm_build_1490
|
||||
}
|
||||
|
||||
func (Dm_build_1492 *dm_build_1345) Dm_build_1491(dm_build_1493 []byte, dm_build_1494 int) []byte {
|
||||
dm_build_1495 := Dm_build_1492.Dm_build_1470(dm_build_1493, dm_build_1494)
|
||||
|
||||
dm_build_1496 := make([]byte, dm_build_1495)
|
||||
copy(dm_build_1496[:int(dm_build_1495)], dm_build_1493[dm_build_1494+2:dm_build_1494+2+int(dm_build_1495)])
|
||||
return dm_build_1496
|
||||
}
|
||||
|
||||
func (Dm_build_1498 *dm_build_1345) Dm_build_1497(dm_build_1499 []byte, dm_build_1500 int, dm_build_1501 int) []byte {
|
||||
|
||||
dm_build_1502 := make([]byte, dm_build_1501)
|
||||
copy(dm_build_1502[:dm_build_1501], dm_build_1499[dm_build_1500:dm_build_1500+dm_build_1501])
|
||||
return dm_build_1502
|
||||
}
|
||||
|
||||
func (Dm_build_1504 *dm_build_1345) Dm_build_1503(dm_build_1505 []byte, dm_build_1506 int, dm_build_1507 int, dm_build_1508 string, dm_build_1509 *DmConnection) string {
|
||||
return Dm_build_1504.Dm_build_1598(dm_build_1505[dm_build_1506:dm_build_1506+dm_build_1507], dm_build_1508, dm_build_1509)
|
||||
}
|
||||
|
||||
func (Dm_build_1511 *dm_build_1345) Dm_build_1510(dm_build_1512 []byte, dm_build_1513 int, dm_build_1514 string, dm_build_1515 *DmConnection) string {
|
||||
dm_build_1516 := Dm_build_1511.Dm_build_1475(dm_build_1512, dm_build_1513)
|
||||
dm_build_1513 += 4
|
||||
return Dm_build_1511.Dm_build_1503(dm_build_1512, dm_build_1513, int(dm_build_1516), dm_build_1514, dm_build_1515)
|
||||
}
|
||||
|
||||
func (Dm_build_1518 *dm_build_1345) Dm_build_1517(dm_build_1519 []byte, dm_build_1520 int, dm_build_1521 string, dm_build_1522 *DmConnection) string {
|
||||
dm_build_1523 := Dm_build_1518.Dm_build_1470(dm_build_1519, dm_build_1520)
|
||||
dm_build_1520 += 2
|
||||
return Dm_build_1518.Dm_build_1503(dm_build_1519, dm_build_1520, int(dm_build_1523), dm_build_1521, dm_build_1522)
|
||||
}
|
||||
|
||||
func (Dm_build_1525 *dm_build_1345) Dm_build_1524(dm_build_1526 byte) []byte {
|
||||
return []byte{dm_build_1526}
|
||||
}
|
||||
|
||||
func (Dm_build_1528 *dm_build_1345) Dm_build_1527(dm_build_1529 int8) []byte {
|
||||
return []byte{byte(dm_build_1529)}
|
||||
}
|
||||
|
||||
func (Dm_build_1531 *dm_build_1345) Dm_build_1530(dm_build_1532 int16) []byte {
|
||||
return []byte{byte(dm_build_1532), byte(dm_build_1532 >> 8)}
|
||||
}
|
||||
|
||||
func (Dm_build_1534 *dm_build_1345) Dm_build_1533(dm_build_1535 int32) []byte {
|
||||
return []byte{byte(dm_build_1535), byte(dm_build_1535 >> 8), byte(dm_build_1535 >> 16), byte(dm_build_1535 >> 24)}
|
||||
}
|
||||
|
||||
func (Dm_build_1537 *dm_build_1345) Dm_build_1536(dm_build_1538 int64) []byte {
|
||||
return []byte{byte(dm_build_1538), byte(dm_build_1538 >> 8), byte(dm_build_1538 >> 16), byte(dm_build_1538 >> 24), byte(dm_build_1538 >> 32),
|
||||
byte(dm_build_1538 >> 40), byte(dm_build_1538 >> 48), byte(dm_build_1538 >> 56)}
|
||||
}
|
||||
|
||||
func (Dm_build_1540 *dm_build_1345) Dm_build_1539(dm_build_1541 float32) []byte {
|
||||
return Dm_build_1540.Dm_build_1551(math.Float32bits(dm_build_1541))
|
||||
}
|
||||
|
||||
func (Dm_build_1543 *dm_build_1345) Dm_build_1542(dm_build_1544 float64) []byte {
|
||||
return Dm_build_1543.Dm_build_1554(math.Float64bits(dm_build_1544))
|
||||
}
|
||||
|
||||
func (Dm_build_1546 *dm_build_1345) Dm_build_1545(dm_build_1547 uint8) []byte {
|
||||
return []byte{byte(dm_build_1547)}
|
||||
}
|
||||
|
||||
func (Dm_build_1549 *dm_build_1345) Dm_build_1548(dm_build_1550 uint16) []byte {
|
||||
return []byte{byte(dm_build_1550), byte(dm_build_1550 >> 8)}
|
||||
}
|
||||
|
||||
func (Dm_build_1552 *dm_build_1345) Dm_build_1551(dm_build_1553 uint32) []byte {
|
||||
return []byte{byte(dm_build_1553), byte(dm_build_1553 >> 8), byte(dm_build_1553 >> 16), byte(dm_build_1553 >> 24)}
|
||||
}
|
||||
|
||||
func (Dm_build_1555 *dm_build_1345) Dm_build_1554(dm_build_1556 uint64) []byte {
|
||||
return []byte{byte(dm_build_1556), byte(dm_build_1556 >> 8), byte(dm_build_1556 >> 16), byte(dm_build_1556 >> 24), byte(dm_build_1556 >> 32), byte(dm_build_1556 >> 40), byte(dm_build_1556 >> 48), byte(dm_build_1556 >> 56)}
|
||||
}
|
||||
|
||||
func (Dm_build_1558 *dm_build_1345) Dm_build_1557(dm_build_1559 []byte, dm_build_1560 string, dm_build_1561 *DmConnection) []byte {
|
||||
if dm_build_1560 == "UTF-8" {
|
||||
return dm_build_1559
|
||||
}
|
||||
|
||||
if dm_build_1561 == nil {
|
||||
if e := dm_build_1603(dm_build_1560); e != nil {
|
||||
tmp, err := ioutil.ReadAll(
|
||||
transform.NewReader(bytes.NewReader(dm_build_1559), e.NewEncoder()),
|
||||
)
|
||||
if err != nil {
|
||||
panic("UTF8 To Charset error!")
|
||||
}
|
||||
|
||||
return tmp
|
||||
}
|
||||
|
||||
panic("Unsupported Charset!")
|
||||
}
|
||||
|
||||
if dm_build_1561.encodeBuffer == nil {
|
||||
dm_build_1561.encodeBuffer = bytes.NewBuffer(nil)
|
||||
dm_build_1561.encode = dm_build_1603(dm_build_1561.getServerEncoding())
|
||||
dm_build_1561.transformReaderDst = make([]byte, 4096)
|
||||
dm_build_1561.transformReaderSrc = make([]byte, 4096)
|
||||
}
|
||||
|
||||
if e := dm_build_1561.encode; e != nil {
|
||||
|
||||
dm_build_1561.encodeBuffer.Reset()
|
||||
|
||||
n, err := dm_build_1561.encodeBuffer.ReadFrom(
|
||||
Dm_build_1617(bytes.NewReader(dm_build_1559), e.NewEncoder(), dm_build_1561.transformReaderDst, dm_build_1561.transformReaderSrc),
|
||||
)
|
||||
if err != nil {
|
||||
panic("UTF8 To Charset error!")
|
||||
}
|
||||
var tmp = make([]byte, n)
|
||||
if _, err = dm_build_1561.encodeBuffer.Read(tmp); err != nil {
|
||||
panic("UTF8 To Charset error!")
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
panic("Unsupported Charset!")
|
||||
}
|
||||
|
||||
func (Dm_build_1563 *dm_build_1345) Dm_build_1562(dm_build_1564 string, dm_build_1565 string, dm_build_1566 *DmConnection) []byte {
|
||||
return Dm_build_1563.Dm_build_1557([]byte(dm_build_1564), dm_build_1565, dm_build_1566)
|
||||
}
|
||||
|
||||
func (Dm_build_1568 *dm_build_1345) Dm_build_1567(dm_build_1569 []byte) byte {
|
||||
return Dm_build_1568.Dm_build_1439(dm_build_1569, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1571 *dm_build_1345) Dm_build_1570(dm_build_1572 []byte) int16 {
|
||||
return Dm_build_1571.Dm_build_1443(dm_build_1572, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1574 *dm_build_1345) Dm_build_1573(dm_build_1575 []byte) int32 {
|
||||
return Dm_build_1574.Dm_build_1448(dm_build_1575, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1577 *dm_build_1345) Dm_build_1576(dm_build_1578 []byte) int64 {
|
||||
return Dm_build_1577.Dm_build_1453(dm_build_1578, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1580 *dm_build_1345) Dm_build_1579(dm_build_1581 []byte) float32 {
|
||||
return Dm_build_1580.Dm_build_1458(dm_build_1581, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1583 *dm_build_1345) Dm_build_1582(dm_build_1584 []byte) float64 {
|
||||
return Dm_build_1583.Dm_build_1462(dm_build_1584, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1586 *dm_build_1345) Dm_build_1585(dm_build_1587 []byte) uint8 {
|
||||
return Dm_build_1586.Dm_build_1466(dm_build_1587, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1589 *dm_build_1345) Dm_build_1588(dm_build_1590 []byte) uint16 {
|
||||
return Dm_build_1589.Dm_build_1470(dm_build_1590, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1592 *dm_build_1345) Dm_build_1591(dm_build_1593 []byte) uint32 {
|
||||
return Dm_build_1592.Dm_build_1475(dm_build_1593, 0)
|
||||
}
|
||||
|
||||
func (Dm_build_1595 *dm_build_1345) Dm_build_1594(dm_build_1596 []byte, dm_build_1597 string) []byte {
|
||||
if dm_build_1597 == "UTF-8" {
|
||||
return dm_build_1596
|
||||
}
|
||||
|
||||
if e := dm_build_1603(dm_build_1597); e != nil {
|
||||
|
||||
tmp, err := ioutil.ReadAll(
|
||||
transform.NewReader(bytes.NewReader(dm_build_1596), e.NewDecoder()),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
panic("Charset To UTF8 error!")
|
||||
}
|
||||
|
||||
return tmp
|
||||
}
|
||||
|
||||
panic("Unsupported Charset!")
|
||||
|
||||
}
|
||||
|
||||
func (Dm_build_1599 *dm_build_1345) Dm_build_1598(dm_build_1600 []byte, dm_build_1601 string, dm_build_1602 *DmConnection) string {
|
||||
return string(Dm_build_1599.Dm_build_1594(dm_build_1600, dm_build_1601))
|
||||
}
|
||||
|
||||
func dm_build_1603(dm_build_1604 string) encoding.Encoding {
|
||||
if e, err := ianaindex.MIB.Encoding(dm_build_1604); err == nil && e != nil {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Dm_build_1605 struct {
|
||||
dm_build_1606 io.Reader
|
||||
dm_build_1607 transform.Transformer
|
||||
dm_build_1608 error
|
||||
|
||||
dm_build_1609 []byte
|
||||
dm_build_1610, dm_build_1611 int
|
||||
|
||||
dm_build_1612 []byte
|
||||
dm_build_1613, dm_build_1614 int
|
||||
|
||||
dm_build_1615 bool
|
||||
}
|
||||
|
||||
const dm_build_1616 = 4096
|
||||
|
||||
func Dm_build_1617(dm_build_1618 io.Reader, dm_build_1619 transform.Transformer, dm_build_1620 []byte, dm_build_1621 []byte) *Dm_build_1605 {
|
||||
dm_build_1619.Reset()
|
||||
return &Dm_build_1605{
|
||||
dm_build_1606: dm_build_1618,
|
||||
dm_build_1607: dm_build_1619,
|
||||
dm_build_1609: dm_build_1620,
|
||||
dm_build_1612: dm_build_1621,
|
||||
}
|
||||
}
|
||||
|
||||
func (dm_build_1623 *Dm_build_1605) Read(dm_build_1624 []byte) (int, error) {
|
||||
dm_build_1625, dm_build_1626 := 0, error(nil)
|
||||
for {
|
||||
|
||||
if dm_build_1623.dm_build_1610 != dm_build_1623.dm_build_1611 {
|
||||
dm_build_1625 = copy(dm_build_1624, dm_build_1623.dm_build_1609[dm_build_1623.dm_build_1610:dm_build_1623.dm_build_1611])
|
||||
dm_build_1623.dm_build_1610 += dm_build_1625
|
||||
if dm_build_1623.dm_build_1610 == dm_build_1623.dm_build_1611 && dm_build_1623.dm_build_1615 {
|
||||
return dm_build_1625, dm_build_1623.dm_build_1608
|
||||
}
|
||||
return dm_build_1625, nil
|
||||
} else if dm_build_1623.dm_build_1615 {
|
||||
return 0, dm_build_1623.dm_build_1608
|
||||
}
|
||||
|
||||
if dm_build_1623.dm_build_1613 != dm_build_1623.dm_build_1614 || dm_build_1623.dm_build_1608 != nil {
|
||||
dm_build_1623.dm_build_1610 = 0
|
||||
dm_build_1623.dm_build_1611, dm_build_1625, dm_build_1626 = dm_build_1623.dm_build_1607.Transform(dm_build_1623.dm_build_1609, dm_build_1623.dm_build_1612[dm_build_1623.dm_build_1613:dm_build_1623.dm_build_1614], dm_build_1623.dm_build_1608 == io.EOF)
|
||||
dm_build_1623.dm_build_1613 += dm_build_1625
|
||||
|
||||
switch {
|
||||
case dm_build_1626 == nil:
|
||||
if dm_build_1623.dm_build_1613 != dm_build_1623.dm_build_1614 {
|
||||
dm_build_1623.dm_build_1608 = nil
|
||||
}
|
||||
|
||||
dm_build_1623.dm_build_1615 = dm_build_1623.dm_build_1608 != nil
|
||||
continue
|
||||
case dm_build_1626 == transform.ErrShortDst && (dm_build_1623.dm_build_1611 != 0 || dm_build_1625 != 0):
|
||||
|
||||
continue
|
||||
case dm_build_1626 == transform.ErrShortSrc && dm_build_1623.dm_build_1614-dm_build_1623.dm_build_1613 != len(dm_build_1623.dm_build_1612) && dm_build_1623.dm_build_1608 == nil:
|
||||
|
||||
default:
|
||||
dm_build_1623.dm_build_1615 = true
|
||||
|
||||
if dm_build_1623.dm_build_1608 == nil || dm_build_1623.dm_build_1608 == io.EOF {
|
||||
dm_build_1623.dm_build_1608 = dm_build_1626
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if dm_build_1623.dm_build_1613 != 0 {
|
||||
dm_build_1623.dm_build_1613, dm_build_1623.dm_build_1614 = 0, copy(dm_build_1623.dm_build_1612, dm_build_1623.dm_build_1612[dm_build_1623.dm_build_1613:dm_build_1623.dm_build_1614])
|
||||
}
|
||||
dm_build_1625, dm_build_1623.dm_build_1608 = dm_build_1623.dm_build_1606.Read(dm_build_1623.dm_build_1612[dm_build_1623.dm_build_1614:])
|
||||
dm_build_1623.dm_build_1614 += dm_build_1625
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"github.com/golang/snappy"
|
||||
)
|
||||
|
||||
func Compress(srcBuffer *Dm_build_78, offset int, length int, compressID int) ([]byte, error) {
|
||||
if compressID == Dm_build_786 {
|
||||
return snappy.Encode(nil, srcBuffer.Dm_build_372(offset, length)), nil
|
||||
}
|
||||
return GzlibCompress(srcBuffer, offset, length)
|
||||
}
|
||||
|
||||
func UnCompress(srcBytes []byte, compressID int) ([]byte, error) {
|
||||
if compressID == Dm_build_786 {
|
||||
return snappy.Decode(nil, srcBytes)
|
||||
}
|
||||
return GzlibUncompress(srcBytes)
|
||||
}
|
||||
|
||||
func GzlibCompress(srcBuffer *Dm_build_78, offset int, length int) ([]byte, error) {
|
||||
var ret bytes.Buffer
|
||||
var w = zlib.NewWriter(&ret)
|
||||
w.Write(srcBuffer.Dm_build_372(offset, length))
|
||||
w.Close()
|
||||
return ret.Bytes(), nil
|
||||
}
|
||||
|
||||
func GzlibUncompress(srcBytes []byte) ([]byte, error) {
|
||||
var bytesBuf = new(bytes.Buffer)
|
||||
r, err := zlib.NewReader(bytes.NewReader(srcBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Close()
|
||||
_, err = bytesBuf.ReadFrom(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytesBuf.Bytes(), nil
|
||||
}
|
||||
+2158
File diff suppressed because it is too large
Load Diff
+8
@@ -0,0 +1,8 @@
|
||||
module gitee.com/chunanyong/dm
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/golang/snappy v0.0.1
|
||||
golang.org/x/text v0.3.2
|
||||
)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
+923
@@ -0,0 +1,923 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func encodeByString(x string, column column, conn DmConnection) ([]byte, error) {
|
||||
dt := make([]int, DT_LEN)
|
||||
if _, err := toDTFromString(x, dt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
}
|
||||
|
||||
func encodeByTime(x time.Time, column column, conn DmConnection) ([]byte, error) {
|
||||
dt := toDTFromTime(x)
|
||||
return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
}
|
||||
|
||||
func toTimeFromString(str string, ltz int) time.Time {
|
||||
dt := make([]int, DT_LEN)
|
||||
toDTFromString(str, dt)
|
||||
return toTimeFromDT(dt, ltz)
|
||||
}
|
||||
|
||||
func toTimeFromDT(dt []int, ltz int) time.Time {
|
||||
var year, month, day, hour, minute, second, nsec, tz int
|
||||
|
||||
year = dt[OFFSET_YEAR]
|
||||
|
||||
if dt[OFFSET_MONTH] > 0 {
|
||||
month = dt[OFFSET_MONTH]
|
||||
} else {
|
||||
month = 1
|
||||
}
|
||||
|
||||
if dt[OFFSET_DAY] > 0 {
|
||||
day = dt[OFFSET_DAY]
|
||||
} else {
|
||||
day = 1
|
||||
}
|
||||
|
||||
hour = dt[OFFSET_HOUR]
|
||||
minute = dt[OFFSET_MINUTE]
|
||||
second = dt[OFFSET_SECOND]
|
||||
nsec = dt[OFFSET_NANOSECOND]
|
||||
if dt[OFFSET_TIMEZONE] == INVALID_VALUE {
|
||||
tz = ltz * 60
|
||||
} else {
|
||||
tz = dt[OFFSET_TIMEZONE] * 60
|
||||
}
|
||||
return time.Date(year, time.Month(month), day, hour, minute, second, nsec, time.FixedZone("", tz))
|
||||
}
|
||||
|
||||
func decode(value []byte, isBdta bool, column column, ltz int, dtz int) []int {
|
||||
var dt []int
|
||||
if isBdta {
|
||||
dt = dmdtDecodeBdta(value)
|
||||
} else {
|
||||
dt = dmdtDecodeFast(value)
|
||||
}
|
||||
|
||||
if column.mask == MASK_LOCAL_DATETIME {
|
||||
transformTZ(dt, dtz, ltz)
|
||||
}
|
||||
|
||||
return dt
|
||||
}
|
||||
|
||||
func dmdtDecodeFast(value []byte) []int {
|
||||
dt := make([]int, DT_LEN)
|
||||
dt[OFFSET_TIMEZONE] = INVALID_VALUE
|
||||
|
||||
dtype := 0
|
||||
if len(value) == DATE_PREC {
|
||||
dtype = DATE
|
||||
} else if len(value) == TIME_PREC {
|
||||
dtype = TIME
|
||||
} else if len(value) == TIME_TZ_PREC {
|
||||
dtype = TIME_TZ
|
||||
} else if len(value) == DATETIME_PREC {
|
||||
dtype = DATETIME
|
||||
} else if len(value) == DATETIME2_PREC {
|
||||
dtype = DATETIME2
|
||||
} else if len(value) == DATETIME_TZ_PREC {
|
||||
dtype = DATETIME_TZ
|
||||
} else if len(value) == DATETIME2_TZ_PREC {
|
||||
dtype = DATETIME2_TZ
|
||||
}
|
||||
|
||||
if dtype == DATE {
|
||||
|
||||
dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF
|
||||
if dt[OFFSET_YEAR] > 9999 {
|
||||
dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000))
|
||||
}
|
||||
|
||||
dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1)
|
||||
|
||||
dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f
|
||||
} else if dtype == TIME {
|
||||
dt[OFFSET_HOUR] = int(value[0]) & 0x1F
|
||||
dt[OFFSET_MINUTE] = ((int(value[0]) >> 5) & 0x07) + ((int(value[1]) & 0x07) << 3)
|
||||
dt[OFFSET_SECOND] = ((int(value[1]) >> 3) & 0x1f) + ((int(value[2]) & 0x01) << 5)
|
||||
dt[OFFSET_NANOSECOND] = ((int(value[2]) >> 1) & 0x7f) + ((int(value[3]) & 0x00ff) << 7) + ((int(value[4]) & 0x1F) << 15)
|
||||
dt[OFFSET_NANOSECOND] *= 1000
|
||||
} else if dtype == TIME_TZ {
|
||||
dt[OFFSET_HOUR] = int(value[0]) & 0x1F
|
||||
dt[OFFSET_MINUTE] = ((int(value[0]) >> 5) & 0x07) + ((int(value[1]) & 0x07) << 3)
|
||||
dt[OFFSET_SECOND] = ((int(value[1]) >> 3) & 0x1f) + ((int(value[2]) & 0x01) << 5)
|
||||
dt[OFFSET_NANOSECOND] = ((int(value[2]) >> 1) & 0x7f) + ((int(value[3]) & 0x00ff) << 7) + ((int(value[4]) & 0x1F) << 15)
|
||||
dt[OFFSET_NANOSECOND] *= 1000
|
||||
dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, 5))
|
||||
} else if dtype == DATETIME {
|
||||
|
||||
dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF
|
||||
if dt[OFFSET_YEAR] > 9999 {
|
||||
dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000))
|
||||
}
|
||||
|
||||
dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1)
|
||||
|
||||
dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f
|
||||
|
||||
dt[OFFSET_HOUR] = (int(value[3]) & 0x1F)
|
||||
|
||||
dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3)
|
||||
|
||||
dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5)
|
||||
|
||||
dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x1F) << 15)
|
||||
dt[OFFSET_NANOSECOND] *= 1000
|
||||
} else if dtype == DATETIME_TZ {
|
||||
|
||||
dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF
|
||||
if dt[OFFSET_YEAR] > 9999 {
|
||||
dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000))
|
||||
}
|
||||
|
||||
dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1)
|
||||
|
||||
dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f
|
||||
|
||||
dt[OFFSET_HOUR] = (int(value[3]) & 0x1F)
|
||||
|
||||
dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3)
|
||||
|
||||
dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5)
|
||||
|
||||
dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x1F) << 15)
|
||||
dt[OFFSET_NANOSECOND] *= 1000
|
||||
|
||||
dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, len(value)-2))
|
||||
} else if dtype == DATETIME2 {
|
||||
|
||||
dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF
|
||||
if dt[OFFSET_YEAR] > 9999 {
|
||||
dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000))
|
||||
}
|
||||
|
||||
dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1)
|
||||
|
||||
dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f
|
||||
|
||||
dt[OFFSET_HOUR] = (int(value[3]) & 0x1F)
|
||||
|
||||
dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3)
|
||||
|
||||
dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5)
|
||||
|
||||
dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x00ff) << 15) + ((int(value[8]) & 0x7F) << 23)
|
||||
} else if dtype == DATETIME2_TZ {
|
||||
|
||||
dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF
|
||||
if dt[OFFSET_YEAR] > 9999 {
|
||||
dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000))
|
||||
}
|
||||
|
||||
dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1)
|
||||
|
||||
dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f
|
||||
|
||||
dt[OFFSET_HOUR] = (int(value[3]) & 0x1F)
|
||||
|
||||
dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3)
|
||||
|
||||
dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5)
|
||||
|
||||
dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x00ff) << 15) + ((int(value[8]) & 0x7F) << 23)
|
||||
|
||||
dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, len(value)-2))
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
func dmdtDecodeBdta(value []byte) []int {
|
||||
dt := make([]int, DT_LEN)
|
||||
dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0))
|
||||
dt[OFFSET_MONTH] = int(value[2] & 0xFF)
|
||||
dt[OFFSET_DAY] = int(value[3] & 0xFF)
|
||||
dt[OFFSET_HOUR] = int(value[4] & 0xFF)
|
||||
dt[OFFSET_MINUTE] = int(value[5] & 0xFF)
|
||||
dt[OFFSET_SECOND] = int(value[6] & 0xFF)
|
||||
dt[OFFSET_NANOSECOND] = int((value[7] & 0xFF) + (value[8] << 8) + (value[9] << 16))
|
||||
dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, 10))
|
||||
|
||||
if len(value) > 12 {
|
||||
|
||||
dt[OFFSET_NANOSECOND] += int(value[12] << 24)
|
||||
}
|
||||
return dt
|
||||
}
|
||||
|
||||
func dtToStringByOracleFormat(dt []int, oracleFormatPattern string, scale int32, language int) string {
|
||||
return format(dt, oracleFormatPattern, scale, language)
|
||||
}
|
||||
|
||||
func dtToString(dt []int, dtype int, scale int) string {
|
||||
switch dtype {
|
||||
case DATE:
|
||||
return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY])
|
||||
|
||||
case TIME:
|
||||
if scale > 0 {
|
||||
return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale)
|
||||
} else {
|
||||
return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND])
|
||||
}
|
||||
|
||||
case TIME_TZ:
|
||||
if scale > 0 {
|
||||
return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale) + " " + formatTZ(dt[OFFSET_TIMEZONE])
|
||||
} else {
|
||||
return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + " " + formatTZ(dt[OFFSET_TIMEZONE])
|
||||
}
|
||||
|
||||
case DATETIME, DATETIME2:
|
||||
if scale > 0 {
|
||||
return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale)
|
||||
} else {
|
||||
return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND])
|
||||
}
|
||||
|
||||
case DATETIME_TZ, DATETIME2_TZ:
|
||||
if scale > 0 {
|
||||
return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale) + " " + formatTZ(dt[OFFSET_TIMEZONE])
|
||||
} else {
|
||||
return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + " " + formatTZ(dt[OFFSET_TIMEZONE])
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func formatYear(value int) string {
|
||||
if value >= 0 {
|
||||
if value < 10 {
|
||||
return "000" + strconv.FormatInt(int64(value), 10)
|
||||
} else if value < 100 {
|
||||
return "00" + strconv.FormatInt(int64(value), 10)
|
||||
} else if value < 1000 {
|
||||
return "0" + strconv.FormatInt(int64(value), 10)
|
||||
} else {
|
||||
return strconv.FormatInt(int64(value), 10)
|
||||
}
|
||||
} else {
|
||||
if value > -10 {
|
||||
return "-000" + strconv.FormatInt(int64(-value), 10)
|
||||
} else if value > -100 {
|
||||
return "-00" + strconv.FormatInt(int64(-value), 10)
|
||||
} else if value > -1000 {
|
||||
return "-0" + strconv.FormatInt(int64(-value), 10)
|
||||
} else {
|
||||
return strconv.FormatInt(int64(value), 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func format2(value int) string {
|
||||
if value < 10 {
|
||||
return "0" + strconv.FormatInt(int64(value), 10)
|
||||
} else {
|
||||
return strconv.FormatInt(int64(value), 10)
|
||||
}
|
||||
}
|
||||
|
||||
func formatMilliSecond(ms int, prec int) string {
|
||||
var ret string
|
||||
if ms < 10 {
|
||||
ret = "00000000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 100 {
|
||||
ret = "0000000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 1000 {
|
||||
ret = "000000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 10000 {
|
||||
ret = "00000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 100000 {
|
||||
ret = "0000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 1000000 {
|
||||
ret = "000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 10000000 {
|
||||
ret = "00" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 100000000 {
|
||||
ret = "0" + strconv.FormatInt(int64(ms), 10)
|
||||
} else {
|
||||
ret = strconv.FormatInt(int64(ms), 10)
|
||||
}
|
||||
|
||||
if prec < NANOSECOND_DIGITS {
|
||||
ret = ret[:prec]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func formatTZ(tz int) string {
|
||||
tz_hour := int(math.Abs(float64(tz / 60)))
|
||||
tz_min := int(math.Abs(float64(tz % 60)))
|
||||
|
||||
if tz >= 0 {
|
||||
return "+" + format2(tz_hour) + ":" + format2(tz_min)
|
||||
} else {
|
||||
return "-" + format2(tz_hour) + ":" + format2(tz_min)
|
||||
}
|
||||
}
|
||||
|
||||
func toDTFromTime(x time.Time) []int {
|
||||
hour, min, sec := x.Clock()
|
||||
ts := make([]int, DT_LEN)
|
||||
ts[OFFSET_YEAR] = x.Year()
|
||||
ts[OFFSET_MONTH] = int(x.Month())
|
||||
ts[OFFSET_DAY] = x.Day()
|
||||
ts[OFFSET_HOUR] = hour
|
||||
ts[OFFSET_MINUTE] = min
|
||||
ts[OFFSET_SECOND] = sec
|
||||
ts[OFFSET_NANOSECOND] = (int)(x.Nanosecond())
|
||||
_, tz := x.Zone()
|
||||
ts[OFFSET_TIMEZONE] = tz / 60
|
||||
return ts
|
||||
}
|
||||
|
||||
func toDTFromUnix(sec int64, nsec int64) []int {
|
||||
return toDTFromTime(time.Unix(sec, nsec))
|
||||
}
|
||||
|
||||
func toDTFromString(s string, dt []int) (dtype int, err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
err = ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
}()
|
||||
date_s := ""
|
||||
time_s := ""
|
||||
nanos_s := ""
|
||||
tz_s := ""
|
||||
year := 0
|
||||
month := 0
|
||||
day := 0
|
||||
hour := 0
|
||||
minute := 0
|
||||
second := 0
|
||||
a_nanos := 0
|
||||
firstDash := -1
|
||||
secondDash := -1
|
||||
firstColon := -1
|
||||
secondColon := -1
|
||||
period := -1
|
||||
sign := 0
|
||||
ownTz := INVALID_VALUE
|
||||
dtype = -1
|
||||
|
||||
zeros := "000000000"
|
||||
|
||||
if s != "" && strings.TrimSpace(s) == "" {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
if strings.Index(s, "-") == 0 {
|
||||
s = strings.TrimSpace(s[1:])
|
||||
sign = 1
|
||||
}
|
||||
|
||||
comps := strings.Split(s, " ")
|
||||
|
||||
switch len(comps) {
|
||||
case 3:
|
||||
date_s = comps[0]
|
||||
time_s = comps[1]
|
||||
tz_s = comps[2]
|
||||
dtype = DATETIME_TZ
|
||||
|
||||
case 2:
|
||||
if strings.Index(comps[0], ":") > 0 {
|
||||
time_s = comps[0]
|
||||
tz_s = comps[1]
|
||||
dtype = TIME_TZ
|
||||
} else {
|
||||
date_s = comps[0]
|
||||
time_s = comps[1]
|
||||
dtype = DATETIME
|
||||
}
|
||||
|
||||
case 1:
|
||||
if strings.Index(comps[0], ":") > 0 {
|
||||
time_s = comps[0]
|
||||
dtype = TIME
|
||||
} else {
|
||||
date_s = comps[0]
|
||||
dtype = DATE
|
||||
}
|
||||
|
||||
default:
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
|
||||
if date_s != "" {
|
||||
|
||||
firstDash = strings.Index(date_s, "-")
|
||||
secondDash = strings.Index(date_s[firstDash+1:], "-")
|
||||
|
||||
if firstDash < 0 || secondDash < 0 {
|
||||
firstDash = strings.Index(s, ".")
|
||||
secondDash = strings.Index(date_s[firstDash+1:], ".")
|
||||
}
|
||||
|
||||
if firstDash < 0 || secondDash < 0 {
|
||||
firstDash = strings.Index(s, "/")
|
||||
secondDash = strings.Index(date_s[firstDash+1:], "/")
|
||||
}
|
||||
if secondDash > 0 {
|
||||
secondDash += firstDash + 1
|
||||
}
|
||||
|
||||
if (firstDash > 0) && (secondDash > 0) && (secondDash < len(date_s)-1) {
|
||||
|
||||
if sign == 1 {
|
||||
i, err := strconv.ParseInt(date_s[:firstDash], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
year = 0 - int(i) - 1900
|
||||
} else {
|
||||
i, err := strconv.ParseInt(date_s[:firstDash], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
year = int(i) - 1900
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(date_s[firstDash+1:secondDash], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
month = int(i) - 1
|
||||
|
||||
i, err = strconv.ParseInt(date_s[secondDash+1:], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
day = int(i)
|
||||
|
||||
if !checkDate(year+1900, month+1, day) {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
} else {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
}
|
||||
|
||||
if time_s != "" {
|
||||
firstColon = strings.Index(time_s, ":")
|
||||
secondColon = strings.Index(time_s[firstColon+1:], ":")
|
||||
if secondColon > 0 {
|
||||
secondColon += firstColon + 1
|
||||
}
|
||||
|
||||
period = strings.Index(time_s[secondColon+1:], ".")
|
||||
if period > 0 {
|
||||
period += secondColon + 1
|
||||
}
|
||||
|
||||
if (firstColon > 0) && (secondColon > 0) && (secondColon < len(time_s)-1) {
|
||||
i, err := strconv.ParseInt(time_s[:firstColon], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
hour = int(i)
|
||||
|
||||
i, err = strconv.ParseInt(time_s[firstColon+1:secondColon], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
minute = int(i)
|
||||
|
||||
if period > 0 && period < len(time_s)-1 {
|
||||
i, err = strconv.ParseInt(time_s[secondColon+1:period], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
second = int(i)
|
||||
|
||||
nanos_s = time_s[period+1:]
|
||||
if len(nanos_s) > NANOSECOND_DIGITS {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
if !unicode.IsDigit(rune(nanos_s[0])) {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
nanos_s = nanos_s + zeros[0:NANOSECOND_DIGITS-len(nanos_s)]
|
||||
|
||||
i, err = strconv.ParseInt(nanos_s, 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
a_nanos = int(i)
|
||||
} else if period > 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
} else {
|
||||
i, err = strconv.ParseInt(time_s[secondColon+1:], 10, 32)
|
||||
if err != nil {
|
||||
return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw()
|
||||
}
|
||||
second = int(i)
|
||||
}
|
||||
|
||||
if hour >= 24 || hour < 0 || minute >= 60 || minute < 0 || second >= 60 || second < 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
} else {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
}
|
||||
|
||||
if tz_s != "" {
|
||||
neg := false
|
||||
if strings.Index(tz_s, "-") == 0 {
|
||||
neg = true
|
||||
}
|
||||
|
||||
if strings.Index(tz_s, "-") == 0 || strings.Index(tz_s, "+") == 0 {
|
||||
tz_s = strings.TrimSpace(tz_s[1:])
|
||||
}
|
||||
|
||||
hm := strings.Split(tz_s, ":")
|
||||
var tzh, tzm int16 = 0, 0
|
||||
switch len(hm) {
|
||||
case 2:
|
||||
s, err := strconv.ParseInt(strings.TrimSpace(hm[0]), 10, 16)
|
||||
if err != nil {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
tzh = int16(s)
|
||||
|
||||
s, err = strconv.ParseInt(strings.TrimSpace(hm[1]), 10, 16)
|
||||
if err != nil {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
tzm = int16(s)
|
||||
case 1:
|
||||
s, err := strconv.ParseInt(strings.TrimSpace(hm[0]), 10, 16)
|
||||
if err != nil {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
tzh = int16(s)
|
||||
default:
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
|
||||
ownTz = int(tzh*60 + tzm)
|
||||
if ownTz < 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
|
||||
if neg {
|
||||
ownTz *= -1
|
||||
}
|
||||
|
||||
if ownTz <= -13*60 || ownTz > 14*60 {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
}
|
||||
|
||||
dt[OFFSET_YEAR] = year + 1900
|
||||
dt[OFFSET_MONTH] = month + 1
|
||||
if day == 0 {
|
||||
dt[OFFSET_DAY] = 1
|
||||
} else {
|
||||
dt[OFFSET_DAY] = day
|
||||
}
|
||||
dt[OFFSET_HOUR] = hour
|
||||
dt[OFFSET_MINUTE] = minute
|
||||
dt[OFFSET_SECOND] = second
|
||||
dt[OFFSET_NANOSECOND] = a_nanos
|
||||
dt[OFFSET_TIMEZONE] = int(ownTz)
|
||||
return dtype, nil
|
||||
}
|
||||
|
||||
func transformTZ(dt []int, defaultSrcTz int, destTz int) {
|
||||
srcTz := defaultSrcTz
|
||||
|
||||
if srcTz != INVALID_VALUE && destTz != INVALID_VALUE && destTz != srcTz {
|
||||
dt = addMinute(dt, destTz-srcTz)
|
||||
|
||||
dt[OFFSET_TIMEZONE] = destTz
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func encode(dt []int, column column, lTz int, dTz int) ([]byte, error) {
|
||||
if dt[OFFSET_TIMEZONE] != INVALID_VALUE {
|
||||
transformTZ(dt, dt[OFFSET_TIMEZONE], lTz)
|
||||
}
|
||||
|
||||
if column.mask == MASK_LOCAL_DATETIME {
|
||||
transformTZ(dt, dt[OFFSET_TIMEZONE], dTz)
|
||||
}
|
||||
|
||||
if dt[OFFSET_YEAR] < -4712 || dt[OFFSET_YEAR] > 9999 {
|
||||
return nil, ECGO_DATETIME_OVERFLOW.throw()
|
||||
}
|
||||
|
||||
year := dt[OFFSET_YEAR]
|
||||
|
||||
month := dt[OFFSET_MONTH]
|
||||
|
||||
day := dt[OFFSET_DAY]
|
||||
|
||||
hour := dt[OFFSET_HOUR]
|
||||
|
||||
min := dt[OFFSET_MINUTE]
|
||||
|
||||
sec := dt[OFFSET_SECOND]
|
||||
|
||||
msec := dt[OFFSET_NANOSECOND]
|
||||
|
||||
var tz int
|
||||
|
||||
if dt[OFFSET_TIMEZONE] == INVALID_VALUE {
|
||||
tz = dTz
|
||||
} else {
|
||||
tz = dt[OFFSET_TIMEZONE]
|
||||
}
|
||||
|
||||
var ret []byte
|
||||
|
||||
if column.colType == DATE {
|
||||
ret = make([]byte, 3)
|
||||
|
||||
ret[0] = (byte)(year & 0xFF)
|
||||
|
||||
if year >= 0 {
|
||||
ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7))
|
||||
} else {
|
||||
ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f))
|
||||
}
|
||||
|
||||
ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3))
|
||||
} else if column.colType == DATETIME {
|
||||
msec /= 1000
|
||||
ret = make([]byte, 8)
|
||||
|
||||
ret[0] = (byte)(year & 0xFF)
|
||||
|
||||
if year >= 0 {
|
||||
ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7))
|
||||
} else {
|
||||
ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f))
|
||||
}
|
||||
|
||||
ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3))
|
||||
|
||||
ret[3] = (byte)(hour | ((min & 0x07) << 5))
|
||||
|
||||
ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3))
|
||||
|
||||
ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1))
|
||||
|
||||
ret[6] = (byte)((msec >> 7) & 0xFF)
|
||||
|
||||
ret[7] = (byte)((msec >> 15) & 0xFF)
|
||||
} else if column.colType == DATETIME2 {
|
||||
ret = make([]byte, 9)
|
||||
|
||||
ret[0] = (byte)(year & 0xFF)
|
||||
|
||||
if year >= 0 {
|
||||
ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7))
|
||||
} else {
|
||||
ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f))
|
||||
}
|
||||
|
||||
ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3))
|
||||
|
||||
ret[3] = (byte)(hour | ((min & 0x07) << 5))
|
||||
|
||||
ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3))
|
||||
|
||||
ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1))
|
||||
|
||||
ret[6] = (byte)((msec >> 7) & 0xFF)
|
||||
|
||||
ret[7] = (byte)((msec >> 15) & 0xFF)
|
||||
|
||||
ret[8] = (byte)((msec >> 23) & 0xFF)
|
||||
} else if column.colType == DATETIME_TZ {
|
||||
msec /= 1000
|
||||
ret = make([]byte, 10)
|
||||
|
||||
ret[0] = (byte)(year & 0xFF)
|
||||
|
||||
if year >= 0 {
|
||||
ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7))
|
||||
} else {
|
||||
ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f))
|
||||
}
|
||||
|
||||
ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3))
|
||||
|
||||
ret[3] = (byte)(hour | ((min & 0x07) << 5))
|
||||
|
||||
ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3))
|
||||
|
||||
ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1))
|
||||
|
||||
ret[6] = (byte)((msec >> 7) & 0xFF)
|
||||
|
||||
ret[7] = (byte)((msec >> 15) & 0xFF)
|
||||
|
||||
Dm_build_1346.Dm_build_1357(ret, 8, int16(tz))
|
||||
} else if column.colType == DATETIME2_TZ {
|
||||
ret = make([]byte, 11)
|
||||
|
||||
ret[0] = (byte)(year & 0xFF)
|
||||
|
||||
if year >= 0 {
|
||||
ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7))
|
||||
} else {
|
||||
ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f))
|
||||
}
|
||||
|
||||
ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3))
|
||||
|
||||
ret[3] = (byte)(hour | ((min & 0x07) << 5))
|
||||
|
||||
ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3))
|
||||
|
||||
ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1))
|
||||
|
||||
ret[6] = (byte)((msec >> 7) & 0xFF)
|
||||
|
||||
ret[7] = (byte)((msec >> 15) & 0xFF)
|
||||
|
||||
ret[8] = (byte)((msec >> 23) & 0xFF)
|
||||
|
||||
Dm_build_1346.Dm_build_1357(ret, 8, int16(tz))
|
||||
} else if column.colType == TIME {
|
||||
msec /= 1000
|
||||
ret = make([]byte, 5)
|
||||
|
||||
ret[0] = (byte)(hour | ((min & 0x07) << 5))
|
||||
|
||||
ret[1] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3))
|
||||
|
||||
ret[2] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1))
|
||||
|
||||
ret[3] = (byte)((msec >> 7) & 0xFF)
|
||||
|
||||
ret[4] = (byte)((msec >> 15) & 0xFF)
|
||||
} else if column.colType == TIME_TZ {
|
||||
msec /= 1000
|
||||
ret = make([]byte, 7)
|
||||
|
||||
ret[0] = (byte)(hour | ((min & 0x07) << 5))
|
||||
|
||||
ret[1] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3))
|
||||
|
||||
ret[2] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1))
|
||||
|
||||
ret[3] = (byte)((msec >> 7) & 0xFF)
|
||||
|
||||
ret[4] = (byte)((msec >> 15) & 0xFF)
|
||||
|
||||
Dm_build_1346.Dm_build_1357(ret, 5, int16(tz))
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func toDate(x int64, column column, conn DmConnection) ([]byte, error) {
|
||||
switch column.colType {
|
||||
case DATETIME, DATETIME2:
|
||||
if x > 2958463*24*60*60 {
|
||||
return nil, ECGO_DATETIME_OVERFLOW.throw()
|
||||
}
|
||||
|
||||
dt := toDTFromUnix(x-Seconds_1900_1970, 0)
|
||||
return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
|
||||
case TIME:
|
||||
dt := toDTFromUnix(x, 0)
|
||||
return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
|
||||
case DATE:
|
||||
if x > 2958463 {
|
||||
return nil, ECGO_DATETIME_OVERFLOW.throw()
|
||||
}
|
||||
|
||||
dt := toDTFromUnix(x*24*60*60-Seconds_1900_1970, 0)
|
||||
if dt[OFFSET_YEAR] < -4712 || dt[OFFSET_YEAR] > 9999 {
|
||||
return nil, ECGO_DATETIME_OVERFLOW.throw()
|
||||
}
|
||||
return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
|
||||
default:
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
}
|
||||
|
||||
func checkDate(year int, month int, day int) bool {
|
||||
if year > 9999 || year < -4712 || month > 12 || month < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
monthDays := getDaysOfMonth(year, month)
|
||||
if day > monthDays || day < 1 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getDaysOfMonth(year int, month int) int {
|
||||
switch month {
|
||||
case 1, 3, 5, 7, 8, 10, 12:
|
||||
return 31
|
||||
case 4, 6, 9, 11:
|
||||
return 30
|
||||
case 2:
|
||||
if isLeapYear(year) {
|
||||
return 29
|
||||
}
|
||||
return 28
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func isLeapYear(year int) bool {
|
||||
return (year%4 == 0 && year%100 != 0) || year%400 == 0
|
||||
}
|
||||
|
||||
func addYear(dt []int, n int) []int {
|
||||
dt[OFFSET_YEAR] += n
|
||||
return dt
|
||||
}
|
||||
|
||||
func addMonth(dt []int, n int) []int {
|
||||
month := dt[OFFSET_MONTH] + n
|
||||
addYearValue := month / 12
|
||||
if month %= 12; month < 1 {
|
||||
month += 12
|
||||
addYearValue--
|
||||
}
|
||||
|
||||
daysOfMonth := getDaysOfMonth(dt[OFFSET_YEAR], month)
|
||||
if dt[OFFSET_DAY] > daysOfMonth {
|
||||
dt[OFFSET_DAY] = daysOfMonth
|
||||
}
|
||||
|
||||
dt[OFFSET_MONTH] = month
|
||||
addYear(dt, addYearValue)
|
||||
return dt
|
||||
}
|
||||
|
||||
func addDay(dt []int, n int) []int {
|
||||
tmp := dt[OFFSET_DAY] + n
|
||||
monthDays := 0
|
||||
monthDays = getDaysOfMonth(dt[OFFSET_YEAR], dt[OFFSET_MONTH])
|
||||
for tmp > monthDays || tmp <= 0 {
|
||||
if tmp > monthDays {
|
||||
addMonth(dt, 1)
|
||||
tmp -= monthDays
|
||||
} else {
|
||||
addMonth(dt, -1)
|
||||
tmp += monthDays
|
||||
}
|
||||
}
|
||||
dt[OFFSET_DAY] = tmp
|
||||
return dt
|
||||
}
|
||||
|
||||
func addHour(dt []int, n int) []int {
|
||||
hour := dt[OFFSET_HOUR] + n
|
||||
addDayValue := hour / 24
|
||||
if hour %= 24; hour < 0 {
|
||||
hour += 24
|
||||
addDayValue--
|
||||
}
|
||||
|
||||
dt[OFFSET_HOUR] = hour
|
||||
addDay(dt, addDayValue)
|
||||
return dt
|
||||
}
|
||||
|
||||
func addMinute(dt []int, n int) []int {
|
||||
minute := dt[OFFSET_MINUTE] + n
|
||||
addHourValue := minute / 60
|
||||
if minute %= 60; minute < 0 {
|
||||
minute += 60
|
||||
addHourValue--
|
||||
}
|
||||
|
||||
dt[OFFSET_MINUTE] = minute
|
||||
addHour(dt, addHourValue)
|
||||
return dt
|
||||
}
|
||||
+917
@@ -0,0 +1,917 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
var DB2G db2g
|
||||
|
||||
type db2g struct {
|
||||
}
|
||||
|
||||
func (DB2G db2g) processVarchar2(bytes []byte, prec int) []byte {
|
||||
rbytes := make([]byte, prec)
|
||||
copy(rbytes[:len(bytes)], bytes[:])
|
||||
for i := len(bytes); i < len(rbytes); i++ {
|
||||
rbytes[i] = ' '
|
||||
}
|
||||
return rbytes
|
||||
}
|
||||
|
||||
func (DB2G db2g) charToString(bytes []byte, column *column, conn *DmConnection) string {
|
||||
if column.colType == VARCHAR2 {
|
||||
bytes = DB2G.processVarchar2(bytes, int(column.prec))
|
||||
} else if column.colType == CLOB {
|
||||
clob := newClobFromDB(bytes, conn, column, true)
|
||||
clobLen, _ := clob.GetLength()
|
||||
clobStr, _ := clob.getSubString(1, int32(clobLen))
|
||||
return clobStr
|
||||
}
|
||||
return Dm_build_1346.Dm_build_1598(bytes, conn.serverEncoding, conn)
|
||||
}
|
||||
|
||||
func (DB2G db2g) charToFloat64(bytes []byte, column *column, conn *DmConnection) (float64, error) {
|
||||
str := DB2G.charToString(bytes, column, conn)
|
||||
val, err := strconv.ParseFloat(str, 64)
|
||||
if err != nil {
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (DB2G db2g) charToDeciaml(bytes []byte, column *column, conn *DmConnection) (*DmDecimal, error) {
|
||||
str := DB2G.charToString(bytes, column, conn)
|
||||
return NewDecimalFromString(str)
|
||||
}
|
||||
|
||||
func (DB2G db2g) BinaryToInt64(bytes []byte, column *column, conn *DmConnection) (int64, error) {
|
||||
if column.colType == BLOB {
|
||||
blob := newBlobFromDB(bytes, conn, column, true)
|
||||
blobLen, err := blob.GetLength()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
bytes, err = blob.getBytes(1, int32(blobLen))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
var n, b int64 = 0, 0
|
||||
|
||||
startIndex := 0
|
||||
var length int
|
||||
if len(bytes) > 8 {
|
||||
length = 8
|
||||
for j := 0; j < len(bytes)-8; j++ {
|
||||
if bytes[j] != 0 {
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
startIndex = len(bytes) - 8
|
||||
length = 8
|
||||
}
|
||||
} else {
|
||||
length = len(bytes)
|
||||
}
|
||||
|
||||
for j := startIndex; j < startIndex+length; j++ {
|
||||
b = int64(0xff & bytes[j])
|
||||
n = b | (n << 8)
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (DB2G db2g) decToDecimal(bytes []byte, prec int, scale int, compatibleOracle bool) (*DmDecimal, error) {
|
||||
|
||||
if compatibleOracle {
|
||||
prec = -1
|
||||
scale = -1
|
||||
}
|
||||
return newDecimal(bytes, prec, scale)
|
||||
}
|
||||
|
||||
func (DB2G db2g) toBytes(bytes []byte, column *column, conn *DmConnection) ([]byte, error) {
|
||||
retBytes := Dm_build_1346.Dm_build_1497(bytes, 0, len(bytes))
|
||||
switch column.colType {
|
||||
case CLOB:
|
||||
clob := newClobFromDB(retBytes, conn, column, true)
|
||||
str, err := clob.getSubString(1, int32(clob.length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return Dm_build_1346.Dm_build_1562(str, conn.getServerEncoding(), conn), nil
|
||||
case BLOB:
|
||||
blob := newBlobFromDB(retBytes, conn, column, true)
|
||||
bs, err := blob.getBytes(1, int32(blob.length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bs, nil
|
||||
}
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toString(bytes []byte, column *column, conn *DmConnection) string {
|
||||
switch column.colType {
|
||||
case CHAR, VARCHAR, VARCHAR2:
|
||||
return DB2G.charToString(bytes, column, conn)
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
return strconv.FormatInt(int64(bytes[0]), 10)
|
||||
case SMALLINT:
|
||||
return strconv.FormatInt(int64(Dm_build_1346.Dm_build_1570(bytes)), 10)
|
||||
case INT:
|
||||
return strconv.FormatInt(int64(Dm_build_1346.Dm_build_1573(bytes)), 10)
|
||||
case BIGINT:
|
||||
return strconv.FormatInt(int64(Dm_build_1346.Dm_build_1576(bytes)), 10)
|
||||
case REAL:
|
||||
return strconv.FormatFloat(float64(Dm_build_1346.Dm_build_1579(bytes)), 'f', -1, 32)
|
||||
case DOUBLE:
|
||||
return strconv.FormatFloat(float64(Dm_build_1346.Dm_build_1582(bytes)), 'f', -1, 64)
|
||||
case DECIMAL:
|
||||
|
||||
case BINARY, VARBINARY:
|
||||
util.StringUtil.BytesToHexString(bytes, false)
|
||||
case BLOB:
|
||||
|
||||
case CLOB:
|
||||
|
||||
case DATE:
|
||||
dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
if conn.FormatDate != "" {
|
||||
return dtToStringByOracleFormat(dt, conn.FormatDate, column.scale, int(conn.OracleDateLanguage))
|
||||
}
|
||||
case TIME:
|
||||
dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
if conn.FormatTime != "" {
|
||||
return dtToStringByOracleFormat(dt, conn.FormatTime, column.scale, int(conn.OracleDateLanguage))
|
||||
}
|
||||
case DATETIME, DATETIME2:
|
||||
dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
if conn.FormatTimestamp != "" {
|
||||
return dtToStringByOracleFormat(dt, conn.FormatTimestamp, column.scale, int(conn.OracleDateLanguage))
|
||||
}
|
||||
case TIME_TZ:
|
||||
dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
if conn.FormatTimeTZ != "" {
|
||||
return dtToStringByOracleFormat(dt, conn.FormatTimeTZ, column.scale, int(conn.OracleDateLanguage))
|
||||
}
|
||||
case DATETIME_TZ, DATETIME2_TZ:
|
||||
dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
if conn.FormatTimestampTZ != "" {
|
||||
return dtToStringByOracleFormat(dt, conn.FormatTimestampTZ, column.scale, int(conn.OracleDateLanguage))
|
||||
}
|
||||
case INTERVAL_DT:
|
||||
return newDmIntervalDTByBytes(bytes).String()
|
||||
case INTERVAL_YM:
|
||||
return newDmIntervalYMByBytes(bytes).String()
|
||||
case ARRAY:
|
||||
|
||||
case SARRAY:
|
||||
|
||||
case CLASS:
|
||||
|
||||
case PLTYPE_RECORD:
|
||||
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (DB2G db2g) toBool(bytes []byte, column *column, conn *DmConnection) (bool, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
return bytes[0] != 0, nil
|
||||
case SMALLINT:
|
||||
return Dm_build_1346.Dm_build_1443(bytes, 0) != 0, nil
|
||||
case INT:
|
||||
return Dm_build_1346.Dm_build_1448(bytes, 0) != 0, nil
|
||||
case BIGINT:
|
||||
return Dm_build_1346.Dm_build_1453(bytes, 0) != 0, nil
|
||||
case REAL:
|
||||
return Dm_build_1346.Dm_build_1458(bytes, 0) != 0, nil
|
||||
case DOUBLE:
|
||||
return Dm_build_1346.Dm_build_1462(bytes, 0) != 0, nil
|
||||
case DECIMAL:
|
||||
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
return G2DB.toBool(DB2G.charToString(bytes, column, conn))
|
||||
}
|
||||
|
||||
return false, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toByte(bytes []byte, column *column, conn *DmConnection) (byte, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
} else {
|
||||
return bytes[0], nil
|
||||
}
|
||||
case SMALLINT:
|
||||
tval := Dm_build_1346.Dm_build_1443(bytes, 0)
|
||||
if tval < int16(BYTE_MIN) || tval > int16(BYTE_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return byte(tval), nil
|
||||
case INT:
|
||||
tval := Dm_build_1346.Dm_build_1448(bytes, 0)
|
||||
if tval < int32(BYTE_MIN) || tval > int32(BYTE_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return byte(tval), nil
|
||||
case BIGINT:
|
||||
tval := Dm_build_1346.Dm_build_1453(bytes, 0)
|
||||
if tval < int64(BYTE_MIN) || tval > int64(BYTE_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return byte(tval), nil
|
||||
case REAL:
|
||||
tval := Dm_build_1346.Dm_build_1458(bytes, 0)
|
||||
if tval < float32(BYTE_MIN) || tval > float32(BYTE_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return byte(tval), nil
|
||||
case DOUBLE:
|
||||
tval := Dm_build_1346.Dm_build_1462(bytes, 0)
|
||||
if tval < float64(BYTE_MIN) || tval > float64(BYTE_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return byte(tval), nil
|
||||
case DECIMAL:
|
||||
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < float64(BYTE_MIN) || tval > float64(BYTE_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return byte(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
{
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < int64(BYTE_MIN) || tval > int64(BYTE_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return byte(tval), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toInt8(bytes []byte, column *column, conn *DmConnection) (int8, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return int8(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
tval := Dm_build_1346.Dm_build_1443(bytes, 0)
|
||||
if tval < int16(INT8_MIN) || tval < int16(INT8_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int8(tval), nil
|
||||
case INT:
|
||||
|
||||
tval := Dm_build_1346.Dm_build_1448(bytes, 0)
|
||||
if tval < int32(INT8_MIN) || tval > int32(INT8_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int8(tval), nil
|
||||
case BIGINT:
|
||||
tval := Dm_build_1346.Dm_build_1453(bytes, 0)
|
||||
if tval < int64(INT8_MIN) || tval > int64(INT8_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int8(tval), nil
|
||||
case REAL:
|
||||
tval := Dm_build_1346.Dm_build_1458(bytes, 0)
|
||||
if tval < float32(INT8_MIN) || tval > float32(INT8_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int8(tval), nil
|
||||
case DOUBLE:
|
||||
tval := Dm_build_1346.Dm_build_1462(bytes, 0)
|
||||
if tval < float64(INT8_MIN) || tval > float64(INT8_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int8(tval), nil
|
||||
case DECIMAL:
|
||||
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < float64(INT8_MIN) || tval > float64(INT8_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int8(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
{
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < int64(INT8_MIN) || tval > int64(INT8_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int8(tval), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toInt16(bytes []byte, column *column, conn *DmConnection) (int16, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return int16(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
return Dm_build_1346.Dm_build_1443(bytes, 0), nil
|
||||
case INT:
|
||||
|
||||
tval := Dm_build_1346.Dm_build_1448(bytes, 0)
|
||||
if tval < int32(INT16_MIN) || tval > int32(INT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int16(tval), nil
|
||||
case BIGINT:
|
||||
tval := Dm_build_1346.Dm_build_1453(bytes, 0)
|
||||
if tval < int64(INT16_MIN) || tval > int64(INT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int16(tval), nil
|
||||
case REAL:
|
||||
tval := Dm_build_1346.Dm_build_1458(bytes, 0)
|
||||
if tval < float32(INT16_MIN) || tval > float32(INT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int16(tval), nil
|
||||
case DOUBLE:
|
||||
tval := Dm_build_1346.Dm_build_1462(bytes, 0)
|
||||
if tval < float64(INT16_MIN) || tval > float64(INT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int16(tval), nil
|
||||
case DECIMAL:
|
||||
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < float64(INT16_MIN) || tval > float64(INT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int16(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
{
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < int64(INT16_MIN) || tval > int64(INT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int16(tval), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toUInt16(bytes []byte, column *column, conn *DmConnection) (uint16, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return uint16(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
return uint16(Dm_build_1346.Dm_build_1443(bytes, 0)), nil
|
||||
case INT:
|
||||
tval := Dm_build_1346.Dm_build_1448(bytes, 0)
|
||||
if tval < int32(UINT16_MIN) || tval > int32(UINT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint16(tval), nil
|
||||
case BIGINT:
|
||||
tval := Dm_build_1346.Dm_build_1453(bytes, 0)
|
||||
if tval < int64(UINT16_MIN) || tval > int64(UINT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint16(tval), nil
|
||||
case REAL:
|
||||
tval := Dm_build_1346.Dm_build_1458(bytes, 0)
|
||||
if tval < float32(UINT16_MIN) || tval > float32(UINT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint16(tval), nil
|
||||
case DOUBLE:
|
||||
tval := Dm_build_1346.Dm_build_1462(bytes, 0)
|
||||
if tval < float64(UINT16_MIN) || tval > float64(UINT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint16(tval), nil
|
||||
case DECIMAL:
|
||||
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < float64(UINT16_MIN) || tval > float64(UINT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint16(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
{
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < int64(UINT16_MIN) || tval > int64(UINT16_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint16(tval), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toInt32(bytes []byte, column *column, conn *DmConnection) (int32, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return int32(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
return int32(Dm_build_1346.Dm_build_1443(bytes, 0)), nil
|
||||
case INT:
|
||||
return Dm_build_1346.Dm_build_1448(bytes, 0), nil
|
||||
case BIGINT:
|
||||
tval := Dm_build_1346.Dm_build_1453(bytes, 0)
|
||||
if tval < int64(INT32_MIN) || tval > int64(INT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int32(tval), nil
|
||||
case REAL:
|
||||
tval := Dm_build_1346.Dm_build_1458(bytes, 0)
|
||||
if tval < float32(INT32_MIN) || tval > float32(INT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int32(tval), nil
|
||||
case DOUBLE:
|
||||
tval := Dm_build_1346.Dm_build_1462(bytes, 0)
|
||||
if tval < float64(INT32_MIN) || tval > float64(INT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int32(tval), nil
|
||||
case DECIMAL:
|
||||
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < float64(INT32_MIN) || tval > float64(INT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int32(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
{
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < int64(INT32_MIN) || tval > int64(INT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int32(tval), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toUInt32(bytes []byte, column *column, conn *DmConnection) (uint32, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return uint32(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
return uint32(Dm_build_1346.Dm_build_1443(bytes, 0)), nil
|
||||
case INT:
|
||||
return uint32(Dm_build_1346.Dm_build_1448(bytes, 0)), nil
|
||||
case BIGINT:
|
||||
tval := Dm_build_1346.Dm_build_1453(bytes, 0)
|
||||
if tval < int64(UINT32_MIN) || tval > int64(UINT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint32(tval), nil
|
||||
case REAL:
|
||||
tval := Dm_build_1346.Dm_build_1458(bytes, 0)
|
||||
if tval < float32(UINT32_MIN) || tval > float32(UINT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint32(tval), nil
|
||||
case DOUBLE:
|
||||
tval := Dm_build_1346.Dm_build_1462(bytes, 0)
|
||||
if tval < float64(UINT32_MIN) || tval > float64(UINT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint32(tval), nil
|
||||
case DECIMAL:
|
||||
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < float64(UINT32_MIN) || tval > float64(UINT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint32(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
{
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if tval < int64(UINT32_MIN) || tval > int64(UINT32_MAX) {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint32(tval), nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toInt64(bytes []byte, column *column, conn *DmConnection) (int64, error) {
|
||||
switch column.colType {
|
||||
case BOOLEAN, BIT, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return int64(0), nil
|
||||
} else {
|
||||
return int64(bytes[0]), nil
|
||||
}
|
||||
case SMALLINT:
|
||||
return int64(Dm_build_1346.Dm_build_1570(bytes)), nil
|
||||
case INT:
|
||||
return int64(Dm_build_1346.Dm_build_1573(bytes)), nil
|
||||
case BIGINT:
|
||||
return int64(Dm_build_1346.Dm_build_1576(bytes)), nil
|
||||
case REAL:
|
||||
return int64(Dm_build_1346.Dm_build_1579(bytes)), nil
|
||||
case DOUBLE:
|
||||
return int64(Dm_build_1346.Dm_build_1582(bytes)), nil
|
||||
|
||||
case CHAR, VARCHAR2, VARCHAR, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if int64(tval) < INT64_MIN || int64(tval) > INT64_MAX {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return int64(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return tval, nil
|
||||
}
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toUInt64(bytes []byte, column *column, conn *DmConnection) (uint64, error) {
|
||||
switch column.colType {
|
||||
case BOOLEAN, BIT, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return uint64(0), nil
|
||||
} else {
|
||||
return uint64(bytes[0]), nil
|
||||
}
|
||||
case SMALLINT:
|
||||
return uint64(Dm_build_1346.Dm_build_1570(bytes)), nil
|
||||
case INT:
|
||||
return uint64(Dm_build_1346.Dm_build_1573(bytes)), nil
|
||||
case BIGINT:
|
||||
return uint64(Dm_build_1346.Dm_build_1576(bytes)), nil
|
||||
case REAL:
|
||||
return uint64(Dm_build_1346.Dm_build_1579(bytes)), nil
|
||||
case DOUBLE:
|
||||
return uint64(Dm_build_1346.Dm_build_1582(bytes)), nil
|
||||
|
||||
case CHAR, VARCHAR2, VARCHAR, CLOB:
|
||||
tval, err := DB2G.charToFloat64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if uint64(tval) < UINT64_MIN || uint64(tval) > UINT64_MAX {
|
||||
return 0, ECGO_DATA_OVERFLOW.throw()
|
||||
}
|
||||
return uint64(tval), nil
|
||||
case BINARY, VARBINARY, BLOB:
|
||||
tval, err := DB2G.BinaryToInt64(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint64(tval), nil
|
||||
}
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toInt(bytes []byte, column *column, conn *DmConnection) (int, error) {
|
||||
if strconv.IntSize == 32 {
|
||||
tmp, err := DB2G.toInt32(bytes, column, conn)
|
||||
return int(tmp), err
|
||||
} else {
|
||||
tmp, err := DB2G.toInt64(bytes, column, conn)
|
||||
return int(tmp), err
|
||||
}
|
||||
}
|
||||
|
||||
func (DB2G db2g) toUInt(bytes []byte, column *column, conn *DmConnection) (uint, error) {
|
||||
if strconv.IntSize == 32 {
|
||||
tmp, err := DB2G.toUInt32(bytes, column, conn)
|
||||
return uint(tmp), err
|
||||
} else {
|
||||
tmp, err := DB2G.toUInt64(bytes, column, conn)
|
||||
return uint(tmp), err
|
||||
}
|
||||
}
|
||||
|
||||
func (DB2G db2g) toFloat32(bytes []byte, column *column, conn *DmConnection) (float32, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return float32(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
return float32(Dm_build_1346.Dm_build_1443(bytes, 0)), nil
|
||||
case INT:
|
||||
return float32(Dm_build_1346.Dm_build_1448(bytes, 0)), nil
|
||||
case BIGINT:
|
||||
return float32(Dm_build_1346.Dm_build_1453(bytes, 0)), nil
|
||||
case REAL:
|
||||
return Dm_build_1346.Dm_build_1458(bytes, 0), nil
|
||||
case DOUBLE:
|
||||
dval := Dm_build_1346.Dm_build_1462(bytes, 0)
|
||||
return float32(dval), nil
|
||||
case DECIMAL:
|
||||
dval, err := DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float32(dval.ToFloat64()), nil
|
||||
case CHAR, VARCHAR2, VARCHAR, CLOB:
|
||||
dval, err := DB2G.charToDeciaml(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float32(dval.ToFloat64()), nil
|
||||
}
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toFloat64(bytes []byte, column *column, conn *DmConnection) (float64, error) {
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if bytes == nil || len(bytes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return float64(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
return float64(Dm_build_1346.Dm_build_1443(bytes, 0)), nil
|
||||
case INT:
|
||||
return float64(Dm_build_1346.Dm_build_1448(bytes, 0)), nil
|
||||
case BIGINT:
|
||||
return float64(Dm_build_1346.Dm_build_1453(bytes, 0)), nil
|
||||
case REAL:
|
||||
return float64(Dm_build_1346.Dm_build_1458(bytes, 0)), nil
|
||||
case DOUBLE:
|
||||
return Dm_build_1346.Dm_build_1462(bytes, 0), nil
|
||||
case DECIMAL:
|
||||
dval, err := DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return dval.ToFloat64(), nil
|
||||
case CHAR, VARCHAR2, VARCHAR, CLOB:
|
||||
dval, err := DB2G.charToDeciaml(bytes, column, conn)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return dval.ToFloat64(), nil
|
||||
}
|
||||
|
||||
return 0, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toDmBlob(value []byte, column *column, conn *DmConnection) *DmBlob {
|
||||
|
||||
switch column.colType {
|
||||
case BLOB:
|
||||
return newBlobFromDB(value, conn, column, conn.lobFetchAll())
|
||||
default:
|
||||
return newBlobOfLocal(value, conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (DB2G db2g) toDmClob(value []byte, conn *DmConnection, column *column) *DmClob {
|
||||
|
||||
switch column.colType {
|
||||
case CLOB:
|
||||
return newClobFromDB(value, conn, column, conn.lobFetchAll())
|
||||
default:
|
||||
return newClobOfLocal(DB2G.toString(value, column, conn), conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (DB2G db2g) toDmDecimal(value []byte, column *column, conn *DmConnection) (*DmDecimal, error) {
|
||||
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN, TINYINT:
|
||||
if value == nil || len(value) == 0 {
|
||||
return NewDecimalFromInt64(0)
|
||||
} else {
|
||||
return NewDecimalFromInt64(int64(value[0]))
|
||||
}
|
||||
case SMALLINT:
|
||||
return NewDecimalFromInt64(int64(Dm_build_1346.Dm_build_1443(value, 0)))
|
||||
case INT:
|
||||
return NewDecimalFromInt64(int64(Dm_build_1346.Dm_build_1448(value, 0)))
|
||||
case BIGINT:
|
||||
return NewDecimalFromInt64(Dm_build_1346.Dm_build_1453(value, 0))
|
||||
case REAL:
|
||||
return NewDecimalFromFloat64(float64(Dm_build_1346.Dm_build_1458(value, 0)))
|
||||
case DOUBLE:
|
||||
return NewDecimalFromFloat64(Dm_build_1346.Dm_build_1462(value, 0))
|
||||
case DECIMAL:
|
||||
return decodeDecimal(value, int(column.prec), int(column.scale))
|
||||
case CHAR, VARCHAR, VARCHAR2, CLOB:
|
||||
return DB2G.charToDeciaml(value, column, conn)
|
||||
}
|
||||
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR
|
||||
}
|
||||
|
||||
func (DB2G db2g) toTime(bytes []byte, column *column, conn *DmConnection) (time.Time, error) {
|
||||
switch column.colType {
|
||||
case DATE, TIME, TIME_TZ, DATETIME_TZ, DATETIME, DATETIME2_TZ, DATETIME2:
|
||||
dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
return toTimeFromDT(dt, int(conn.dmConnector.localTimezone)), nil
|
||||
case CHAR, VARCHAR2, VARCHAR, CLOB:
|
||||
return toTimeFromString(DB2G.charToString(bytes, column, conn), int(conn.dmConnector.localTimezone)), nil
|
||||
}
|
||||
return time.Now(), ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toObject(bytes []byte, column *column, conn *DmConnection) (interface{}, error) {
|
||||
|
||||
switch column.colType {
|
||||
case BIT, BOOLEAN:
|
||||
return bytes[0] != 0, nil
|
||||
|
||||
case TINYINT:
|
||||
|
||||
return Dm_build_1346.Dm_build_1439(bytes, 0), nil
|
||||
case SMALLINT:
|
||||
return Dm_build_1346.Dm_build_1443(bytes, 0), nil
|
||||
case INT:
|
||||
return Dm_build_1346.Dm_build_1448(bytes, 0), nil
|
||||
case BIGINT:
|
||||
return Dm_build_1346.Dm_build_1453(bytes, 0), nil
|
||||
case DECIMAL:
|
||||
return DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle())
|
||||
case REAL:
|
||||
return Dm_build_1346.Dm_build_1458(bytes, 0), nil
|
||||
case DOUBLE:
|
||||
return Dm_build_1346.Dm_build_1462(bytes, 0), nil
|
||||
case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ:
|
||||
dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
return toTimeFromDT(dt, int(conn.dmConnector.localTimezone)), nil
|
||||
case BINARY, VARBINARY:
|
||||
return bytes, nil
|
||||
case BLOB:
|
||||
blob := newBlobFromDB(bytes, conn, column, conn.lobFetchAll())
|
||||
|
||||
if util.StringUtil.EqualsIgnoreCase(column.typeName, "LONGVARBINARY") {
|
||||
|
||||
l, err := blob.GetLength()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blob.getBytes(1, int32(l))
|
||||
} else {
|
||||
return blob, nil
|
||||
}
|
||||
case CHAR, VARCHAR, VARCHAR2:
|
||||
val := DB2G.charToString(bytes, column, conn)
|
||||
if column.mask == MASK_BFILE {
|
||||
|
||||
}
|
||||
|
||||
return val, nil
|
||||
case CLOB:
|
||||
clob := newClobFromDB(bytes, conn, column, conn.lobFetchAll())
|
||||
if util.StringUtil.EqualsIgnoreCase(column.typeName, "LONGVARCHAR") {
|
||||
|
||||
l, err := clob.GetLength()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return clob.getSubString(1, int32(l))
|
||||
} else {
|
||||
return clob, nil
|
||||
}
|
||||
case INTERVAL_YM:
|
||||
return newDmIntervalYMByBytes(bytes), nil
|
||||
case INTERVAL_DT:
|
||||
return newDmIntervalDTByBytes(bytes), nil
|
||||
case ARRAY:
|
||||
return TypeDataSV.bytesToArray(bytes, nil, column.typeDescriptor)
|
||||
case SARRAY:
|
||||
return TypeDataSV.bytesToSArray(bytes, nil, column.typeDescriptor)
|
||||
case CLASS:
|
||||
|
||||
case PLTYPE_RECORD:
|
||||
|
||||
default:
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
|
||||
func (DB2G db2g) toComplexType(bytes []byte, column *column, conn *DmConnection) (interface{}, error) {
|
||||
switch column.colType {
|
||||
case BLOB:
|
||||
if !isComplexType(int(column.colType), int(column.scale)) {
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
blob := newBlobFromDB(bytes, conn, column, true)
|
||||
return TypeDataSV.objBlobToObj(blob, column.typeDescriptor)
|
||||
case ARRAY:
|
||||
return TypeDataSV.bytesToArray(bytes, nil, column.typeDescriptor)
|
||||
case SARRAY:
|
||||
return TypeDataSV.bytesToSArray(bytes, nil, column.typeDescriptor)
|
||||
case CLASS:
|
||||
return TypeDataSV.bytesToObj(bytes, nil, column.typeDescriptor)
|
||||
case PLTYPE_RECORD:
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
default:
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package i18n
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
)
|
||||
|
||||
type msg struct {
|
||||
Id string `json:"id"`
|
||||
Translation string `json:"translation,omitempty"`
|
||||
}
|
||||
|
||||
type i18n struct {
|
||||
Language string `json:"language"`
|
||||
Messages []msg `json:"messages"`
|
||||
}
|
||||
|
||||
func InitConfig(jsonStr string) {
|
||||
|
||||
var i18n i18n
|
||||
json.Unmarshal([]byte(jsonStr), &i18n)
|
||||
msaArry := i18n.Messages
|
||||
tag := language.MustParse(i18n.Language)
|
||||
for _, e := range msaArry {
|
||||
message.SetString(tag, e.Id, e.Translation)
|
||||
}
|
||||
}
|
||||
|
||||
func Get(key string, locale int) string {
|
||||
var p *message.Printer
|
||||
|
||||
switch locale {
|
||||
case 0:
|
||||
p = message.NewPrinter(language.SimplifiedChinese)
|
||||
case 1:
|
||||
p = message.NewPrinter(language.AmericanEnglish)
|
||||
case 2:
|
||||
p = message.NewPrinter(language.TraditionalChinese)
|
||||
}
|
||||
|
||||
return p.Sprintf(key)
|
||||
}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package i18n
|
||||
|
||||
const Messages_en_US = `{
|
||||
"language": "en-US",
|
||||
"messages": [
|
||||
{
|
||||
"id": "error.dsn.invalidSchema",
|
||||
"translation": "DSN must start with dm://"
|
||||
},
|
||||
{
|
||||
"id": "error.dsn.invalidFormat",
|
||||
"translation": "DSN is invalid"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupported.scan",
|
||||
"translation": "Unsupported scan type"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidParameterNumber",
|
||||
"translation": "Invalid parameter number"
|
||||
},
|
||||
{
|
||||
"id": "error.initThirdPartCipherFailed",
|
||||
"translation": "Init third part cipher failed"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionSwitchFailed",
|
||||
"translation": "Connection switch failed"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionSwitched",
|
||||
"translation": "Connection has been switched"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidServerMode",
|
||||
"translation": "Invalid server mode"
|
||||
},
|
||||
{
|
||||
"id": "error.osauthError",
|
||||
"translation": "At the same time using the specifed user login and OS authentication login, please determine a way."
|
||||
},
|
||||
{
|
||||
"id": "error.notQuerySQL",
|
||||
"translation": "The SQL is not a query SQL"
|
||||
},
|
||||
{
|
||||
"id": "error.notExecSQL",
|
||||
"translation": "The SQL is not a execute SQL"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidTranIsolation",
|
||||
"translation": "invalid Transaltion Isolation"
|
||||
},
|
||||
{
|
||||
"id": "errorCommitInAutoCommitMode",
|
||||
"translation": "Can't commit in Auto commit status"
|
||||
},
|
||||
{
|
||||
"id": "errorCommitInAutoCommitMode",
|
||||
"translation": "Can't rollback in Auto commit status"
|
||||
},
|
||||
{
|
||||
"id": "errorStatementHandleClosed",
|
||||
"translation": "Statement handle is closed"
|
||||
},
|
||||
{
|
||||
"id": "errorResultSetColsed",
|
||||
"translation": "Resultset is closed"
|
||||
},
|
||||
{
|
||||
"id": "error.communicationError",
|
||||
"translation": "Communication error"
|
||||
},
|
||||
{
|
||||
"id": "error.msgCheckError",
|
||||
"translation": "Message check error"
|
||||
},
|
||||
{
|
||||
"id": "error.unkownNetWork",
|
||||
"translation": "Unkown net work"
|
||||
},
|
||||
{
|
||||
"id": "error.serverVersion",
|
||||
"translation": "Server version is too low"
|
||||
},
|
||||
{
|
||||
"id": "error.usernameTooLong",
|
||||
"translation": "Username is too long."
|
||||
},
|
||||
{
|
||||
"id": "error.passwordTooLong",
|
||||
"translation": "Password to login is too long."
|
||||
},
|
||||
{
|
||||
"id": "error.dataTooLong",
|
||||
"translation": "The data is too large to support."
|
||||
},
|
||||
{
|
||||
"id": "error.invalidColumnType",
|
||||
"translation": "Invalid column type"
|
||||
},
|
||||
{
|
||||
"id": "error.dataConvertionError",
|
||||
"translation": "Data convertion error"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidConn",
|
||||
"translation": "Invalid connection"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidHex",
|
||||
"translation": "Invalid Hex Number."
|
||||
},
|
||||
{
|
||||
"id": "error.invalidBFile",
|
||||
"translation": "Invalid BFile format string."
|
||||
},
|
||||
{
|
||||
"id": "error.dataOverflow",
|
||||
"translation": "Digital overflow"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidDateTimeFormat",
|
||||
"translation": "Invalid datetime type format"
|
||||
},
|
||||
{
|
||||
"id": "error.datetimeOverflow",
|
||||
"translation": "Digital overflow"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidTimeInterval",
|
||||
"translation": "Invalid time interval type value"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedInparamType",
|
||||
"translation": "Unsupported input parameter type"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedOutparamType",
|
||||
"translation": "Unsupported output parameter type"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedType",
|
||||
"translation": "Not support this type"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidObjBlob",
|
||||
"translation": "invalid Object Blob Data."
|
||||
},
|
||||
{
|
||||
"id": "error.structMemNotMatch",
|
||||
"translation": "Members are not matched in Record or Class"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidComplexTypeName",
|
||||
"translation": "Invalid descriptor name."
|
||||
},
|
||||
{
|
||||
"id": "error.invalidParamterValue",
|
||||
"translation": "Invalid parameter value"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidArrayLen",
|
||||
"translation": "the length of static array is bigger than the one when defined."
|
||||
},
|
||||
{
|
||||
"id": "error.invalidSequenceNumber",
|
||||
"translation": "Invalid sequence no"
|
||||
},
|
||||
{
|
||||
"id": "error.resultsetInReadOnlyStatus",
|
||||
"translation": "Resultset in readonly status"
|
||||
},
|
||||
{
|
||||
"id": "error.SSLInitFailed",
|
||||
"translation": "Failed to initialize SSL"
|
||||
},
|
||||
{
|
||||
"id": "error.LobDataHasFreed",
|
||||
"translation": "Lob Data has been freed"
|
||||
},
|
||||
{
|
||||
"id": "error.fatalError",
|
||||
"translation": "Fatal error"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidLenOrOffset",
|
||||
"translation": "Invalid length or offset"
|
||||
},
|
||||
{
|
||||
"id": "error.intervalValueOverflow",
|
||||
"translation": "interval type value overflow"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidCipher",
|
||||
"translation": "Invalid cipher type"
|
||||
},
|
||||
{
|
||||
"id": "error.storeInNilPointer",
|
||||
"translation": "Can't store value into a nil pointer"
|
||||
},
|
||||
{
|
||||
"id": "error.batchError",
|
||||
"translation": "Error in executing with batch"
|
||||
},
|
||||
{
|
||||
"id": "warning.bpWithErr",
|
||||
"translation": "Warning:Partial failure on execute with batch"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidSqlType",
|
||||
"translation": "Invalid sql type"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidDateTimeValue",
|
||||
"translation": "Invalid datetime value"
|
||||
},
|
||||
{
|
||||
"id": "error.msgTooLong",
|
||||
"translation": "Message too long, limit 512M"
|
||||
},
|
||||
{
|
||||
"id": "error.isNull",
|
||||
"translation": "Data is NULL"
|
||||
},
|
||||
{
|
||||
"id": "error.ParamCountLimit",
|
||||
"translation": "Parameter count limit is 65536."
|
||||
},
|
||||
{
|
||||
"id": "error.unbindedParameter",
|
||||
"translation": "Unbound parameter"
|
||||
},
|
||||
{
|
||||
"id": "error.stringCut",
|
||||
"translation": "The string is cut"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionClosedOrNotBuild",
|
||||
"translation": "Connection is colsed or not build"
|
||||
}
|
||||
]
|
||||
}`
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package i18n
|
||||
|
||||
const Messages_zh_CN = `{
|
||||
"language": "zh-Hans",
|
||||
"messages": [
|
||||
{
|
||||
"id": "error.dsn.invalidSchema",
|
||||
"translation": "DSN串必须以dm://开头"
|
||||
},
|
||||
{
|
||||
"id": "error.dsn.invalidFormat",
|
||||
"translation": "DSN串格式不正确"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupported.scan",
|
||||
"translation": "Scan类型转换出错"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidParameterNumber",
|
||||
"translation": "参数个数不匹配"
|
||||
},
|
||||
{
|
||||
"id": "error.initThirdPartCipherFailed",
|
||||
"translation": "第三方加密初始化失败"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionSwitchFailed",
|
||||
"translation": "连接重置失败"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionSwitched",
|
||||
"translation": "连接已重置"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidServerMode",
|
||||
"translation": "服务器模式不匹配"
|
||||
},
|
||||
{
|
||||
"id": "error.osauthError",
|
||||
"translation": "同时使用了指定用户登录和OS认证登录, 请确定一种方式."
|
||||
},
|
||||
{
|
||||
"id": "error.notQuerySQL",
|
||||
"translation": "非查询SQL语句"
|
||||
},
|
||||
{
|
||||
"id": "error.notExecSQL",
|
||||
"translation": "非执行SQL语句"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidTranIsolation",
|
||||
"translation": "非法的事务隔离级"
|
||||
},
|
||||
{
|
||||
"id": "errorCommitInAutoCommitMode",
|
||||
"translation": "自动提交模式下不能手动提交"
|
||||
},
|
||||
{
|
||||
"id": "errorRollbackInAutoCommitMode",
|
||||
"translation": "自动提交模式下不能手动回滚"
|
||||
},
|
||||
{
|
||||
"id": "errorStatementHandleClosed",
|
||||
"translation": "语句已经关闭"
|
||||
},
|
||||
{
|
||||
"id": "errorResultSetColsed",
|
||||
"translation": "结果集已经关闭"
|
||||
},
|
||||
{
|
||||
"id": "error.communicationError",
|
||||
"translation": "网络通信异常"
|
||||
},
|
||||
{
|
||||
"id": "error.msgCheckError",
|
||||
"translation": "消息校验异常"
|
||||
},
|
||||
{
|
||||
"id": "error.unkownNetWork",
|
||||
"translation": "未知的网络"
|
||||
},
|
||||
{
|
||||
"id": "error.serverVersion",
|
||||
"translation": "服务器版本太低"
|
||||
},
|
||||
{
|
||||
"id": "error.usernameTooLong",
|
||||
"translation": "用户名超长"
|
||||
},
|
||||
{
|
||||
"id": "error.passwordTooLong",
|
||||
"translation": "密码超长"
|
||||
},
|
||||
{
|
||||
"id": "error.dataTooLong",
|
||||
"translation": "数据大小已超过可支持范围"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidColumnType",
|
||||
"translation": "无效的列类型"
|
||||
},
|
||||
{
|
||||
"id": "error.dataConvertionError",
|
||||
"translation": "类型转换异常"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidConn",
|
||||
"translation": "连接失效"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidHex",
|
||||
"translation": "无效的十六进制数字"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidBFile",
|
||||
"translation": "无效的BFile格式串"
|
||||
},
|
||||
{
|
||||
"id": "error.dataOverflow",
|
||||
"translation": "数字溢出"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidDateTimeFormat",
|
||||
"translation": "错误的日期时间类型格式"
|
||||
},
|
||||
{
|
||||
"id": "error.datetimeOverflow",
|
||||
"translation": "数字溢出"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidTimeInterval",
|
||||
"translation": "错误的时间间隔类型数据"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedInparamType",
|
||||
"translation": "输入参数类型不支持"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedOutparamType",
|
||||
"translation": "输出参数类型不支持"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedType",
|
||||
"translation": "不支持该数据类型"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidObjBlob",
|
||||
"translation": "无效的对象BLOB数据"
|
||||
},
|
||||
{
|
||||
"id": "error.structMemNotMatch",
|
||||
"translation": "记录或类数据成员不匹配"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidComplexTypeName",
|
||||
"translation": "无效的类型描述名称"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidParamterValue",
|
||||
"translation": "无效的参数值"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidArrayLen",
|
||||
"translation": "静态数组长度大于定义时长度"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidSequenceNumber",
|
||||
"translation": "无效的列序号"
|
||||
},
|
||||
{
|
||||
"id": "error.resultsetInReadOnlyStatus",
|
||||
"translation": "结果集处于只读状态"
|
||||
},
|
||||
{
|
||||
"id": "error.SSLInitFailed",
|
||||
"translation": "初始化SSL环境失败"
|
||||
},
|
||||
{
|
||||
"id": "error.LobDataHasFreed",
|
||||
"translation": "LOB数据已经被释放"
|
||||
},
|
||||
{
|
||||
"id": "error.fatalError",
|
||||
"translation": "致命错误"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidLenOrOffset",
|
||||
"translation": "长度或偏移错误"
|
||||
},
|
||||
{
|
||||
"id": "error.intervalValueOverflow",
|
||||
"translation": "时间间隔类型数据溢出"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidCipher",
|
||||
"translation": "不支持的加密类型"
|
||||
},
|
||||
{
|
||||
"id": "error.storeInNilPointer",
|
||||
"translation": "无法将数据存入空指针"
|
||||
},
|
||||
{
|
||||
"id": "error.batchError",
|
||||
"translation": "批量执行出错"
|
||||
},
|
||||
{
|
||||
"id": "warning.bpWithErr",
|
||||
"translation": "警告:批量执行部分行产生错误"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidSqlType",
|
||||
"translation": "非法的SQL语句类型"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidDateTimeValue",
|
||||
"translation": "无效的日期时间类型值"
|
||||
},
|
||||
{
|
||||
"id": "error.msgTooLong",
|
||||
"translation": "消息长度超出限制512M"
|
||||
},
|
||||
{
|
||||
"id": "error.isNull",
|
||||
"translation": "数据为NULL"
|
||||
},
|
||||
{
|
||||
"id": "error.ParamCountLimit",
|
||||
"translation": "参数个数超过最大值65536."
|
||||
},
|
||||
{
|
||||
"id": "error.unbindedParameter",
|
||||
"translation": "有参数未绑定"
|
||||
},
|
||||
{
|
||||
"id": "error.stringCut",
|
||||
"translation": "字符串截断"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionClosedOrNotBuild",
|
||||
"translation": "连接尚未建立或已经关闭"
|
||||
}
|
||||
]
|
||||
}`
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package i18n
|
||||
|
||||
const Messages_zh_HK = `{
|
||||
"language": "zh-Hant",
|
||||
"messages": [
|
||||
{
|
||||
"id": "error.dsn.invalidSchema",
|
||||
"translation": "DSN串必須以dm://開頭"
|
||||
},
|
||||
{
|
||||
"id": "error.dsn.invalidFormat",
|
||||
"translation": "DSN串格式不正確"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupported.scan",
|
||||
"translation": "Scan類型轉換出錯"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidParameterNumber",
|
||||
"translation": "參數個數不匹配"
|
||||
},
|
||||
{
|
||||
"id": "error.initThirdPartCipherFailed",
|
||||
"translation": "第三方加密初始化失敗"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionSwitchFailed",
|
||||
"translation": "連接重置失敗"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionSwitched",
|
||||
"translation": "連接已重置"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidServerMode",
|
||||
"translation": "服務器模式不匹配"
|
||||
},
|
||||
{
|
||||
"id": "error.osauthError",
|
||||
"translation": "同時使用了指定用戶登錄和OS認證登錄, 請確定一種方式."
|
||||
},
|
||||
{
|
||||
"id": "error.notQuerySQL",
|
||||
"translation": "非查詢SQL語句"
|
||||
},
|
||||
{
|
||||
"id": "error.notExecSQL",
|
||||
"translation": "非執行SQL語句"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidTranIsolation",
|
||||
"translation": "非法的事務隔離級"
|
||||
},
|
||||
{
|
||||
"id": "errorCommitInAutoCommitMode",
|
||||
"translation": "自動提交模式下不能手動提交"
|
||||
},
|
||||
{
|
||||
"id": "errorRollbackInAutoCommitMode",
|
||||
"translation": "自動提交模式下不能手動回滾"
|
||||
},
|
||||
{
|
||||
"id": "errorStatementHandleClosed",
|
||||
"translation": "語句已經關閉"
|
||||
},
|
||||
{
|
||||
"id": "errorResultSetColsed",
|
||||
"translation": "結果集已經關閉"
|
||||
},
|
||||
{
|
||||
"id": "error.communicationError",
|
||||
"translation": "網絡通信異常"
|
||||
},
|
||||
{
|
||||
"id": "error.msgCheckError",
|
||||
"translation": "消息校驗異常"
|
||||
},
|
||||
{
|
||||
"id": "error.unkownNetWork",
|
||||
"translation": "未知的網絡"
|
||||
},
|
||||
{
|
||||
"id": "error.serverVersion",
|
||||
"translation": "服務器版本太低"
|
||||
},
|
||||
{
|
||||
"id": "error.usernameTooLong",
|
||||
"translation": "用戶名超長"
|
||||
},
|
||||
{
|
||||
"id": "error.passwordTooLong",
|
||||
"translation": "密碼超長"
|
||||
},
|
||||
{
|
||||
"id": "error.dataTooLong",
|
||||
"translation": "數據大小已超過可支持範圍"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidColumnType",
|
||||
"translation": "無效的列類型"
|
||||
},
|
||||
{
|
||||
"id": "error.dataConvertionError",
|
||||
"translation": "類型轉換異常"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidConn",
|
||||
"translation": "連接失效"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidHex",
|
||||
"translation": "無效的十六進制数字"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidBFile",
|
||||
"translation": "無效的BFile格式串"
|
||||
},
|
||||
{
|
||||
"id": "error.dataOverflow",
|
||||
"translation": "数字溢出"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidDateTimeFormat",
|
||||
"translation": "錯誤的日期時間類型格式"
|
||||
},
|
||||
{
|
||||
"id": "error.datetimeOverflow",
|
||||
"translation": "数字溢出"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidTimeInterval",
|
||||
"translation": "錯誤的時間間隔類型數據"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedInparamType",
|
||||
"translation": "輸入參數類型不支持"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedOutparamType",
|
||||
"translation": "輸出參數類型不支持"
|
||||
},
|
||||
{
|
||||
"id": "error.unsupportedType",
|
||||
"translation": "不支持該數據類型"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidObjBlob",
|
||||
"translation": "無效的對象BLOB數據"
|
||||
},
|
||||
{
|
||||
"id": "error.structMemNotMatch",
|
||||
"translation": "記錄或類數據成員不匹配"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidComplexTypeName",
|
||||
"translation": "無效的類型描述名稱"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidParamterValue",
|
||||
"translation": "無效的參數值"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidArrayLen",
|
||||
"translation": "靜態數組長度大於定義時長度"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidSequenceNumber",
|
||||
"translation": "無效的列序號"
|
||||
},
|
||||
{
|
||||
"id": "error.resultsetInReadOnlyStatus",
|
||||
"translation": "結果集處於只讀狀態"
|
||||
},
|
||||
{
|
||||
"id": "error.SSLInitFailed",
|
||||
"translation": "初始化SSL環境失敗"
|
||||
},
|
||||
{
|
||||
"id": "error.LobDataHasFreed",
|
||||
"translation": "LOB數據已經被釋放"
|
||||
},
|
||||
{
|
||||
"id": "error.fatalError",
|
||||
"translation": "致命錯誤"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidLenOrOffset",
|
||||
"translation": "長度或偏移錯誤"
|
||||
},
|
||||
{
|
||||
"id": "error.intervalValueOverflow",
|
||||
"translation": "時間間隔類型數據溢出"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidCipher",
|
||||
"translation": "不支持的加密類型"
|
||||
},
|
||||
{
|
||||
"id": "error.storeInNilPointer",
|
||||
"translation": "無法將數據存入空指針"
|
||||
},
|
||||
{
|
||||
"id": "error.batchError",
|
||||
"translation": "批量執行出錯"
|
||||
},
|
||||
{
|
||||
"id": "warning.bpWithErr",
|
||||
"translation": "警告:批量執行部分行產生錯誤"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidSqlType",
|
||||
"translation": "非法的SQL語句類型"
|
||||
},
|
||||
{
|
||||
"id": "error.invalidDateTimeValue",
|
||||
"translation": "無效的日期時間類型值"
|
||||
},
|
||||
{
|
||||
"id": "error.msgTooLong",
|
||||
"translation": "消息長度超出限制512M"
|
||||
},
|
||||
{
|
||||
"id": "error.isNull",
|
||||
"translation": "數據為NULL"
|
||||
},
|
||||
{
|
||||
"id": "error.ParamCountLimit",
|
||||
"translation": "參數個數超過最大值65536."
|
||||
},
|
||||
{
|
||||
"id": "error.unbindedParameter",
|
||||
"translation": "有參數未綁定"
|
||||
},
|
||||
{
|
||||
"id": "error.stringCut",
|
||||
"translation": "字符串截斷"
|
||||
},
|
||||
{
|
||||
"id": "error.connectionClosedOrNotBuild",
|
||||
"translation": "連接尚未建立或已經關閉"
|
||||
}
|
||||
]
|
||||
}`
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import "database/sql/driver"
|
||||
|
||||
type DmArray struct {
|
||||
TypeData
|
||||
m_arrDesc *ArrayDescriptor // 数组的描述信息
|
||||
|
||||
m_arrData []TypeData // 数组中各行数据值
|
||||
|
||||
m_objArray interface{} // 从服务端获取的
|
||||
|
||||
m_itemCount int // 本次获取的行数
|
||||
|
||||
m_itemSize int // 数组中一个数组项的大小,单位bytes
|
||||
|
||||
m_objCount int // 一个数组项中存在对象类型的个数(class、动态数组)
|
||||
|
||||
m_strCount int // 一个数组项中存在字符串类型的个数
|
||||
|
||||
m_objStrOffs []int // 对象在前,字符串在后
|
||||
|
||||
typeName string
|
||||
|
||||
elements []interface{}
|
||||
|
||||
// Valid为false代表DmArray数据在数据库中为NULL
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (da *DmArray) init() *DmArray {
|
||||
da.initTypeData()
|
||||
da.m_itemCount = 0
|
||||
da.m_itemSize = 0
|
||||
da.m_objCount = 0
|
||||
da.m_strCount = 0
|
||||
da.m_objStrOffs = nil
|
||||
da.m_dumyData = nil
|
||||
da.m_offset = 0
|
||||
|
||||
da.m_objArray = nil
|
||||
da.Valid = true
|
||||
return da
|
||||
}
|
||||
|
||||
// 数据库自定义数组Array构造函数,typeName为库中定义的数组类型名称,elements为该数组类型的每个值
|
||||
//
|
||||
// 例如,自定义数组类型语句为:create or replace type myArray is array int[];
|
||||
//
|
||||
// 则绑入绑出的go对象为: val := dm.NewDmArray("myArray", []interface{} {123, 456})
|
||||
func NewDmArray(typeName string, elements []interface{}) *DmArray {
|
||||
da := new(DmArray)
|
||||
da.typeName = typeName
|
||||
da.elements = elements
|
||||
da.Valid = true
|
||||
return da
|
||||
}
|
||||
|
||||
func (da *DmArray) create(dc *DmConnection) (*DmArray, error) {
|
||||
desc, err := newArrayDescriptor(da.typeName, dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return da.createByArrayDescriptor(desc, dc)
|
||||
}
|
||||
|
||||
func (da *DmArray) createByArrayDescriptor(arrDesc *ArrayDescriptor, conn *DmConnection) (*DmArray, error) {
|
||||
|
||||
if nil == arrDesc {
|
||||
return nil, ECGO_INVALID_PARAMETER_VALUE.throw()
|
||||
}
|
||||
|
||||
da.init()
|
||||
|
||||
da.m_arrDesc = arrDesc
|
||||
if nil == da.elements {
|
||||
da.m_arrData = make([]TypeData, 0)
|
||||
} else {
|
||||
// 若为静态数组,判断给定数组长度是否超过静态数组的上限
|
||||
if arrDesc.getMDesc() == nil || (arrDesc.getMDesc().getDType() == SARRAY && len(da.elements) > arrDesc.getMDesc().getStaticArrayLength()) {
|
||||
return nil, ECGO_INVALID_ARRAY_LEN.throw()
|
||||
}
|
||||
|
||||
var err error
|
||||
da.m_arrData, err = TypeDataSV.toArray(da.elements, da.m_arrDesc.getMDesc())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
da.m_itemCount = len(da.m_arrData)
|
||||
return da, nil
|
||||
}
|
||||
|
||||
func newDmArrayByTypeData(atData []TypeData, desc *TypeDescriptor) *DmArray {
|
||||
da := new(DmArray)
|
||||
da.init()
|
||||
da.m_arrDesc = newArrayDescriptorByTypeDescriptor(desc)
|
||||
da.m_arrData = atData
|
||||
return da
|
||||
}
|
||||
|
||||
func (da *DmArray) checkIndex(index int64) error {
|
||||
if index < 0 || index > int64(len(da.m_arrData)-1) {
|
||||
return ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (da *DmArray) checkIndexAndCount(index int64, count int) error {
|
||||
err := da.checkIndex(index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count <= 0 || index+int64(count) > int64(len(da.m_arrData)) {
|
||||
return ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取Array对象在数据库中的类型名称
|
||||
func (da *DmArray) GetBaseTypeName() (string, error) {
|
||||
if err := da.checkValid(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return da.m_arrDesc.m_typeDesc.getFulName()
|
||||
}
|
||||
|
||||
// 获取Array对象的go数组对象
|
||||
func (da *DmArray) GetArray() (interface{}, error) {
|
||||
if da.m_arrData == nil || len(da.m_arrData) <= 0 {
|
||||
return nil, nil;
|
||||
}
|
||||
|
||||
return TypeDataSV.toJavaArray(da, 0, len(da.m_arrData), da.m_arrDesc.getItemDesc().getDType())
|
||||
}
|
||||
|
||||
// 获取Array对象的指定偏移和执行长度go数据对象 index从0开始
|
||||
func (da *DmArray) GetObjArray(index int64, count int) (interface{}, error) {
|
||||
var err error
|
||||
if err = da.checkValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = da.checkIndexAndCount(index, count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return TypeDataSV.toJavaArray(da, index, count, da.m_arrDesc.getItemDesc().getDType())
|
||||
}
|
||||
|
||||
func (da *DmArray) GetIntArray(index int64, count int) ([]int, error) {
|
||||
var err error
|
||||
if err = da.checkValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = da.checkIndexAndCount(index, count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_INTEGER)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tmp.([]int), nil
|
||||
}
|
||||
|
||||
func (da *DmArray) GetInt16Array(index int64, count int) ([]int16, error) {
|
||||
var err error
|
||||
if err = da.checkValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = da.checkIndexAndCount(index, count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_SHORT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tmp.([]int16), nil
|
||||
}
|
||||
|
||||
func (da *DmArray) GetInt64Array(index int64, count int) ([]int64, error) {
|
||||
var err error
|
||||
if err = da.checkValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = da.checkIndexAndCount(index, count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_LONG)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tmp.([]int64), nil
|
||||
}
|
||||
|
||||
func (da *DmArray) GetFloatArray(index int64, count int) ([]float32, error) {
|
||||
var err error
|
||||
if err = da.checkValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = da.checkIndexAndCount(index, count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_FLOAT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tmp.([]float32), nil
|
||||
}
|
||||
|
||||
func (da *DmArray) GetDoubleArray(index int64, count int) ([]float64, error) {
|
||||
var err error
|
||||
if err = da.checkValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = da.checkIndexAndCount(index, count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_DOUBLE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tmp.([]float64), nil
|
||||
}
|
||||
|
||||
func (dest *DmArray) Scan(src interface{}) error {
|
||||
if dest == nil {
|
||||
return ECGO_STORE_IN_NIL_POINTER.throw()
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmArray)
|
||||
// 将Valid标志置false表示数据库中该列为NULL
|
||||
(*dest).Valid = false
|
||||
return nil
|
||||
case *DmArray:
|
||||
*dest = *src
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN.throw()
|
||||
}
|
||||
}
|
||||
|
||||
func (array DmArray) Value() (driver.Value, error) {
|
||||
if !array.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return array, nil
|
||||
}
|
||||
|
||||
func (array *DmArray) checkValid() error {
|
||||
if !array.Valid {
|
||||
return ECGO_IS_NULL.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
)
|
||||
|
||||
type DmBlob struct {
|
||||
lob
|
||||
data []byte
|
||||
offset int64
|
||||
}
|
||||
|
||||
func newDmBlob() *DmBlob {
|
||||
return &DmBlob{
|
||||
lob: lob{
|
||||
inRow: true,
|
||||
groupId: -1,
|
||||
fileId: -1,
|
||||
pageNo: -1,
|
||||
readOver: false,
|
||||
local: true,
|
||||
updateable: true,
|
||||
length: -1,
|
||||
compatibleOracle: false,
|
||||
fetchAll: false,
|
||||
freed: false,
|
||||
modify: false,
|
||||
Valid: true,
|
||||
},
|
||||
offset: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func newBlobFromDB(value []byte, conn *DmConnection, column *column, fetchAll bool) *DmBlob {
|
||||
var blob = newDmBlob()
|
||||
blob.connection = conn
|
||||
blob.lobFlag = LOB_FLAG_BYTE
|
||||
blob.compatibleOracle = conn.CompatibleOracle()
|
||||
blob.local = false
|
||||
blob.updateable = !column.readonly
|
||||
blob.tabId = column.lobTabId
|
||||
blob.colId = column.lobColId
|
||||
|
||||
blob.inRow = Dm_build_1346.Dm_build_1439(value, NBLOB_HEAD_IN_ROW_FLAG) == LOB_IN_ROW
|
||||
blob.blobId = Dm_build_1346.Dm_build_1453(value, NBLOB_HEAD_BLOBID)
|
||||
if !blob.inRow {
|
||||
blob.groupId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_GROUPID)
|
||||
blob.fileId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_FILEID)
|
||||
blob.pageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_HEAD_OUTROW_PAGENO)
|
||||
}
|
||||
if conn.NewLobFlag {
|
||||
blob.tabId = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_TABLE_ID)
|
||||
blob.colId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_COL_ID)
|
||||
blob.rowId = Dm_build_1346.Dm_build_1453(value, NBLOB_EX_HEAD_ROW_ID)
|
||||
blob.exGroupId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_GRPID)
|
||||
blob.exFileId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_FILEID)
|
||||
blob.exPageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_FPA_PAGENO)
|
||||
}
|
||||
blob.resetCurrentInfo()
|
||||
|
||||
blob.length = blob.getLengthFromHead(value)
|
||||
if blob.inRow {
|
||||
blob.data = make([]byte, blob.length)
|
||||
if conn.NewLobFlag {
|
||||
Dm_build_1346.Dm_build_1402(blob.data, 0, value, NBLOB_EX_HEAD_SIZE, len(blob.data))
|
||||
} else {
|
||||
Dm_build_1346.Dm_build_1402(blob.data, 0, value, NBLOB_INROW_HEAD_SIZE, len(blob.data))
|
||||
}
|
||||
} else if fetchAll {
|
||||
blob.loadAllData()
|
||||
}
|
||||
return blob
|
||||
}
|
||||
|
||||
func newBlobOfLocal(value []byte, conn *DmConnection) *DmBlob {
|
||||
var blob = newDmBlob()
|
||||
blob.connection = conn
|
||||
blob.lobFlag = LOB_FLAG_BYTE
|
||||
blob.data = value
|
||||
blob.length = int64(len(blob.data))
|
||||
return blob
|
||||
}
|
||||
|
||||
func NewBlob(value []byte) *DmBlob {
|
||||
var blob = newDmBlob()
|
||||
|
||||
blob.lobFlag = LOB_FLAG_BYTE
|
||||
blob.data = value
|
||||
blob.length = int64(len(blob.data))
|
||||
return blob
|
||||
}
|
||||
|
||||
func (blob *DmBlob) Read(dest []byte) (n int, err error) {
|
||||
if err = blob.checkValid(); err != nil {
|
||||
return
|
||||
}
|
||||
result, err := blob.getBytes(blob.offset, int32(len(dest)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
blob.offset += int64(len(result))
|
||||
copy(dest, result)
|
||||
if len(result) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return len(result), nil
|
||||
}
|
||||
|
||||
func (blob *DmBlob) ReadAt(pos int, dest []byte) (n int, err error) {
|
||||
if err = blob.checkValid(); err != nil {
|
||||
return
|
||||
}
|
||||
result, err := blob.getBytes(int64(pos), int32(len(dest)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
copy(dest[0:len(result)], result)
|
||||
return len(result), nil
|
||||
}
|
||||
|
||||
func (blob *DmBlob) Write(pos int, src []byte) (n int, err error) {
|
||||
if err = blob.checkValid(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = blob.checkFreed(); err != nil {
|
||||
return
|
||||
}
|
||||
if pos < 1 {
|
||||
err = ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
return
|
||||
}
|
||||
if !blob.updateable {
|
||||
err = ECGO_RESULTSET_IS_READ_ONLY.throw()
|
||||
return
|
||||
}
|
||||
pos -= 1
|
||||
if blob.local || blob.fetchAll {
|
||||
if int64(pos) > blob.length {
|
||||
err = ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
return
|
||||
}
|
||||
blob.setLocalData(pos, src)
|
||||
n = len(src)
|
||||
} else {
|
||||
if err = blob.connection.checkClosed(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
var writeLen, err = blob.connection.Access.dm_build_638(blob, pos, src)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if blob.groupId == -1 {
|
||||
blob.setLocalData(pos, src)
|
||||
} else {
|
||||
blob.inRow = false
|
||||
blob.length = -1
|
||||
}
|
||||
n = writeLen
|
||||
|
||||
}
|
||||
blob.modify = true
|
||||
return
|
||||
}
|
||||
|
||||
func (blob *DmBlob) Truncate(length int64) error {
|
||||
var err error
|
||||
if err = blob.checkValid(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = blob.checkFreed(); err != nil {
|
||||
return err
|
||||
}
|
||||
if length < 0 {
|
||||
return ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
if !blob.updateable {
|
||||
return ECGO_RESULTSET_IS_READ_ONLY.throw()
|
||||
}
|
||||
if blob.local || blob.fetchAll {
|
||||
if length > int64(len(blob.data)) {
|
||||
return ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
if length == int64(len(blob.data)) {
|
||||
return nil
|
||||
}
|
||||
tmp := make([]byte, length)
|
||||
Dm_build_1346.Dm_build_1402(tmp, 0, blob.data, 0, len(tmp))
|
||||
blob.data = tmp
|
||||
blob.length = int64(len(tmp))
|
||||
} else {
|
||||
if err = blob.connection.checkClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
blob.length, err = blob.connection.Access.dm_build_652(&blob.lob, int(length))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if blob.groupId == -1 {
|
||||
tmp := make([]byte, blob.length)
|
||||
Dm_build_1346.Dm_build_1402(tmp, 0, blob.data, 0, int(blob.length))
|
||||
blob.data = tmp
|
||||
}
|
||||
}
|
||||
blob.modify = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dest *DmBlob) Scan(src interface{}) error {
|
||||
if dest == nil {
|
||||
return ECGO_STORE_IN_NIL_POINTER.throw()
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmBlob)
|
||||
|
||||
(*dest).Valid = false
|
||||
return nil
|
||||
case []byte:
|
||||
*dest = *NewBlob(src)
|
||||
return nil
|
||||
case *DmBlob:
|
||||
*dest = *src
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN.throw()
|
||||
}
|
||||
}
|
||||
|
||||
func (blob DmBlob) Value() (driver.Value, error) {
|
||||
if !blob.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return blob, nil
|
||||
}
|
||||
|
||||
func (blob *DmBlob) getBytes(pos int64, length int32) ([]byte, error) {
|
||||
var err error
|
||||
var leaveLength int64
|
||||
if err = blob.checkFreed(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pos < 1 || length < 0 {
|
||||
return nil, ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
pos = pos - 1
|
||||
if leaveLength, err = blob.GetLength(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leaveLength -= pos
|
||||
if leaveLength < 0 {
|
||||
return nil, ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
if int64(length) > leaveLength {
|
||||
length = int32(leaveLength)
|
||||
}
|
||||
if blob.local || blob.inRow || blob.fetchAll {
|
||||
return blob.data[pos : pos+int64(length)], nil
|
||||
} else {
|
||||
|
||||
return blob.connection.Access.dm_build_599(blob, int32(pos), length)
|
||||
}
|
||||
}
|
||||
|
||||
func (blob *DmBlob) loadAllData() {
|
||||
blob.checkFreed()
|
||||
if blob.local || blob.inRow || blob.fetchAll {
|
||||
return
|
||||
}
|
||||
len, _ := blob.GetLength()
|
||||
blob.data, _ = blob.getBytes(1, int32(len))
|
||||
blob.fetchAll = true
|
||||
}
|
||||
|
||||
func (blob *DmBlob) setLocalData(pos int, p []byte) {
|
||||
if pos+len(p) >= int(blob.length) {
|
||||
var tmp = make([]byte, pos+len(p))
|
||||
Dm_build_1346.Dm_build_1402(tmp, 0, blob.data, 0, pos)
|
||||
Dm_build_1346.Dm_build_1402(tmp, pos, p, 0, len(p))
|
||||
blob.data = tmp
|
||||
} else {
|
||||
Dm_build_1346.Dm_build_1402(blob.data, pos, p, 0, len(p))
|
||||
}
|
||||
blob.length = int64(len(blob.data))
|
||||
}
|
||||
|
||||
func (d *DmBlob) GormDataType() string {
|
||||
return "BLOB"
|
||||
}
|
||||
+279
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
)
|
||||
|
||||
type DmClob struct {
|
||||
lob
|
||||
data []rune
|
||||
serverEncoding string
|
||||
}
|
||||
|
||||
func newDmClob() *DmClob {
|
||||
return &DmClob{
|
||||
lob: lob{
|
||||
inRow: true,
|
||||
groupId: -1,
|
||||
fileId: -1,
|
||||
pageNo: -1,
|
||||
readOver: false,
|
||||
local: true,
|
||||
updateable: true,
|
||||
length: -1,
|
||||
compatibleOracle: false,
|
||||
fetchAll: false,
|
||||
freed: false,
|
||||
modify: false,
|
||||
Valid: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newClobFromDB(value []byte, conn *DmConnection, column *column, fetchAll bool) *DmClob {
|
||||
var clob = newDmClob()
|
||||
clob.connection = conn
|
||||
clob.lobFlag = LOB_FLAG_CHAR
|
||||
clob.compatibleOracle = conn.CompatibleOracle()
|
||||
clob.local = false
|
||||
clob.updateable = !column.readonly
|
||||
clob.tabId = column.lobTabId
|
||||
clob.colId = column.lobColId
|
||||
|
||||
clob.inRow = Dm_build_1346.Dm_build_1439(value, NBLOB_HEAD_IN_ROW_FLAG) == LOB_IN_ROW
|
||||
clob.blobId = Dm_build_1346.Dm_build_1453(value, NBLOB_HEAD_BLOBID)
|
||||
if !clob.inRow {
|
||||
clob.groupId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_GROUPID)
|
||||
clob.fileId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_FILEID)
|
||||
clob.pageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_HEAD_OUTROW_PAGENO)
|
||||
}
|
||||
if conn.NewLobFlag {
|
||||
clob.tabId = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_TABLE_ID)
|
||||
clob.colId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_COL_ID)
|
||||
clob.rowId = Dm_build_1346.Dm_build_1453(value, NBLOB_EX_HEAD_ROW_ID)
|
||||
clob.exGroupId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_GRPID)
|
||||
clob.exFileId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_FILEID)
|
||||
clob.exPageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_FPA_PAGENO)
|
||||
}
|
||||
clob.resetCurrentInfo()
|
||||
|
||||
clob.serverEncoding = conn.getServerEncoding()
|
||||
if clob.inRow {
|
||||
if conn.NewLobFlag {
|
||||
clob.data = []rune(Dm_build_1346.Dm_build_1503(value, NBLOB_EX_HEAD_SIZE, int(clob.getLengthFromHead(value)), clob.serverEncoding, conn))
|
||||
} else {
|
||||
clob.data = []rune(Dm_build_1346.Dm_build_1503(value, NBLOB_INROW_HEAD_SIZE, int(clob.getLengthFromHead(value)), clob.serverEncoding, conn))
|
||||
}
|
||||
clob.length = int64(len(clob.data))
|
||||
} else if fetchAll {
|
||||
clob.loadAllData()
|
||||
}
|
||||
return clob
|
||||
}
|
||||
|
||||
func newClobOfLocal(value string, conn *DmConnection) *DmClob {
|
||||
var clob = newDmClob()
|
||||
clob.connection = conn
|
||||
clob.lobFlag = LOB_FLAG_CHAR
|
||||
clob.data = []rune(value)
|
||||
clob.length = int64(len(clob.data))
|
||||
return clob
|
||||
}
|
||||
|
||||
func NewClob(value string) *DmClob {
|
||||
var clob = newDmClob()
|
||||
|
||||
clob.lobFlag = LOB_FLAG_CHAR
|
||||
clob.data = []rune(value)
|
||||
clob.length = int64(len(clob.data))
|
||||
return clob
|
||||
}
|
||||
|
||||
func (clob *DmClob) ReadString(pos int, length int) (result string, err error) {
|
||||
if err = clob.checkValid(); err != nil {
|
||||
return
|
||||
}
|
||||
result, err = clob.getSubString(int64(pos), int32(length))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(result) == 0 {
|
||||
err = io.EOF
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (clob *DmClob) WriteString(pos int, s string) (n int, err error) {
|
||||
if err = clob.checkValid(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = clob.checkFreed(); err != nil {
|
||||
return
|
||||
}
|
||||
if pos < 1 {
|
||||
err = ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
return
|
||||
}
|
||||
if !clob.updateable {
|
||||
err = ECGO_RESULTSET_IS_READ_ONLY.throw()
|
||||
return
|
||||
}
|
||||
pos -= 1
|
||||
if clob.local || clob.fetchAll {
|
||||
if int64(pos) > clob.length {
|
||||
err = ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
return
|
||||
}
|
||||
clob.setLocalData(pos, s)
|
||||
n = len(s)
|
||||
} else {
|
||||
if err = clob.connection.checkClosed(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
var writeLen, err = clob.connection.Access.dm_build_622(clob, pos, s, clob.serverEncoding)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if clob.groupId == -1 {
|
||||
clob.setLocalData(pos, s)
|
||||
} else {
|
||||
clob.inRow = false
|
||||
clob.length = -1
|
||||
}
|
||||
n = writeLen
|
||||
}
|
||||
clob.modify = true
|
||||
return
|
||||
}
|
||||
|
||||
func (clob *DmClob) Truncate(length int64) error {
|
||||
var err error
|
||||
if err = clob.checkValid(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = clob.checkFreed(); err != nil {
|
||||
return err
|
||||
}
|
||||
if length < 0 {
|
||||
return ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
if !clob.updateable {
|
||||
return ECGO_RESULTSET_IS_READ_ONLY.throw()
|
||||
}
|
||||
if clob.local || clob.fetchAll {
|
||||
if length > int64(len(clob.data)) {
|
||||
return ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
if length == int64(len(clob.data)) {
|
||||
return nil
|
||||
}
|
||||
clob.data = clob.data[0:length]
|
||||
clob.length = int64(len(clob.data))
|
||||
} else {
|
||||
if err = clob.connection.checkClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
clob.length, err = clob.connection.Access.dm_build_652(&clob.lob, int(length))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if clob.groupId == -1 {
|
||||
clob.data = clob.data[0:clob.length]
|
||||
}
|
||||
}
|
||||
clob.modify = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dest *DmClob) Scan(src interface{}) error {
|
||||
if dest == nil {
|
||||
return ECGO_STORE_IN_NIL_POINTER.throw()
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmClob)
|
||||
|
||||
(*dest).Valid = false
|
||||
return nil
|
||||
case string:
|
||||
*dest = *NewClob(src)
|
||||
return nil
|
||||
case *DmClob:
|
||||
*dest = *src
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN.throw()
|
||||
}
|
||||
}
|
||||
|
||||
func (clob DmClob) Value() (driver.Value, error) {
|
||||
if !clob.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return clob, nil
|
||||
}
|
||||
|
||||
func (clob *DmClob) getSubString(pos int64, len int32) (string, error) {
|
||||
var err error
|
||||
var leaveLength int64
|
||||
if err = clob.checkFreed(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if pos < 1 || len < 0 {
|
||||
return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
pos = pos - 1
|
||||
if leaveLength, err = clob.GetLength(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if pos > leaveLength {
|
||||
pos = leaveLength
|
||||
}
|
||||
leaveLength -= pos
|
||||
if leaveLength < 0 {
|
||||
return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
if int64(len) > leaveLength {
|
||||
len = int32(leaveLength)
|
||||
}
|
||||
if clob.local || clob.inRow || clob.fetchAll {
|
||||
if pos > clob.length {
|
||||
return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw()
|
||||
}
|
||||
return string(clob.data[pos : pos+int64(len)]), nil
|
||||
} else {
|
||||
|
||||
return clob.connection.Access.dm_build_610(clob, int32(pos), len)
|
||||
}
|
||||
}
|
||||
|
||||
func (clob *DmClob) loadAllData() {
|
||||
clob.checkFreed()
|
||||
if clob.local || clob.inRow || clob.fetchAll {
|
||||
return
|
||||
}
|
||||
len, _ := clob.GetLength()
|
||||
s, _ := clob.getSubString(1, int32(len))
|
||||
clob.data = []rune(s)
|
||||
clob.fetchAll = true
|
||||
}
|
||||
|
||||
func (clob *DmClob) setLocalData(pos int, str string) {
|
||||
if pos+len(str) >= int(clob.length) {
|
||||
clob.data = []rune(string(clob.data[0:pos]) + str)
|
||||
} else {
|
||||
clob.data = []rune(string(clob.data[0:pos]) + str + string(clob.data[pos+len(str):len(clob.data)]))
|
||||
}
|
||||
clob.length = int64(len(clob.data))
|
||||
}
|
||||
|
||||
func (d *DmClob) GormDataType() string {
|
||||
return "CLOB"
|
||||
}
|
||||
+874
@@ -0,0 +1,874 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"gitee.com/chunanyong/dm/parser"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
"golang.org/x/text/encoding"
|
||||
)
|
||||
|
||||
type DmConnection struct {
|
||||
filterable
|
||||
mu sync.Mutex
|
||||
|
||||
dmConnector *DmConnector
|
||||
Access *dm_build_414
|
||||
stmtMap map[int32]*DmStatement
|
||||
|
||||
lastExecInfo *execRetInfo
|
||||
lexer *parser.Lexer
|
||||
encode encoding.Encoding
|
||||
encodeBuffer *bytes.Buffer
|
||||
transformReaderDst []byte
|
||||
transformReaderSrc []byte
|
||||
|
||||
serverEncoding string
|
||||
GlobalServerSeries int
|
||||
ServerVersion string
|
||||
Malini2 bool
|
||||
Execute2 bool
|
||||
LobEmptyCompOrcl bool
|
||||
IsoLevel int32
|
||||
ReadOnly bool
|
||||
NewLobFlag bool
|
||||
sslEncrypt int
|
||||
MaxRowSize int32
|
||||
DDLAutoCommit bool
|
||||
BackSlashFlag bool
|
||||
SvrStat int32
|
||||
SvrMode int32
|
||||
ConstParaOpt bool
|
||||
DbTimezone int16
|
||||
LifeTimeRemainder int16
|
||||
InstanceName string
|
||||
Schema string
|
||||
LastLoginIP string
|
||||
LastLoginTime string
|
||||
FailedAttempts int32
|
||||
LoginWarningID int32
|
||||
GraceTimeRemainder int32
|
||||
Guid string
|
||||
DbName string
|
||||
StandbyHost string
|
||||
StandbyPort int32
|
||||
StandbyCount int32
|
||||
SessionID int64
|
||||
OracleDateLanguage byte
|
||||
FormatDate string
|
||||
FormatTimestamp string
|
||||
FormatTimestampTZ string
|
||||
FormatTime string
|
||||
FormatTimeTZ string
|
||||
Local bool
|
||||
MsgVersion int32
|
||||
TrxStatus int32
|
||||
dscControl bool
|
||||
trxFinish bool
|
||||
autoCommit bool
|
||||
isBatch bool
|
||||
|
||||
watching bool
|
||||
watcher chan<- context.Context
|
||||
closech chan struct{}
|
||||
finished chan<- struct{}
|
||||
canceled atomicError
|
||||
closed atomicBool
|
||||
}
|
||||
|
||||
func (conn *DmConnection) setTrxFinish(status int32) {
|
||||
switch status & Dm_build_825 {
|
||||
case Dm_build_822, Dm_build_823, Dm_build_824:
|
||||
conn.trxFinish = true
|
||||
default:
|
||||
conn.trxFinish = false
|
||||
}
|
||||
}
|
||||
|
||||
func (dmConn *DmConnection) init() {
|
||||
|
||||
dmConn.stmtMap = make(map[int32]*DmStatement)
|
||||
dmConn.DbTimezone = 0
|
||||
dmConn.GlobalServerSeries = 0
|
||||
dmConn.MaxRowSize = 0
|
||||
dmConn.LobEmptyCompOrcl = false
|
||||
dmConn.ReadOnly = false
|
||||
dmConn.DDLAutoCommit = false
|
||||
dmConn.ConstParaOpt = false
|
||||
dmConn.IsoLevel = -1
|
||||
dmConn.Malini2 = true
|
||||
dmConn.NewLobFlag = true
|
||||
dmConn.Execute2 = true
|
||||
dmConn.serverEncoding = ENCODING_GB18030
|
||||
dmConn.TrxStatus = Dm_build_773
|
||||
dmConn.setTrxFinish(dmConn.TrxStatus)
|
||||
dmConn.OracleDateLanguage = byte(Locale)
|
||||
dmConn.lastExecInfo = NewExceInfo()
|
||||
dmConn.MsgVersion = Dm_build_706
|
||||
|
||||
dmConn.idGenerator = dmConnIDGenerator
|
||||
}
|
||||
|
||||
func (dmConn *DmConnection) reset() {
|
||||
dmConn.DbTimezone = 0
|
||||
dmConn.GlobalServerSeries = 0
|
||||
dmConn.MaxRowSize = 0
|
||||
dmConn.LobEmptyCompOrcl = false
|
||||
dmConn.ReadOnly = false
|
||||
dmConn.DDLAutoCommit = false
|
||||
dmConn.ConstParaOpt = false
|
||||
dmConn.IsoLevel = -1
|
||||
dmConn.Malini2 = true
|
||||
dmConn.NewLobFlag = true
|
||||
dmConn.Execute2 = true
|
||||
dmConn.serverEncoding = ENCODING_GB18030
|
||||
dmConn.TrxStatus = Dm_build_773
|
||||
dmConn.setTrxFinish(dmConn.TrxStatus)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) checkClosed() error {
|
||||
if dc.closed.IsSet() {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) executeInner(query string, execType int16) (interface{}, error) {
|
||||
|
||||
stmt, err := NewDmStmt(dc, query)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if execType == Dm_build_790 {
|
||||
defer stmt.close()
|
||||
}
|
||||
|
||||
stmt.innerUsed = true
|
||||
|
||||
var escapeSql = query
|
||||
if stmt.dmConn.dmConnector.escapeProcess {
|
||||
escapeSql, err = stmt.dmConn.escape(escapeSql, stmt.dmConn.dmConnector.keyWords)
|
||||
if err != nil {
|
||||
stmt.close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
stmt.nativeSql = escapeSql
|
||||
|
||||
var optParamList []OptParameter
|
||||
|
||||
if stmt.dmConn.ConstParaOpt {
|
||||
optParamList = make([]OptParameter, 0)
|
||||
stmt.nativeSql, optParamList, err = stmt.dmConn.execOpt(stmt.nativeSql, optParamList, stmt.dmConn.getServerEncoding(), stmt.dmConn.BackSlashFlag)
|
||||
}
|
||||
|
||||
if execType == Dm_build_789 && dc.dmConnector.enRsCache {
|
||||
rpv, err := rp.get(stmt, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rpv != nil {
|
||||
stmt.execInfo = rpv.execInfo
|
||||
dc.lastExecInfo = rpv.execInfo
|
||||
return newDmRows(rpv.getResultSet(stmt)), nil
|
||||
}
|
||||
}
|
||||
|
||||
var info *execRetInfo
|
||||
|
||||
if optParamList != nil && len(optParamList) > 0 {
|
||||
info, err = dc.Access.Dm_build_497(stmt, optParamList)
|
||||
if err != nil {
|
||||
stmt.nativeSql = escapeSql
|
||||
info, err = dc.Access.Dm_build_503(stmt, execType)
|
||||
}
|
||||
} else {
|
||||
info, err = dc.Access.Dm_build_503(stmt, execType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
stmt.close()
|
||||
return nil, err
|
||||
}
|
||||
dc.lastExecInfo = info
|
||||
|
||||
if execType == Dm_build_789 && info.hasResultSet {
|
||||
return newDmRows(newInnerRows(0, stmt, info)), nil
|
||||
} else {
|
||||
return newDmResult(stmt, info), nil
|
||||
}
|
||||
}
|
||||
|
||||
func g2dbIsoLevel(isoLevel int32) int32 {
|
||||
switch isoLevel {
|
||||
case 1:
|
||||
return Dm_build_777
|
||||
case 2:
|
||||
return Dm_build_778
|
||||
case 4:
|
||||
return Dm_build_779
|
||||
case 6:
|
||||
return Dm_build_780
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Begin() (driver.Tx, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.begin()
|
||||
} else {
|
||||
return dc.filterChain.reset().DmConnectionBegin(dc)
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.beginTx(ctx, opts)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionBeginTx(dc, ctx, opts)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Commit() error {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.commit()
|
||||
} else {
|
||||
return dc.filterChain.reset().DmConnectionCommit(dc)
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Rollback() error {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.rollback()
|
||||
} else {
|
||||
return dc.filterChain.reset().DmConnectionRollback(dc)
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Close() error {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.close()
|
||||
} else {
|
||||
return dc.filterChain.reset().DmConnectionClose(dc)
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Ping(ctx context.Context) error {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.ping(ctx)
|
||||
} else {
|
||||
return dc.filterChain.reset().DmConnectionPing(dc, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.exec(query, args)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionExec(dc, query, args)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.execContext(ctx, query, args)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionExecContext(dc, ctx, query, args)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Query(query string, args []driver.Value) (driver.Rows, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.query(query, args)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionQuery(dc, query, args)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.queryContext(ctx, query, args)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionQueryContext(dc, ctx, query, args)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) Prepare(query string) (driver.Stmt, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.prepare(query)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionPrepare(dc, query)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.prepareContext(ctx, query)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionPrepareContext(dc, ctx, query)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) ResetSession(ctx context.Context) error {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.resetSession(ctx)
|
||||
}
|
||||
if err := dc.filterChain.reset().DmConnectionResetSession(dc, ctx); err != nil {
|
||||
return driver.ErrBadConn
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) CheckNamedValue(nv *driver.NamedValue) error {
|
||||
if len(dc.filterChain.filters) == 0 {
|
||||
return dc.checkNamedValue(nv)
|
||||
}
|
||||
return dc.filterChain.reset().DmConnectionCheckNamedValue(dc, nv)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) begin() (*DmConnection, error) {
|
||||
return dc.beginTx(context.Background(), driver.TxOptions{driver.IsolationLevel(sql.LevelDefault), false})
|
||||
}
|
||||
|
||||
func (dc *DmConnection) beginTx(ctx context.Context, opts driver.TxOptions) (*DmConnection, error) {
|
||||
if err := dc.watchCancel(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dc.finish()
|
||||
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc.autoCommit = false
|
||||
|
||||
if dc.ReadOnly != opts.ReadOnly {
|
||||
dc.ReadOnly = opts.ReadOnly
|
||||
var readonly = 0
|
||||
if opts.ReadOnly {
|
||||
readonly = 1
|
||||
}
|
||||
dc.exec(fmt.Sprintf("SP_SET_SESSION_READONLY(%d)", readonly), nil)
|
||||
}
|
||||
|
||||
if dc.IsoLevel != int32(opts.Isolation) {
|
||||
switch sql.IsolationLevel(opts.Isolation) {
|
||||
case sql.LevelDefault:
|
||||
dc.IsoLevel = int32(sql.LevelReadCommitted)
|
||||
case sql.LevelReadUncommitted, sql.LevelReadCommitted, sql.LevelSerializable:
|
||||
dc.IsoLevel = int32(opts.Isolation)
|
||||
case sql.LevelRepeatableRead:
|
||||
if dc.CompatibleMysql() {
|
||||
dc.IsoLevel = int32(sql.LevelReadCommitted)
|
||||
} else {
|
||||
return nil, ECGO_INVALID_TRAN_ISOLATION.throw()
|
||||
}
|
||||
default:
|
||||
return nil, ECGO_INVALID_TRAN_ISOLATION.throw()
|
||||
}
|
||||
|
||||
err = dc.Access.Dm_build_565(dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return dc, nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) commit() error {
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
dc.autoCommit = dc.dmConnector.autoCommit
|
||||
if dc.ReadOnly {
|
||||
dc.exec("SP_SET_SESSION_READONLY(0)", nil)
|
||||
}
|
||||
}()
|
||||
|
||||
if !dc.autoCommit || !dc.trxFinish {
|
||||
err = dc.Access.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dc.trxFinish = true
|
||||
return nil
|
||||
} else if !dc.dmConnector.alwayseAllowCommit {
|
||||
return ECGO_COMMIT_IN_AUTOCOMMIT_MODE.throw()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) rollback() error {
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
dc.autoCommit = dc.dmConnector.autoCommit
|
||||
if dc.ReadOnly {
|
||||
dc.exec("SP_SET_SESSION_READONLY(0)", nil)
|
||||
}
|
||||
}()
|
||||
|
||||
if !dc.autoCommit {
|
||||
err = dc.Access.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dc.trxFinish = true
|
||||
return nil
|
||||
} else if !dc.dmConnector.alwayseAllowCommit {
|
||||
return ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE.throw()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) reconnect() error {
|
||||
err := dc.Access.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, stmt := range dc.stmtMap {
|
||||
|
||||
for id, rs := range stmt.rsMap {
|
||||
rs.Close()
|
||||
delete(stmt.rsMap, id)
|
||||
}
|
||||
}
|
||||
|
||||
var newConn *DmConnection
|
||||
if dc.dmConnector.group != nil {
|
||||
if newConn, err = dc.dmConnector.group.connect(dc.dmConnector); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
newConn, err = dc.dmConnector.connect(context.Background())
|
||||
}
|
||||
|
||||
oldMap := dc.stmtMap
|
||||
newConn.mu = dc.mu
|
||||
newConn.filterable = dc.filterable
|
||||
*dc = *newConn
|
||||
|
||||
for _, stmt := range oldMap {
|
||||
if stmt.closed {
|
||||
continue
|
||||
}
|
||||
err = dc.Access.Dm_build_475(stmt)
|
||||
if err != nil {
|
||||
stmt.free()
|
||||
continue
|
||||
}
|
||||
|
||||
if stmt.prepared || stmt.paramCount > 0 {
|
||||
if err = stmt.prepare(); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
dc.stmtMap[stmt.id] = stmt
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) cleanup() {
|
||||
dc.close()
|
||||
}
|
||||
|
||||
func (dc *DmConnection) close() error {
|
||||
if !dc.closed.TrySet(true) {
|
||||
return nil
|
||||
}
|
||||
|
||||
util.AbsorbPanic(func() {
|
||||
close(dc.closech)
|
||||
})
|
||||
if dc.Access == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dc.rollback()
|
||||
|
||||
for _, stmt := range dc.stmtMap {
|
||||
stmt.free()
|
||||
}
|
||||
|
||||
dc.Access.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) ping(ctx context.Context) error {
|
||||
if err := dc.watchCancel(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dc.finish()
|
||||
|
||||
rows, err := dc.query("select 1", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return rows.close()
|
||||
}
|
||||
|
||||
func (dc *DmConnection) exec(query string, args []driver.Value) (*DmResult, error) {
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if args != nil && len(args) > 0 {
|
||||
stmt, err := dc.prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.close()
|
||||
dc.lastExecInfo = stmt.execInfo
|
||||
|
||||
return stmt.exec(args)
|
||||
} else {
|
||||
r1, err := dc.executeInner(query, Dm_build_790)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r2, ok := r1.(*DmResult); ok {
|
||||
return r2, nil
|
||||
} else {
|
||||
return nil, ECGO_NOT_EXEC_SQL.throw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) execContext(ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) {
|
||||
if err := dc.watchCancel(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dc.finish()
|
||||
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if args != nil && len(args) > 0 {
|
||||
stmt, err := dc.prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.close()
|
||||
dc.lastExecInfo = stmt.execInfo
|
||||
dargs, err := namedValueToValue(stmt, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stmt.exec(dargs)
|
||||
} else {
|
||||
r1, err := dc.executeInner(query, Dm_build_790)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r2, ok := r1.(*DmResult); ok {
|
||||
return r2, nil
|
||||
} else {
|
||||
return nil, ECGO_NOT_EXEC_SQL.throw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) query(query string, args []driver.Value) (*DmRows, error) {
|
||||
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if args != nil && len(args) > 0 {
|
||||
stmt, err := dc.prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dc.lastExecInfo = stmt.execInfo
|
||||
|
||||
stmt.innerUsed = true
|
||||
return stmt.query(args)
|
||||
|
||||
} else {
|
||||
r1, err := dc.executeInner(query, Dm_build_789)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r2, ok := r1.(*DmRows); ok {
|
||||
return r2, nil
|
||||
} else {
|
||||
return nil, ECGO_NOT_QUERY_SQL.throw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *DmConnection) queryContext(ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) {
|
||||
if err := dc.watchCancel(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dc.finish()
|
||||
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if args != nil && len(args) > 0 {
|
||||
stmt, err := dc.prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dc.lastExecInfo = stmt.execInfo
|
||||
|
||||
stmt.innerUsed = true
|
||||
dargs, err := namedValueToValue(stmt, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stmt.query(dargs)
|
||||
|
||||
} else {
|
||||
r1, err := dc.executeInner(query, Dm_build_789)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r2, ok := r1.(*DmRows); ok {
|
||||
return r2, nil
|
||||
} else {
|
||||
return nil, ECGO_NOT_QUERY_SQL.throw()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (dc *DmConnection) prepare(query string) (stmt *DmStatement, err error) {
|
||||
if err = dc.checkClosed(); err != nil {
|
||||
return
|
||||
}
|
||||
if stmt, err = NewDmStmt(dc, query); err != nil {
|
||||
return
|
||||
}
|
||||
if err = stmt.prepare(); err != nil {
|
||||
stmt.close()
|
||||
stmt = nil
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dc *DmConnection) prepareContext(ctx context.Context, query string) (*DmStatement, error) {
|
||||
if err := dc.watchCancel(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dc.finish()
|
||||
|
||||
return dc.prepare(query)
|
||||
}
|
||||
|
||||
func (dc *DmConnection) resetSession(ctx context.Context) error {
|
||||
if err := dc.watchCancel(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
defer dc.finish()
|
||||
|
||||
err := dc.checkClosed()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) checkNamedValue(nv *driver.NamedValue) error {
|
||||
var err error
|
||||
var cvt = converter{dc, false}
|
||||
nv.Value, err = cvt.ConvertValue(nv.Value)
|
||||
dc.isBatch = cvt.isBatch
|
||||
return err
|
||||
}
|
||||
|
||||
func (dc *DmConnection) driverQuery(query string) (*DmStatement, *DmRows, error) {
|
||||
stmt, err := NewDmStmt(dc, query)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
stmt.innerUsed = true
|
||||
stmt.innerExec = true
|
||||
info, err := dc.Access.Dm_build_503(stmt, Dm_build_789)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
dc.lastExecInfo = info
|
||||
stmt.innerExec = false
|
||||
return stmt, newDmRows(newInnerRows(0, stmt, info)), nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) getIndexOnEPGroup() int32 {
|
||||
if dc.dmConnector.group == nil || dc.dmConnector.group.epList == nil {
|
||||
return -1
|
||||
}
|
||||
for i := 0; i < len(dc.dmConnector.group.epList); i++ {
|
||||
ep := dc.dmConnector.group.epList[i]
|
||||
if dc.dmConnector.host == ep.host && dc.dmConnector.port == ep.port {
|
||||
return int32(i)
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (dc *DmConnection) getServerEncoding() string {
|
||||
if dc.dmConnector.charCode != "" {
|
||||
return dc.dmConnector.charCode
|
||||
}
|
||||
return dc.serverEncoding
|
||||
}
|
||||
|
||||
func (dc *DmConnection) lobFetchAll() bool {
|
||||
return dc.dmConnector.lobMode == 2
|
||||
}
|
||||
|
||||
func (conn *DmConnection) CompatibleOracle() bool {
|
||||
return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_ORACLE
|
||||
}
|
||||
|
||||
func (conn *DmConnection) CompatibleMysql() bool {
|
||||
return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_MYSQL
|
||||
}
|
||||
|
||||
func (conn *DmConnection) cancel(err error) {
|
||||
conn.canceled.Set(err)
|
||||
conn.close()
|
||||
|
||||
}
|
||||
|
||||
func (conn *DmConnection) finish() {
|
||||
if !conn.watching || conn.finished == nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case conn.finished <- struct{}{}:
|
||||
conn.watching = false
|
||||
case <-conn.closech:
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *DmConnection) startWatcher() {
|
||||
watcher := make(chan context.Context, 1)
|
||||
conn.watcher = watcher
|
||||
finished := make(chan struct{})
|
||||
conn.finished = finished
|
||||
go func() {
|
||||
for {
|
||||
var ctx context.Context
|
||||
select {
|
||||
case ctx = <-watcher:
|
||||
case <-conn.closech:
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
conn.cancel(ctx.Err())
|
||||
case <-finished:
|
||||
case <-conn.closech:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (conn *DmConnection) watchCancel(ctx context.Context) error {
|
||||
if conn.watching {
|
||||
|
||||
conn.cleanup()
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ctx.Done() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if conn.watcher == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
conn.watching = true
|
||||
conn.watcher <- ctx
|
||||
return nil
|
||||
}
|
||||
|
||||
type noCopy struct{}
|
||||
|
||||
func (*noCopy) Lock() {}
|
||||
|
||||
type atomicBool struct {
|
||||
_noCopy noCopy
|
||||
value uint32
|
||||
}
|
||||
|
||||
func (ab *atomicBool) IsSet() bool {
|
||||
return atomic.LoadUint32(&ab.value) > 0
|
||||
}
|
||||
|
||||
func (ab *atomicBool) Set(value bool) {
|
||||
if value {
|
||||
atomic.StoreUint32(&ab.value, 1)
|
||||
} else {
|
||||
atomic.StoreUint32(&ab.value, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (ab *atomicBool) TrySet(value bool) bool {
|
||||
if value {
|
||||
return atomic.SwapUint32(&ab.value, 1) == 0
|
||||
}
|
||||
return atomic.SwapUint32(&ab.value, 0) > 0
|
||||
}
|
||||
|
||||
type atomicError struct {
|
||||
_noCopy noCopy
|
||||
value atomic.Value
|
||||
}
|
||||
|
||||
func (ae *atomicError) Set(value error) {
|
||||
ae.value.Store(value)
|
||||
}
|
||||
|
||||
func (ae *atomicError) Value() error {
|
||||
if v := ae.value.Load(); v != nil {
|
||||
|
||||
return v.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+985
@@ -0,0 +1,985 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
const (
|
||||
TimeZoneKey = "timeZone"
|
||||
EnRsCacheKey = "enRsCache"
|
||||
RsCacheSizeKey = "rsCacheSize"
|
||||
RsRefreshFreqKey = "rsRefreshFreq"
|
||||
LoginPrimary = "loginPrimary"
|
||||
LoginModeKey = "loginMode"
|
||||
LoginStatusKey = "loginStatus"
|
||||
LoginDscCtrlKey = "loginDscCtrl"
|
||||
SwitchTimesKey = "switchTimes"
|
||||
SwitchIntervalKey = "switchInterval"
|
||||
EpSelectorKey = "epSelector"
|
||||
PrimaryKey = "primaryKey"
|
||||
KeywordsKey = "keywords"
|
||||
CompressKey = "compress"
|
||||
CompressIdKey = "compressId"
|
||||
LoginEncryptKey = "loginEncrypt"
|
||||
CommunicationEncryptKey = "communicationEncrypt"
|
||||
DirectKey = "direct"
|
||||
Dec2DoubleKey = "dec2double"
|
||||
RwSeparateKey = "rwSeparate"
|
||||
RwPercentKey = "rwPercent"
|
||||
RwAutoDistributeKey = "rwAutoDistribute"
|
||||
CompatibleModeKey = "compatibleMode"
|
||||
CompatibleOraKey = "comOra"
|
||||
CipherPathKey = "cipherPath"
|
||||
DoSwitchKey = "doSwitch"
|
||||
DriverReconnectKey = "driverReconnect"
|
||||
ClusterKey = "cluster"
|
||||
LanguageKey = "language"
|
||||
DbAliveCheckFreqKey = "dbAliveCheckFreq"
|
||||
RwStandbyRecoverTimeKey = "rwStandbyRecoverTime"
|
||||
LogLevelKey = "logLevel"
|
||||
LogDirKey = "logDir"
|
||||
LogBufferPoolSizeKey = "logBufferPoolSize"
|
||||
LogBufferSizeKey = "logBufferSize"
|
||||
LogFlusherQueueSizeKey = "logFlusherQueueSize"
|
||||
LogFlushFreqKey = "logFlushFreq"
|
||||
StatEnableKey = "statEnable"
|
||||
StatDirKey = "statDir"
|
||||
StatFlushFreqKey = "statFlushFreq"
|
||||
StatHighFreqSqlCountKey = "statHighFreqSqlCount"
|
||||
StatSlowSqlCountKey = "statSlowSqlCount"
|
||||
StatSqlMaxCountKey = "statSqlMaxCount"
|
||||
StatSqlRemoveModeKey = "statSqlRemoveMode"
|
||||
AddressRemapKey = "addressRemap"
|
||||
UserRemapKey = "userRemap"
|
||||
ConnectTimeoutKey = "connectTimeout"
|
||||
LoginCertificateKey = "loginCertificate"
|
||||
UrlKey = "url"
|
||||
HostKey = "host"
|
||||
PortKey = "port"
|
||||
UserKey = "user"
|
||||
PasswordKey = "password"
|
||||
DialNameKey = "dialName"
|
||||
RwStandbyKey = "rwStandby"
|
||||
IsCompressKey = "isCompress"
|
||||
RwHAKey = "rwHA"
|
||||
RwIgnoreSqlKey = "rwIgnoreSql"
|
||||
AppNameKey = "appName"
|
||||
OsNameKey = "osName"
|
||||
MppLocalKey = "mppLocal"
|
||||
SocketTimeoutKey = "socketTimeout"
|
||||
SessionTimeoutKey = "sessionTimeout"
|
||||
ContinueBatchOnErrorKey = "continueBatchOnError"
|
||||
BatchAllowMaxErrorsKey = "batchAllowMaxErrors"
|
||||
EscapeProcessKey = "escapeProcess"
|
||||
AutoCommitKey = "autoCommit"
|
||||
MaxRowsKey = "maxRows"
|
||||
RowPrefetchKey = "rowPrefetch"
|
||||
BufPrefetchKey = "bufPrefetch"
|
||||
LobModeKey = "LobMode"
|
||||
StmtPoolSizeKey = "StmtPoolSize"
|
||||
|
||||
AlwayseAllowCommitKey = "AlwayseAllowCommit"
|
||||
BatchTypeKey = "batchType"
|
||||
BatchNotOnCallKey = "batchNotOnCall"
|
||||
IsBdtaRSKey = "isBdtaRS"
|
||||
ClobAsStringKey = "clobAsString"
|
||||
SslCertPathKey = "sslCertPath"
|
||||
SslKeyPathKey = "sslKeyPath"
|
||||
SslFilesPathKey = "sslFilesPath"
|
||||
KerberosLoginConfPathKey = "kerberosLoginConfPath"
|
||||
UKeyNameKey = "uKeyName"
|
||||
UKeyPinKey = "uKeyPin"
|
||||
ColumnNameUpperCaseKey = "columnNameUpperCase"
|
||||
ColumnNameCaseKey = "columnNameCase"
|
||||
DatabaseProductNameKey = "databaseProductName"
|
||||
OsAuthTypeKey = "osAuthType"
|
||||
SchemaKey = "schema"
|
||||
CatalogKey = "catalog"
|
||||
ServerOptionKey = "serverOption"
|
||||
ClobToBytesKey = "clobToBytes"
|
||||
|
||||
DO_SWITCH_OFF int32 = 0
|
||||
DO_SWITCH_WHEN_CONN_ERROR int32 = 1
|
||||
DO_SWITCH_WHEN_EP_RECOVER int32 = 2
|
||||
|
||||
CLUSTER_TYPE_NORMAL int32 = 0
|
||||
CLUSTER_TYPE_RW int32 = 1
|
||||
CLUSTER_TYPE_DW int32 = 2
|
||||
CLUSTER_TYPE_DSC int32 = 3
|
||||
CLUSTER_TYPE_MPP int32 = 4
|
||||
|
||||
EP_STATUS_OK int32 = 1
|
||||
EP_STATUS_ERROR int32 = 2
|
||||
|
||||
LOGIN_MODE_PRIMARY_FIRST int32 = 0
|
||||
|
||||
LOGIN_MODE_PRIMARY_ONLY int32 = 1
|
||||
|
||||
LOGIN_MODE_STANDBY_ONLY int32 = 2
|
||||
|
||||
LOGIN_MODE_STANDBY_FIRST int32 = 3
|
||||
|
||||
LOGIN_MODE_NORMAL_FIRST int32 = 4
|
||||
|
||||
SERVER_MODE_NORMAL int32 = 0
|
||||
|
||||
SERVER_MODE_PRIMARY int32 = 1
|
||||
|
||||
SERVER_MODE_STANDBY int32 = 2
|
||||
|
||||
SERVER_STATUS_MOUNT int32 = 3
|
||||
|
||||
SERVER_STATUS_OPEN int32 = 4
|
||||
|
||||
SERVER_STATUS_SUSPEND int32 = 5
|
||||
|
||||
COMPATIBLE_MODE_ORACLE int = 1
|
||||
|
||||
COMPATIBLE_MODE_MYSQL int = 2
|
||||
|
||||
LANGUAGE_CN int = 0
|
||||
|
||||
LANGUAGE_EN int = 1
|
||||
|
||||
LANGUAGE_CNT_HK = 2
|
||||
|
||||
COLUMN_NAME_NATURAL_CASE = 0
|
||||
|
||||
COLUMN_NAME_UPPER_CASE = 1
|
||||
|
||||
COLUMN_NAME_LOWER_CASE = 2
|
||||
|
||||
RW_SEPARATE_OFF int32 = 0
|
||||
|
||||
RW_SEPARATE_CLIENT int32 = 1
|
||||
|
||||
RW_SEPARATE_EP_GROUP int32 = 2
|
||||
|
||||
RW_SEPARATE_DB int32 = 3
|
||||
|
||||
RW_SEPARATE_DB_APPLY_WAIT int32 = 4
|
||||
|
||||
RW_SEPARATE_USER_DEFINED int32 = 5
|
||||
|
||||
compressDef = Dm_build_784
|
||||
compressIDDef = Dm_build_785
|
||||
|
||||
charCodeDef = ""
|
||||
|
||||
enRsCacheDef = false
|
||||
|
||||
rsCacheSizeDef = 20
|
||||
|
||||
rsRefreshFreqDef = 10
|
||||
|
||||
loginModeDef = LOGIN_MODE_NORMAL_FIRST
|
||||
|
||||
loginStatusDef = 0
|
||||
|
||||
loginEncryptDef = true
|
||||
|
||||
loginCertificateDef = ""
|
||||
|
||||
dec2DoubleDef = false
|
||||
|
||||
rwHADef = false
|
||||
|
||||
rwStandbyDef = false
|
||||
|
||||
rwSeparateDef = RW_SEPARATE_OFF
|
||||
|
||||
rwPercentDef = 25
|
||||
|
||||
rwAutoDistributeDef = true
|
||||
|
||||
rwStandbyRecoverTimeDef = 1000
|
||||
|
||||
cipherPathDef = ""
|
||||
|
||||
urlDef = ""
|
||||
|
||||
userDef = "SYSDBA"
|
||||
|
||||
passwordDef = "SYSDBA"
|
||||
|
||||
hostDef = "localhost"
|
||||
|
||||
portDef = DEFAULT_PORT
|
||||
|
||||
appNameDef = ""
|
||||
|
||||
mppLocalDef = false
|
||||
|
||||
socketTimeoutDef = 0
|
||||
|
||||
connectTimeoutDef = 5000
|
||||
|
||||
sessionTimeoutDef = 0
|
||||
|
||||
osAuthTypeDef = Dm_build_767
|
||||
|
||||
continueBatchOnErrorDef = false
|
||||
|
||||
escapeProcessDef = false
|
||||
|
||||
autoCommitDef = true
|
||||
|
||||
maxRowsDef = 0
|
||||
|
||||
rowPrefetchDef = Dm_build_768
|
||||
|
||||
bufPrefetchDef = 0
|
||||
|
||||
lobModeDef = 1
|
||||
|
||||
stmtPoolMaxSizeDef = 15
|
||||
|
||||
alwayseAllowCommitDef = true
|
||||
|
||||
isBdtaRSDef = false
|
||||
|
||||
kerberosLoginConfPathDef = ""
|
||||
|
||||
uKeyNameDef = ""
|
||||
|
||||
uKeyPinDef = ""
|
||||
|
||||
databaseProductNameDef = ""
|
||||
|
||||
caseSensitiveDef = true
|
||||
|
||||
compatibleModeDef = 0
|
||||
)
|
||||
|
||||
type DmConnector struct {
|
||||
filterable
|
||||
|
||||
mu sync.Mutex
|
||||
|
||||
dmDriver *DmDriver
|
||||
|
||||
compress int
|
||||
|
||||
compressID int8
|
||||
|
||||
newClientType bool
|
||||
|
||||
charCode string
|
||||
|
||||
enRsCache bool
|
||||
|
||||
rsCacheSize int
|
||||
|
||||
rsRefreshFreq int
|
||||
|
||||
loginMode int32
|
||||
|
||||
loginStatus int
|
||||
|
||||
loginDscCtrl bool
|
||||
|
||||
switchTimes int32
|
||||
|
||||
switchInterval int
|
||||
|
||||
epSelector int32
|
||||
|
||||
keyWords []string
|
||||
|
||||
loginEncrypt bool
|
||||
|
||||
loginCertificate string
|
||||
|
||||
dec2Double bool
|
||||
|
||||
rwHA bool
|
||||
|
||||
rwStandby bool
|
||||
|
||||
rwSeparate int32
|
||||
|
||||
rwPercent int32
|
||||
|
||||
rwAutoDistribute bool
|
||||
|
||||
rwStandbyRecoverTime int
|
||||
|
||||
rwIgnoreSql bool
|
||||
|
||||
doSwitch int32
|
||||
|
||||
driverReconnect bool
|
||||
|
||||
cluster int32
|
||||
|
||||
cipherPath string
|
||||
|
||||
url string
|
||||
|
||||
user string
|
||||
|
||||
password string
|
||||
|
||||
dialName string
|
||||
|
||||
host string
|
||||
|
||||
group *epGroup
|
||||
|
||||
port int32
|
||||
|
||||
appName string
|
||||
|
||||
osName string
|
||||
|
||||
mppLocal bool
|
||||
|
||||
socketTimeout int
|
||||
|
||||
connectTimeout int
|
||||
|
||||
sessionTimeout int
|
||||
|
||||
osAuthType byte
|
||||
|
||||
continueBatchOnError bool
|
||||
|
||||
batchAllowMaxErrors int32
|
||||
|
||||
escapeProcess bool
|
||||
|
||||
autoCommit bool
|
||||
|
||||
maxRows int
|
||||
|
||||
rowPrefetch int
|
||||
|
||||
bufPrefetch int
|
||||
|
||||
lobMode int
|
||||
|
||||
stmtPoolMaxSize int
|
||||
|
||||
alwayseAllowCommit bool
|
||||
|
||||
batchType int
|
||||
|
||||
batchNotOnCall bool
|
||||
|
||||
isBdtaRS bool
|
||||
|
||||
sslCertPath string
|
||||
|
||||
sslKeyPath string
|
||||
|
||||
sslFilesPath string
|
||||
|
||||
kerberosLoginConfPath string
|
||||
|
||||
uKeyName string
|
||||
|
||||
uKeyPin string
|
||||
|
||||
svcConfPath string
|
||||
|
||||
columnNameCase int
|
||||
|
||||
caseSensitive bool
|
||||
|
||||
compatibleMode int
|
||||
|
||||
localTimezone int16
|
||||
|
||||
schema string
|
||||
|
||||
catalog string
|
||||
|
||||
logLevel int
|
||||
|
||||
logDir string
|
||||
|
||||
logFlushFreq int
|
||||
|
||||
logFlushQueueSize int
|
||||
|
||||
logBufferSize int
|
||||
|
||||
statEnable bool
|
||||
|
||||
statDir string
|
||||
|
||||
statFlushFreq int
|
||||
|
||||
statSlowSqlCount int
|
||||
|
||||
statHighFreqSqlCount int
|
||||
|
||||
statSqlMaxCount int
|
||||
|
||||
statSqlRemoveMode int
|
||||
|
||||
serverOption []string
|
||||
|
||||
clobToBytes bool
|
||||
}
|
||||
|
||||
func (c *DmConnector) init() *DmConnector {
|
||||
c.compress = compressDef
|
||||
c.compressID = compressIDDef
|
||||
c.charCode = charCodeDef
|
||||
c.enRsCache = enRsCacheDef
|
||||
c.rsCacheSize = rsCacheSizeDef
|
||||
c.rsRefreshFreq = rsRefreshFreqDef
|
||||
c.loginMode = loginModeDef
|
||||
c.loginStatus = loginStatusDef
|
||||
c.loginDscCtrl = false
|
||||
c.switchTimes = 1
|
||||
c.switchInterval = 200
|
||||
c.epSelector = 0
|
||||
c.keyWords = nil
|
||||
c.loginEncrypt = loginEncryptDef
|
||||
c.loginCertificate = loginCertificateDef
|
||||
c.dec2Double = dec2DoubleDef
|
||||
c.rwHA = rwHADef
|
||||
c.rwStandby = rwStandbyDef
|
||||
c.rwSeparate = rwSeparateDef
|
||||
c.rwPercent = rwPercentDef
|
||||
c.rwAutoDistribute = rwAutoDistributeDef
|
||||
c.rwStandbyRecoverTime = rwStandbyRecoverTimeDef
|
||||
c.rwIgnoreSql = false
|
||||
c.doSwitch = DO_SWITCH_WHEN_CONN_ERROR
|
||||
c.driverReconnect = false
|
||||
c.cluster = CLUSTER_TYPE_NORMAL
|
||||
c.cipherPath = cipherPathDef
|
||||
c.url = urlDef
|
||||
c.user = userDef
|
||||
c.password = passwordDef
|
||||
c.host = hostDef
|
||||
c.port = portDef
|
||||
c.appName = appNameDef
|
||||
c.osName = runtime.GOOS
|
||||
c.mppLocal = mppLocalDef
|
||||
c.socketTimeout = socketTimeoutDef
|
||||
c.connectTimeout = connectTimeoutDef
|
||||
c.sessionTimeout = sessionTimeoutDef
|
||||
c.osAuthType = osAuthTypeDef
|
||||
c.continueBatchOnError = continueBatchOnErrorDef
|
||||
c.batchAllowMaxErrors = 0
|
||||
c.escapeProcess = escapeProcessDef
|
||||
c.autoCommit = autoCommitDef
|
||||
c.maxRows = maxRowsDef
|
||||
c.rowPrefetch = rowPrefetchDef
|
||||
c.bufPrefetch = bufPrefetchDef
|
||||
c.lobMode = lobModeDef
|
||||
c.stmtPoolMaxSize = stmtPoolMaxSizeDef
|
||||
|
||||
c.alwayseAllowCommit = alwayseAllowCommitDef
|
||||
c.batchType = 1
|
||||
c.batchNotOnCall = false
|
||||
c.isBdtaRS = isBdtaRSDef
|
||||
c.kerberosLoginConfPath = kerberosLoginConfPathDef
|
||||
c.uKeyName = uKeyNameDef
|
||||
c.uKeyPin = uKeyPinDef
|
||||
c.columnNameCase = COLUMN_NAME_NATURAL_CASE
|
||||
c.caseSensitive = caseSensitiveDef
|
||||
c.compatibleMode = compatibleModeDef
|
||||
_, tzs := time.Now().Zone()
|
||||
c.localTimezone = int16(tzs / 60)
|
||||
c.idGenerator = dmConntorIDGenerator
|
||||
|
||||
c.logDir = LogDirDef
|
||||
c.logFlushFreq = LogFlushFreqDef
|
||||
c.logFlushQueueSize = LogFlushQueueSizeDef
|
||||
c.logBufferSize = LogBufferSizeDef
|
||||
c.statEnable = StatEnableDef
|
||||
c.statDir = StatDirDef
|
||||
c.statFlushFreq = StatFlushFreqDef
|
||||
c.statSlowSqlCount = StatSlowSqlCountDef
|
||||
c.statHighFreqSqlCount = StatHighFreqSqlCountDef
|
||||
c.statSqlMaxCount = StatSqlMaxCountDef
|
||||
c.statSqlRemoveMode = StatSqlRemoveModeDef
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *DmConnector) setAttributes(props *Properties) error {
|
||||
if props == nil || props.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.url = props.GetTrimString(UrlKey, c.url)
|
||||
c.host = props.GetTrimString(HostKey, c.host)
|
||||
c.port = int32(props.GetInt(PortKey, int(c.port), 0, 65535))
|
||||
c.user = props.GetString(UserKey, c.user)
|
||||
c.password = props.GetString(PasswordKey, c.password)
|
||||
c.dialName = props.GetString(DialNameKey, "")
|
||||
c.rwStandby = props.GetBool(RwStandbyKey, c.rwStandby)
|
||||
|
||||
if b := props.GetBool(IsCompressKey, false); b {
|
||||
c.compress = Dm_build_783
|
||||
}
|
||||
|
||||
c.compress = props.GetInt(CompressKey, c.compress, 0, 2)
|
||||
c.compressID = int8(props.GetInt(CompressIdKey, int(c.compressID), 0, 1))
|
||||
c.enRsCache = props.GetBool(EnRsCacheKey, c.enRsCache)
|
||||
c.localTimezone = int16(props.GetInt(TimeZoneKey, int(c.localTimezone), -779, 840))
|
||||
c.rsCacheSize = props.GetInt(RsCacheSizeKey, c.rsCacheSize, 0, int(INT32_MAX))
|
||||
c.rsRefreshFreq = props.GetInt(RsRefreshFreqKey, c.rsRefreshFreq, 0, int(INT32_MAX))
|
||||
c.loginMode = int32(props.GetInt(LoginModeKey, int(c.loginMode), 0, 4))
|
||||
c.loginStatus = props.GetInt(LoginStatusKey, c.loginStatus, 0, int(INT32_MAX))
|
||||
c.loginDscCtrl = props.GetBool(LoginDscCtrlKey, c.loginDscCtrl)
|
||||
c.switchTimes = int32(props.GetInt(SwitchTimesKey, int(c.switchTimes), 0, int(INT32_MAX)))
|
||||
c.switchInterval = props.GetInt(SwitchIntervalKey, c.switchInterval, 0, int(INT32_MAX))
|
||||
c.epSelector = int32(props.GetInt(EpSelectorKey, int(c.epSelector), 0, 1))
|
||||
c.loginEncrypt = props.GetBool(LoginEncryptKey, c.loginEncrypt)
|
||||
c.loginCertificate = props.GetTrimString(LoginCertificateKey, c.loginCertificate)
|
||||
c.dec2Double = props.GetBool(Dec2DoubleKey, c.dec2Double)
|
||||
parseLanguage(props.GetString(LanguageKey, ""))
|
||||
|
||||
c.rwSeparate = int32(props.GetInt(RwSeparateKey, int(c.rwSeparate), 0, 4))
|
||||
c.rwAutoDistribute = props.GetBool(RwAutoDistributeKey, c.rwAutoDistribute)
|
||||
c.rwPercent = int32(props.GetInt(RwPercentKey, int(c.rwPercent), 0, 100))
|
||||
c.rwHA = props.GetBool(RwHAKey, c.rwHA)
|
||||
c.rwStandbyRecoverTime = props.GetInt(RwStandbyRecoverTimeKey, c.rwStandbyRecoverTime, 0, int(INT32_MAX))
|
||||
c.rwIgnoreSql = props.GetBool(RwIgnoreSqlKey, c.rwIgnoreSql)
|
||||
c.doSwitch = int32(props.GetInt(DoSwitchKey, int(c.doSwitch), 0, 2))
|
||||
c.driverReconnect = props.GetBool(DriverReconnectKey, c.driverReconnect)
|
||||
c.parseCluster(props)
|
||||
c.cipherPath = props.GetTrimString(CipherPathKey, c.cipherPath)
|
||||
|
||||
if props.GetBool(CompatibleOraKey, false) {
|
||||
c.compatibleMode = int(COMPATIBLE_MODE_ORACLE)
|
||||
}
|
||||
c.parseCompatibleMode(props)
|
||||
c.keyWords = props.GetStringArray(KeywordsKey, c.keyWords)
|
||||
|
||||
c.appName = props.GetTrimString(AppNameKey, c.appName)
|
||||
c.osName = props.GetTrimString(OsNameKey, c.osName)
|
||||
c.mppLocal = props.GetBool(MppLocalKey, c.mppLocal)
|
||||
c.socketTimeout = props.GetInt(SocketTimeoutKey, c.socketTimeout, 0, int(INT32_MAX))
|
||||
c.connectTimeout = props.GetInt(ConnectTimeoutKey, c.connectTimeout, 0, int(INT32_MAX))
|
||||
c.sessionTimeout = props.GetInt(SessionTimeoutKey, c.sessionTimeout, 0, int(INT32_MAX))
|
||||
|
||||
err := c.parseOsAuthType(props)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.continueBatchOnError = props.GetBool(ContinueBatchOnErrorKey, c.continueBatchOnError)
|
||||
c.batchAllowMaxErrors = int32(props.GetInt(BatchAllowMaxErrorsKey, int(c.batchAllowMaxErrors), 0, int(INT32_MAX)))
|
||||
c.escapeProcess = props.GetBool(EscapeProcessKey, c.escapeProcess)
|
||||
c.autoCommit = props.GetBool(AutoCommitKey, c.autoCommit)
|
||||
c.maxRows = props.GetInt(MaxRowsKey, c.maxRows, 0, int(INT32_MAX))
|
||||
c.rowPrefetch = props.GetInt(RowPrefetchKey, c.rowPrefetch, 0, int(INT32_MAX))
|
||||
c.bufPrefetch = props.GetInt(BufPrefetchKey, c.bufPrefetch, int(Dm_build_769), int(Dm_build_770))
|
||||
c.lobMode = props.GetInt(LobModeKey, c.lobMode, 1, 2)
|
||||
c.stmtPoolMaxSize = props.GetInt(StmtPoolSizeKey, c.stmtPoolMaxSize, 0, int(INT32_MAX))
|
||||
|
||||
c.alwayseAllowCommit = props.GetBool(AlwayseAllowCommitKey, c.alwayseAllowCommit)
|
||||
c.batchType = props.GetInt(BatchTypeKey, c.batchType, 1, 2)
|
||||
c.batchNotOnCall = props.GetBool(BatchNotOnCallKey, c.batchNotOnCall)
|
||||
c.isBdtaRS = props.GetBool(IsBdtaRSKey, c.isBdtaRS)
|
||||
c.sslFilesPath = props.GetTrimString(SslFilesPathKey, c.sslFilesPath)
|
||||
c.sslCertPath = props.GetTrimString(SslCertPathKey, c.sslCertPath)
|
||||
if c.sslCertPath == "" && c.sslFilesPath != "" {
|
||||
c.sslCertPath = filepath.Join(c.sslFilesPath, "client-cert.pem")
|
||||
}
|
||||
c.sslKeyPath = props.GetTrimString(SslKeyPathKey, c.sslKeyPath)
|
||||
if c.sslKeyPath == "" && c.sslFilesPath != "" {
|
||||
c.sslKeyPath = filepath.Join(c.sslKeyPath, "client-key.pem")
|
||||
}
|
||||
|
||||
c.kerberosLoginConfPath = props.GetTrimString(KerberosLoginConfPathKey, c.kerberosLoginConfPath)
|
||||
|
||||
c.uKeyName = props.GetTrimString(UKeyNameKey, c.uKeyName)
|
||||
c.uKeyPin = props.GetTrimString(UKeyPinKey, c.uKeyPin)
|
||||
|
||||
c.svcConfPath = props.GetString("confPath", "")
|
||||
|
||||
if props.GetBool(ColumnNameUpperCaseKey, false) {
|
||||
c.columnNameCase = COLUMN_NAME_UPPER_CASE
|
||||
}
|
||||
|
||||
v := props.GetTrimString(ColumnNameCaseKey, "")
|
||||
if util.StringUtil.EqualsIgnoreCase(v, "upper") {
|
||||
c.columnNameCase = COLUMN_NAME_UPPER_CASE
|
||||
} else if util.StringUtil.EqualsIgnoreCase(v, "lower") {
|
||||
c.columnNameCase = COLUMN_NAME_LOWER_CASE
|
||||
}
|
||||
|
||||
c.schema = props.GetTrimString(SchemaKey, c.schema)
|
||||
c.catalog = props.GetTrimString(CatalogKey, c.catalog)
|
||||
|
||||
c.logLevel = ParseLogLevel(props)
|
||||
LogLevel = c.logLevel
|
||||
c.logDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef))
|
||||
LogDir = c.logDir
|
||||
c.logBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX))
|
||||
LogBufferSize = c.logBufferSize
|
||||
c.logFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX))
|
||||
LogFlushFreq = c.logFlushFreq
|
||||
c.logFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX))
|
||||
LogFlushQueueSize = c.logFlushQueueSize
|
||||
|
||||
c.statEnable = props.GetBool(StatEnableKey, StatEnableDef)
|
||||
StatEnable = c.statEnable
|
||||
c.statDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef))
|
||||
StatDir = c.statDir
|
||||
c.statFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX))
|
||||
StatFlushFreq = c.statFlushFreq
|
||||
c.statHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000)
|
||||
StatHighFreqSqlCount = c.statHighFreqSqlCount
|
||||
c.statSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000)
|
||||
StatSlowSqlCount = c.statSlowSqlCount
|
||||
c.statSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000)
|
||||
StatSqlMaxCount = c.statSqlMaxCount
|
||||
c.parseStatSqlRemoveMode(props)
|
||||
|
||||
c.parseServerOption(props)
|
||||
c.clobToBytes = props.GetBool(ClobToBytesKey, ClobToBytesDef)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DmConnector) parseServerOption(props *Properties) {
|
||||
value := props.GetString(ServerOptionKey, "")
|
||||
if len(value) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(value, "{") && strings.HasSuffix(value, "}") {
|
||||
|
||||
value = strings.TrimPrefix(value, "{")
|
||||
value = strings.TrimSuffix(value, "}")
|
||||
}
|
||||
|
||||
c.serverOption = strings.Split(value, ",")
|
||||
}
|
||||
|
||||
func (c *DmConnector) parseOsAuthType(props *Properties) error {
|
||||
value := props.GetString(OsAuthTypeKey, "")
|
||||
if value != "" && !util.StringUtil.IsDigit(value) {
|
||||
if util.StringUtil.EqualsIgnoreCase(value, "ON") {
|
||||
c.osAuthType = Dm_build_767
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "SYSDBA") {
|
||||
c.osAuthType = Dm_build_763
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "SYSAUDITOR") {
|
||||
c.osAuthType = Dm_build_765
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "SYSSSO") {
|
||||
c.osAuthType = Dm_build_764
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "AUTO") {
|
||||
c.osAuthType = Dm_build_766
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "OFF") {
|
||||
c.osAuthType = Dm_build_762
|
||||
}
|
||||
} else {
|
||||
c.osAuthType = byte(props.GetInt(OsAuthTypeKey, int(c.osAuthType), 0, 4))
|
||||
}
|
||||
if c.user == "" && c.osAuthType == Dm_build_762 {
|
||||
c.user = "SYSDBA"
|
||||
} else if c.osAuthType != Dm_build_762 && c.user != "" {
|
||||
return ECGO_OSAUTH_ERROR.throw()
|
||||
} else if c.osAuthType != Dm_build_762 {
|
||||
c.user = os.Getenv("user")
|
||||
c.password = ""
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DmConnector) parseCompatibleMode(props *Properties) {
|
||||
value := props.GetString(CompatibleModeKey, "")
|
||||
if value != "" && !util.StringUtil.IsDigit(value) {
|
||||
if util.StringUtil.EqualsIgnoreCase(value, "oracle") {
|
||||
c.compatibleMode = COMPATIBLE_MODE_ORACLE
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "mysql") {
|
||||
c.compatibleMode = COMPATIBLE_MODE_MYSQL
|
||||
}
|
||||
} else {
|
||||
c.compatibleMode = props.GetInt(CompatibleModeKey, c.compatibleMode, 0, 2)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DmConnector) parseStatSqlRemoveMode(props *Properties) {
|
||||
value := props.GetString(StatSqlRemoveModeKey, "")
|
||||
if value != "" && !util.StringUtil.IsDigit(value) {
|
||||
if util.StringUtil.EqualsIgnoreCase("oldest", value) || util.StringUtil.EqualsIgnoreCase("eldest", value) {
|
||||
c.statSqlRemoveMode = STAT_SQL_REMOVE_OLDEST
|
||||
} else if util.StringUtil.EqualsIgnoreCase("latest", value) {
|
||||
c.statSqlRemoveMode = STAT_SQL_REMOVE_LATEST
|
||||
}
|
||||
} else {
|
||||
c.statSqlRemoveMode = props.GetInt(StatSqlRemoveModeKey, StatSqlRemoveModeDef, 1, 2)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DmConnector) parseCluster(props *Properties) {
|
||||
value := props.GetTrimString(ClusterKey, "")
|
||||
if util.StringUtil.EqualsIgnoreCase(value, "DSC") {
|
||||
c.cluster = CLUSTER_TYPE_DSC
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "RW") {
|
||||
c.cluster = CLUSTER_TYPE_RW
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "DW") {
|
||||
c.cluster = CLUSTER_TYPE_DW
|
||||
} else if util.StringUtil.EqualsIgnoreCase(value, "MPP") {
|
||||
c.cluster = CLUSTER_TYPE_MPP
|
||||
} else {
|
||||
c.cluster = CLUSTER_TYPE_NORMAL
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DmConnector) parseDSN(dsn string) (*Properties, string, string, error) {
|
||||
var dsnProps = NewProperties()
|
||||
|
||||
if strings.Index(dsn, "dm://") != 0 {
|
||||
return nil, "", "", DSN_INVALID_SCHEMA
|
||||
}
|
||||
dsn = dsn[5:]
|
||||
|
||||
urlString := dsn
|
||||
queryIndex := strings.LastIndex(dsn, "?")
|
||||
if queryIndex > 0 {
|
||||
urlString = dsn[:queryIndex]
|
||||
var queryString = dsn[queryIndex+1:]
|
||||
|
||||
for _, kvString := range strings.Split(queryString, "&") {
|
||||
kv := strings.SplitN(kvString, "=", 2)
|
||||
if kv != nil && len(kv) > 1 {
|
||||
dsnProps.Set(kv[0], kv[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hostString := urlString
|
||||
atIndex := strings.LastIndex(urlString, "@")
|
||||
if atIndex == -1 {
|
||||
return nil, "", "", DSN_INVALID_FORMAT
|
||||
} else {
|
||||
var userString = urlString[:atIndex]
|
||||
hostString = urlString[atIndex+1:]
|
||||
kv := strings.SplitN(userString, ":", 2)
|
||||
if kv != nil && len(kv) > 1 {
|
||||
c.user = kv[0]
|
||||
c.password = kv[1]
|
||||
}
|
||||
}
|
||||
if catalogIndex := strings.LastIndex(hostString, "/"); catalogIndex > 0 {
|
||||
return dsnProps, hostString[0:catalogIndex], hostString[catalogIndex+1:], nil
|
||||
}
|
||||
return dsnProps, hostString, "", nil
|
||||
|
||||
}
|
||||
|
||||
func (c *DmConnector) BuildDSN() string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
buf.WriteString("dm://")
|
||||
|
||||
if len(c.user) > 0 {
|
||||
buf.WriteString(url.QueryEscape(c.user))
|
||||
if len(c.password) > 0 {
|
||||
buf.WriteByte(':')
|
||||
buf.WriteString(url.QueryEscape(c.password))
|
||||
}
|
||||
buf.WriteByte('@')
|
||||
}
|
||||
|
||||
if len(c.host) > 0 {
|
||||
buf.WriteString(c.host)
|
||||
if c.port > 0 {
|
||||
buf.WriteByte(':')
|
||||
buf.WriteString(strconv.Itoa(int(c.port)))
|
||||
}
|
||||
}
|
||||
|
||||
hasParam := false
|
||||
if c.connectTimeout > 0 {
|
||||
if hasParam {
|
||||
buf.WriteString("&timeout=")
|
||||
} else {
|
||||
buf.WriteString("?timeout=")
|
||||
hasParam = true
|
||||
}
|
||||
buf.WriteString(strconv.Itoa(c.connectTimeout))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (c *DmConnector) mergeConfigs(dsn string) error {
|
||||
props, host, catalog, err := c.parseDSN(dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
driverInit(props.GetString("svcConfPath", ""))
|
||||
|
||||
addressRemapStr := props.GetTrimString(AddressRemapKey, "")
|
||||
userRemapStr := props.GetTrimString(UserRemapKey, "")
|
||||
if addressRemapStr == "" {
|
||||
addressRemapStr = GlobalProperties.GetTrimString(AddressRemapKey, "")
|
||||
}
|
||||
if userRemapStr == "" {
|
||||
userRemapStr = GlobalProperties.GetTrimString(UserRemapKey, "")
|
||||
}
|
||||
|
||||
host = c.remap(host, addressRemapStr)
|
||||
|
||||
c.user = c.remap(c.user, userRemapStr)
|
||||
|
||||
if a := props.GetTrimString(host, ""); a != "" {
|
||||
|
||||
if strings.HasPrefix(a, "(") && strings.HasSuffix(a, ")") {
|
||||
a = strings.TrimSpace(a[1 : len(a)-1])
|
||||
}
|
||||
c.group = parseServerName(host, a)
|
||||
if c.group != nil {
|
||||
c.group.props = NewProperties()
|
||||
c.group.props.SetProperties(GlobalProperties)
|
||||
}
|
||||
} else if group, ok := ServerGroupMap.Load(strings.ToLower(host)); ok {
|
||||
|
||||
c.group = group.(*epGroup)
|
||||
} else {
|
||||
host, port, err := net.SplitHostPort(host)
|
||||
if err == nil {
|
||||
ip := net.ParseIP(host)
|
||||
var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
|
||||
if ip != nil && len(ip) == net.IPv6len && !bytes.Equal(ip[0:12], v4InV6Prefix) {
|
||||
|
||||
host = "[" + host + "]"
|
||||
}
|
||||
}
|
||||
|
||||
c.host = host
|
||||
|
||||
tmpPort, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
c.port = portDef
|
||||
} else {
|
||||
c.port = int32(tmpPort)
|
||||
}
|
||||
|
||||
if len(catalog) > 0 {
|
||||
c.schema = catalog
|
||||
}
|
||||
|
||||
c.group = newEPGroup(c.host+":"+strconv.Itoa(int(c.port)), []*ep{newEP(c.host, c.port)})
|
||||
}
|
||||
|
||||
props.SetDiffProperties(c.group.props)
|
||||
|
||||
props.SetDiffProperties(GlobalProperties)
|
||||
|
||||
if c.rwSeparate = int32(props.GetInt(RwSeparateKey, 0, 0, 5)); c.rwSeparate > RW_SEPARATE_OFF {
|
||||
props.SetIfNotExist(LoginModeKey, strconv.Itoa(int(LOGIN_MODE_PRIMARY_ONLY)))
|
||||
props.SetIfNotExist(LoginStatusKey, strconv.Itoa(int(SERVER_STATUS_OPEN)))
|
||||
|
||||
props.SetIfNotExist(DoSwitchKey, "true")
|
||||
|
||||
}
|
||||
|
||||
if err = c.setAttributes(props); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DmConnector) remap(origin string, cfgStr string) string {
|
||||
if cfgStr == "" || origin == "" {
|
||||
return origin
|
||||
}
|
||||
|
||||
maps := regexp.MustCompile("\\(.*?,.*?\\)").FindAllString(cfgStr, -1)
|
||||
for _, kvStr := range maps {
|
||||
kv := strings.Split(strings.TrimSpace(kvStr[1:len(kvStr)-1]), ",")
|
||||
if util.StringUtil.Equals(strings.TrimSpace(kv[0]), origin) {
|
||||
return strings.TrimSpace(kv[1])
|
||||
}
|
||||
}
|
||||
return origin
|
||||
}
|
||||
|
||||
func (c *DmConnector) Connect(ctx context.Context) (driver.Conn, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.filterChain.reset().DmConnectorConnect(c, ctx)
|
||||
}
|
||||
|
||||
func (c *DmConnector) Driver() driver.Driver {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.filterChain.reset().DmConnectorDriver(c)
|
||||
}
|
||||
|
||||
func (c *DmConnector) connect(ctx context.Context) (*DmConnection, error) {
|
||||
if c.group != nil && len(c.group.epList) > 0 {
|
||||
return c.group.connect(c)
|
||||
} else {
|
||||
return c.connectSingle(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DmConnector) driver() *DmDriver {
|
||||
return c.dmDriver
|
||||
}
|
||||
|
||||
func (c *DmConnector) connectSingle(ctx context.Context) (*DmConnection, error) {
|
||||
var err error
|
||||
var dc = &DmConnection{
|
||||
closech: make(chan struct{}),
|
||||
dmConnector: c,
|
||||
autoCommit: c.autoCommit,
|
||||
}
|
||||
|
||||
dc.createFilterChain(c, nil)
|
||||
dc.objId = -1
|
||||
dc.init()
|
||||
|
||||
dc.Access, err = dm_build_426(ctx, dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc.startWatcher()
|
||||
if err = dc.watchCancel(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dc.finish()
|
||||
|
||||
if err = dc.Access.dm_build_471(); err != nil {
|
||||
|
||||
if !dc.closed.IsSet() {
|
||||
close(dc.closech)
|
||||
if dc.Access != nil {
|
||||
dc.Access.Close()
|
||||
}
|
||||
dc.closed.Set(true)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.schema != "" {
|
||||
_, err = dc.exec("set schema \""+util.StringUtil.ProcessDoubleQuoteOfName(c.schema)+"\"", nil)
|
||||
if err != nil {
|
||||
|
||||
dc.cleanup()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return dc, nil
|
||||
}
|
||||
+456
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
XDEC_MAX_PREC int = 40
|
||||
XDEC_SIZE = 21
|
||||
|
||||
FLAG_ZERO int = 0x80
|
||||
FLAG_POSITIVE int = 0xC1
|
||||
FLAG_NEGTIVE int = 0x3E
|
||||
POSITIVE_EXP_MAX = 0xff - FLAG_POSITIVE
|
||||
EXP_MAX int = 0xFF - 1 - FLAG_POSITIVE
|
||||
EXP_MIN int = FLAG_NEGTIVE + 1 - 0x7F
|
||||
|
||||
NUM_POSITIVE int = 1
|
||||
NUM_NEGTIVE int = 101
|
||||
)
|
||||
|
||||
type DmDecimal struct {
|
||||
sign int
|
||||
weight int
|
||||
prec int
|
||||
scale int
|
||||
digits string
|
||||
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func NewDecimalFromInt64(x int64) (*DmDecimal, error) {
|
||||
return NewDecimalFromBigInt(big.NewInt(x))
|
||||
}
|
||||
|
||||
func (d DmDecimal) ToInt64() int64 {
|
||||
return d.ToBigInt().Int64()
|
||||
}
|
||||
|
||||
func NewDecimalFromFloat64(x float64) (*DmDecimal, error) {
|
||||
return NewDecimalFromBigFloat(big.NewFloat(x))
|
||||
}
|
||||
|
||||
func (d DmDecimal) ToFloat64() float64 {
|
||||
f, _ := d.ToBigFloat().Float64()
|
||||
return f
|
||||
}
|
||||
|
||||
func NewDecimalFromBigInt(bigInt *big.Int) (*DmDecimal, error) {
|
||||
return newDecimal(bigInt, len(bigInt.String()), 0)
|
||||
}
|
||||
|
||||
func (d DmDecimal) ToBigInt() *big.Int {
|
||||
if d.isZero() {
|
||||
return big.NewInt(0)
|
||||
}
|
||||
var digits = d.digits
|
||||
if d.sign < 0 {
|
||||
digits = "-" + digits
|
||||
}
|
||||
i1, ok := new(big.Int).SetString(digits, 10)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if d.weight > 0 {
|
||||
i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", d.weight), 10)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
i1.Mul(i1, i2)
|
||||
} else if d.weight < 0 {
|
||||
i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", -d.weight), 10)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
i1.Quo(i1, i2)
|
||||
}
|
||||
return i1
|
||||
}
|
||||
|
||||
func NewDecimalFromBigFloat(bigFloat *big.Float) (*DmDecimal, error) {
|
||||
return newDecimal(bigFloat, int(bigFloat.Prec()), int(bigFloat.Prec()))
|
||||
}
|
||||
|
||||
func (d DmDecimal) ToBigFloat() *big.Float {
|
||||
if d.isZero() {
|
||||
return big.NewFloat(0.0)
|
||||
}
|
||||
var digits = d.digits
|
||||
if d.sign < 0 {
|
||||
digits = "-" + digits
|
||||
}
|
||||
f1, ok := new(big.Float).SetString(digits)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if d.weight > 0 {
|
||||
f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", d.weight))
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
f1.Mul(f1, f2)
|
||||
} else if d.weight < 0 {
|
||||
f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", -d.weight))
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
f1.Quo(f1, f2)
|
||||
}
|
||||
return f1
|
||||
}
|
||||
|
||||
func NewDecimalFromString(s string) (*DmDecimal, error) {
|
||||
num, ok := new(big.Float).SetString(strings.TrimSpace(s))
|
||||
if !ok {
|
||||
return nil, ECGO_DATA_CONVERTION_ERROR.throw()
|
||||
}
|
||||
return NewDecimalFromBigFloat(num)
|
||||
}
|
||||
|
||||
func (d DmDecimal) String() string {
|
||||
|
||||
if d.isZero() {
|
||||
return "0"
|
||||
}
|
||||
digitsStr := d.digits
|
||||
if d.weight > 0 {
|
||||
digitsStr = digitsStr + strings.Repeat("0", d.weight)
|
||||
} else if d.weight < 0 {
|
||||
if len(digitsStr) < -d.weight {
|
||||
digitsStr = strings.Repeat("0", -d.weight-len(digitsStr)+1) + digitsStr
|
||||
}
|
||||
indexOfDot := len(digitsStr) + d.weight
|
||||
digitsStr = digitsStr[:indexOfDot] + "." + digitsStr[indexOfDot:]
|
||||
}
|
||||
|
||||
if digitsStr[0] == '0' && digitsStr[1] != '.' {
|
||||
digitsStr = digitsStr[1:]
|
||||
}
|
||||
|
||||
if digitsStr[len(digitsStr)-1] == '0' && strings.IndexRune(digitsStr, '.') >= 0 {
|
||||
digitsStr = digitsStr[0 : len(digitsStr)-1]
|
||||
}
|
||||
|
||||
if d.sign < 0 {
|
||||
digitsStr = "-" + digitsStr
|
||||
}
|
||||
|
||||
return digitsStr
|
||||
}
|
||||
|
||||
func (d DmDecimal) Sign() int {
|
||||
return d.sign
|
||||
}
|
||||
|
||||
func (dest *DmDecimal) Scan(src interface{}) error {
|
||||
if dest == nil {
|
||||
return ECGO_STORE_IN_NIL_POINTER.throw()
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmDecimal)
|
||||
|
||||
(*dest).Valid = false
|
||||
return nil
|
||||
case int, int8, int16, int32, int64:
|
||||
d, err := NewDecimalFromInt64(reflect.ValueOf(src).Int())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = *d
|
||||
return nil
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
d, err := NewDecimalFromBigInt(new(big.Int).SetUint64(reflect.ValueOf(src).Uint()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = *d
|
||||
return nil
|
||||
case float32, float64:
|
||||
d, err := NewDecimalFromFloat64(reflect.ValueOf(src).Float())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = *d
|
||||
return nil
|
||||
case string:
|
||||
d, err := NewDecimalFromString(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = *d
|
||||
return nil
|
||||
case *DmDecimal:
|
||||
*dest = *src
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN
|
||||
}
|
||||
}
|
||||
|
||||
func (d DmDecimal) Value() (driver.Value, error) {
|
||||
if !d.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func newDecimal(dec interface{}, prec int, scale int) (*DmDecimal, error) {
|
||||
d := &DmDecimal{
|
||||
prec: prec,
|
||||
scale: scale,
|
||||
Valid: true,
|
||||
}
|
||||
if isFloat(DECIMAL, scale) {
|
||||
d.prec = getFloatPrec(prec)
|
||||
d.scale = -1
|
||||
}
|
||||
switch de := dec.(type) {
|
||||
case *big.Int:
|
||||
d.sign = de.Sign()
|
||||
|
||||
if d.isZero() {
|
||||
return d, nil
|
||||
}
|
||||
str := de.String()
|
||||
|
||||
if d.sign < 0 {
|
||||
str = str[1:]
|
||||
}
|
||||
|
||||
if err := checkPrec(len(str), prec); err != nil {
|
||||
return d, err
|
||||
}
|
||||
i := 0
|
||||
istart := len(str) - 1
|
||||
|
||||
for i = istart; i > 0; i-- {
|
||||
if str[i] != '0' {
|
||||
break
|
||||
}
|
||||
}
|
||||
str = str[:i+1]
|
||||
d.weight += istart - i
|
||||
|
||||
if isOdd(d.weight) {
|
||||
str += "0"
|
||||
d.weight -= 1
|
||||
}
|
||||
if isOdd(len(str)) {
|
||||
str = "0" + str
|
||||
}
|
||||
d.digits = str
|
||||
case *big.Float:
|
||||
d.sign = de.Sign()
|
||||
|
||||
if d.isZero() {
|
||||
return d, nil
|
||||
}
|
||||
str := de.Text('f', -1)
|
||||
|
||||
if d.sign < 0 {
|
||||
str = str[1:]
|
||||
}
|
||||
|
||||
pointIndex := strings.IndexByte(str, '.')
|
||||
i, istart, length := 0, 0, len(str)
|
||||
|
||||
if pointIndex != -1 {
|
||||
if str[0] == '0' {
|
||||
|
||||
istart = 2
|
||||
for i = istart; i < length; i++ {
|
||||
if str[i] != '0' {
|
||||
break
|
||||
}
|
||||
}
|
||||
str = str[i:]
|
||||
d.weight -= i - istart + len(str)
|
||||
} else {
|
||||
str = str[:pointIndex] + str[pointIndex+1:]
|
||||
d.weight -= length - pointIndex - 1
|
||||
}
|
||||
}
|
||||
|
||||
length = len(str)
|
||||
istart = length - 1
|
||||
for i = istart; i > 0; i-- {
|
||||
if str[i] != '0' {
|
||||
break
|
||||
}
|
||||
}
|
||||
str = str[:i+1] + str[length:]
|
||||
d.weight += istart - i
|
||||
|
||||
if isOdd(d.weight) {
|
||||
str += "0"
|
||||
d.weight -= 1
|
||||
}
|
||||
if isOdd(len(str)) {
|
||||
str = "0" + str
|
||||
}
|
||||
d.digits = str
|
||||
case []byte:
|
||||
return decodeDecimal(de, prec, scale)
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d DmDecimal) encodeDecimal() ([]byte, error) {
|
||||
if d.isZero() {
|
||||
return []byte{byte(FLAG_ZERO)}, nil
|
||||
}
|
||||
exp := (d.weight+len(d.digits))/2 - 1
|
||||
|
||||
var realExpMax int
|
||||
|
||||
if d.sign == NUM_POSITIVE {
|
||||
realExpMax = POSITIVE_EXP_MAX
|
||||
} else {
|
||||
realExpMax = EXP_MAX
|
||||
}
|
||||
if exp > realExpMax || exp < EXP_MIN {
|
||||
return nil, ECGO_DATA_TOO_LONG.throw()
|
||||
}
|
||||
validLen := len(d.digits)/2 + 1
|
||||
|
||||
if d.sign < 0 && validLen >= XDEC_SIZE {
|
||||
validLen = XDEC_SIZE - 1
|
||||
} else if validLen > XDEC_SIZE {
|
||||
validLen = XDEC_SIZE
|
||||
}
|
||||
retLen := validLen
|
||||
if d.sign < 0 {
|
||||
retLen = validLen + 1
|
||||
}
|
||||
retBytes := make([]byte, retLen)
|
||||
if d.sign > 0 {
|
||||
retBytes[0] = byte(exp + FLAG_POSITIVE)
|
||||
} else {
|
||||
retBytes[0] = byte(FLAG_NEGTIVE - exp)
|
||||
}
|
||||
|
||||
ibytes := 1
|
||||
for ichar := 0; ibytes < validLen; {
|
||||
digit1, err := strconv.Atoi(string(d.digits[ichar]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ichar++
|
||||
digit2, err := strconv.Atoi(string(d.digits[ichar]))
|
||||
ichar++
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
digit := digit1*10 + digit2
|
||||
if d.sign > 0 {
|
||||
retBytes[ibytes] = byte(digit + NUM_POSITIVE)
|
||||
} else {
|
||||
retBytes[ibytes] = byte(NUM_NEGTIVE - digit)
|
||||
}
|
||||
ibytes++
|
||||
}
|
||||
if d.sign < 0 && ibytes < retLen {
|
||||
retBytes[ibytes] = 0x66
|
||||
ibytes++
|
||||
}
|
||||
if ibytes < retLen {
|
||||
retBytes[ibytes] = 0x00
|
||||
}
|
||||
return retBytes, nil
|
||||
}
|
||||
|
||||
func decodeDecimal(values []byte, prec int, scale int) (*DmDecimal, error) {
|
||||
var decimal = &DmDecimal{
|
||||
prec: prec,
|
||||
scale: scale,
|
||||
sign: 0,
|
||||
weight: 0,
|
||||
Valid: true,
|
||||
}
|
||||
if values == nil || len(values) == 0 || len(values) > XDEC_SIZE {
|
||||
return nil, ECGO_FATAL_ERROR.throw()
|
||||
}
|
||||
if values[0] == byte(FLAG_ZERO) || len(values) == 1 {
|
||||
return decimal, nil
|
||||
}
|
||||
if values[0]&byte(FLAG_ZERO) != 0 {
|
||||
decimal.sign = 1
|
||||
} else {
|
||||
decimal.sign = -1
|
||||
}
|
||||
|
||||
var flag = int(Dm_build_1346.Dm_build_1466(values, 0))
|
||||
var exp int
|
||||
if decimal.sign > 0 {
|
||||
exp = flag - FLAG_POSITIVE
|
||||
} else {
|
||||
exp = FLAG_NEGTIVE - flag
|
||||
}
|
||||
var digit = 0
|
||||
var sf = ""
|
||||
for ival := 1; ival < len(values); ival++ {
|
||||
if decimal.sign > 0 {
|
||||
digit = int(values[ival]) - NUM_POSITIVE
|
||||
} else {
|
||||
digit = NUM_NEGTIVE - int(values[ival])
|
||||
}
|
||||
if digit < 0 || digit > 99 {
|
||||
break
|
||||
}
|
||||
if digit < 10 {
|
||||
sf += "0"
|
||||
}
|
||||
sf += strconv.Itoa(digit)
|
||||
}
|
||||
decimal.digits = sf
|
||||
decimal.weight = exp*2 - (len(decimal.digits) - 2)
|
||||
|
||||
return decimal, nil
|
||||
}
|
||||
|
||||
func (d DmDecimal) isZero() bool {
|
||||
return d.sign == 0
|
||||
}
|
||||
|
||||
func checkPrec(len int, prec int) error {
|
||||
if prec > 0 && len > prec || len > XDEC_MAX_PREC {
|
||||
return ECGO_DATA_TOO_LONG.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isOdd(val int) bool {
|
||||
return val%2 != 0
|
||||
}
|
||||
|
||||
func (d *DmDecimal) checkValid() error {
|
||||
if !d.Valid {
|
||||
return ECGO_IS_NULL.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DmDecimal) GormDataType() string {
|
||||
return "DECIMAL"
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"gitee.com/chunanyong/dm/i18n"
|
||||
)
|
||||
|
||||
// 发版标记
|
||||
var version = "8.1.4.170"
|
||||
var build_date = "2025.11.21"
|
||||
var svn = "43114"
|
||||
|
||||
var globalDmDriver = newDmDriver()
|
||||
|
||||
func init() {
|
||||
sql.Register("dm", globalDmDriver)
|
||||
|
||||
i18n.InitConfig(i18n.Messages_zh_CN)
|
||||
i18n.InitConfig(i18n.Messages_en_US)
|
||||
i18n.InitConfig(i18n.Messages_zh_HK)
|
||||
}
|
||||
|
||||
func driverInit(svcConfPath string) {
|
||||
load(svcConfPath)
|
||||
if GlobalProperties != nil && GlobalProperties.Len() > 0 {
|
||||
setDriverAttributes(GlobalProperties)
|
||||
}
|
||||
globalDmDriver.createFilterChain(nil, GlobalProperties)
|
||||
}
|
||||
|
||||
type DmDriver struct {
|
||||
filterable
|
||||
mu sync.Mutex
|
||||
//readPropMutex sync.Mutex
|
||||
}
|
||||
|
||||
func newDmDriver() *DmDriver {
|
||||
d := new(DmDriver)
|
||||
d.idGenerator = dmDriverIDGenerator
|
||||
return d
|
||||
}
|
||||
|
||||
// 支持自定义连接网络地址,返回标准net.Conn对象,相关数据库操作的消息包都将发送到该对象
|
||||
type DialFunc func(addr string) (net.Conn, error)
|
||||
|
||||
// 支持自定义连接网络地址,返回标准net.Conn对象,相关数据库操作的消息包都将发送到该对象
|
||||
type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error)
|
||||
|
||||
var (
|
||||
dialsLock sync.RWMutex
|
||||
dials map[string]DialContextFunc
|
||||
)
|
||||
|
||||
// 注册自定义连接方法
|
||||
func RegisterDial(dialName string, dial DialFunc) {
|
||||
RegisterDialContext(dialName, func(_ context.Context, addr string) (net.Conn, error) {
|
||||
return dial(addr)
|
||||
})
|
||||
}
|
||||
|
||||
// 注册自定义连接方法
|
||||
func RegisterDialContext(dialName string, dial DialContextFunc) {
|
||||
dialsLock.Lock()
|
||||
defer dialsLock.Unlock()
|
||||
if dials == nil {
|
||||
dials = make(map[string]DialContextFunc)
|
||||
}
|
||||
dials[dialName] = dial
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
** PUBLIC METHODS AND FUNCTIONS
|
||||
*************************************************************/
|
||||
func (d *DmDriver) Open(dsn string) (driver.Conn, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
return d.open(dsn)
|
||||
}
|
||||
|
||||
func (d *DmDriver) OpenConnector(dsn string) (driver.Connector, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
return d.openConnector(dsn)
|
||||
}
|
||||
|
||||
func (d *DmDriver) open(dsn string) (*DmConnection, error) {
|
||||
c, err := d.openConnector(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.connect(context.Background())
|
||||
}
|
||||
|
||||
func (d *DmDriver) openConnector(dsn string) (*DmConnector, error) {
|
||||
connector := new(DmConnector).init()
|
||||
connector.url = dsn
|
||||
connector.dmDriver = d
|
||||
//d.readPropMutex.Lock()
|
||||
err := connector.mergeConfigs(dsn)
|
||||
//d.readPropMutex.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
connector.createFilterChain(connector, nil)
|
||||
return connector, nil
|
||||
}
|
||||
|
||||
func GetDriverVersion() string {
|
||||
return version
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package parser
|
||||
|
||||
import "strconv"
|
||||
|
||||
const (
|
||||
MAX_DEC_LEN = 38
|
||||
)
|
||||
|
||||
const (
|
||||
NORMAL int = iota
|
||||
INT
|
||||
DOUBLE
|
||||
DECIMAL
|
||||
STRING
|
||||
HEX_INT
|
||||
WHITESPACE_OR_COMMENT
|
||||
NULL
|
||||
)
|
||||
|
||||
type LVal struct {
|
||||
Value string
|
||||
Tp int
|
||||
Position int
|
||||
}
|
||||
|
||||
func newLValNoParams() *LVal {
|
||||
return new(LVal).reset()
|
||||
}
|
||||
|
||||
func newLVal(value string, tp int) *LVal {
|
||||
return &LVal{Value: value, Tp: tp}
|
||||
}
|
||||
|
||||
func (l *LVal) reset() *LVal {
|
||||
l.Value = ""
|
||||
l.Tp = NORMAL
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *LVal) String() string {
|
||||
return strconv.Itoa(l.Tp) + ":" + l.Value
|
||||
}
|
||||
+1206
File diff suppressed because it is too large
Load Diff
+1455
File diff suppressed because it is too large
Load Diff
+494
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
const (
|
||||
QUA_Y = 0
|
||||
QUA_YM = 1
|
||||
QUA_MO = 2
|
||||
)
|
||||
|
||||
type DmIntervalYM struct {
|
||||
leadScale int
|
||||
isLeadScaleSet bool
|
||||
_type byte
|
||||
years int
|
||||
months int
|
||||
scaleForSvr int
|
||||
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func newDmIntervalYM() *DmIntervalYM {
|
||||
return &DmIntervalYM{
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
func NewDmIntervalYMByString(str string) (ym *DmIntervalYM, err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
err = ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
}()
|
||||
ym = newDmIntervalYM()
|
||||
ym.isLeadScaleSet = false
|
||||
if err = ym.parseIntervYMString(strings.TrimSpace(str)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ym, nil
|
||||
}
|
||||
|
||||
func newDmIntervalYMByBytes(bytes []byte) *DmIntervalYM {
|
||||
ym := newDmIntervalYM()
|
||||
|
||||
ym.scaleForSvr = int(Dm_build_1346.Dm_build_1448(bytes, 8))
|
||||
ym.leadScale = (ym.scaleForSvr >> 4) & 0x0000000F
|
||||
ym._type = bytes[9]
|
||||
switch ym._type {
|
||||
case QUA_Y:
|
||||
ym.years = int(Dm_build_1346.Dm_build_1448(bytes, 0))
|
||||
case QUA_YM:
|
||||
ym.years = int(Dm_build_1346.Dm_build_1448(bytes, 0))
|
||||
ym.months = int(Dm_build_1346.Dm_build_1448(bytes, 4))
|
||||
case QUA_MO:
|
||||
ym.months = int(Dm_build_1346.Dm_build_1448(bytes, 4))
|
||||
}
|
||||
return ym
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) GetYear() int {
|
||||
return ym.years
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) GetMonth() int {
|
||||
return ym.months
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) GetYMType() byte {
|
||||
return ym._type
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) String() string {
|
||||
if !ym.Valid {
|
||||
return ""
|
||||
}
|
||||
str := "INTERVAL "
|
||||
var year, month string
|
||||
var l int
|
||||
var destLen int
|
||||
|
||||
switch ym._type {
|
||||
case QUA_Y:
|
||||
year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)
|
||||
if ym.years < 0 {
|
||||
str += "-"
|
||||
}
|
||||
|
||||
if ym.leadScale > len(year) {
|
||||
l = len(year)
|
||||
destLen = ym.leadScale
|
||||
|
||||
for destLen > l {
|
||||
year = "0" + year
|
||||
destLen--
|
||||
}
|
||||
}
|
||||
|
||||
str += "'" + year + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")"
|
||||
case QUA_YM:
|
||||
year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)
|
||||
month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10)
|
||||
|
||||
if ym.years < 0 || ym.months < 0 {
|
||||
str += "-"
|
||||
}
|
||||
|
||||
if ym.leadScale > len(year) {
|
||||
l = len(year)
|
||||
destLen = ym.leadScale
|
||||
|
||||
for destLen > l {
|
||||
year = "0" + year
|
||||
destLen--
|
||||
}
|
||||
}
|
||||
|
||||
if len(month) < 2 {
|
||||
month = "0" + month
|
||||
}
|
||||
|
||||
str += "'" + year + "-" + month + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ") TO MONTH"
|
||||
case QUA_MO:
|
||||
|
||||
month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10)
|
||||
if ym.months < 0 {
|
||||
str += "-"
|
||||
}
|
||||
|
||||
if ym.leadScale > len(month) {
|
||||
l = len(month)
|
||||
destLen = ym.leadScale
|
||||
for destLen > l {
|
||||
month = "0" + month
|
||||
destLen--
|
||||
}
|
||||
}
|
||||
|
||||
str += "'" + month + "' MONTH(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")"
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (dest *DmIntervalYM) Scan(src interface{}) error {
|
||||
if dest == nil {
|
||||
return ECGO_STORE_IN_NIL_POINTER.throw()
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmIntervalYM)
|
||||
|
||||
(*dest).Valid = false
|
||||
return nil
|
||||
case *DmIntervalYM:
|
||||
*dest = *src
|
||||
return nil
|
||||
case string:
|
||||
ret, err := NewDmIntervalYMByString(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = *ret
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN
|
||||
}
|
||||
}
|
||||
|
||||
func (ym DmIntervalYM) Value() (driver.Value, error) {
|
||||
if !ym.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return ym, nil
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) parseIntervYMString(str string) error {
|
||||
str = strings.ToUpper(str)
|
||||
ret := strings.Split(str, " ")
|
||||
l := len(ret)
|
||||
if l < 3 || !util.StringUtil.EqualsIgnoreCase(ret[0], "INTERVAL") || !(strings.HasPrefix(ret[2], "YEAR") || strings.HasPrefix(ret[2], "MONTH")) {
|
||||
return ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
ym._type = QUA_YM
|
||||
yearId := strings.Index(str, "YEAR")
|
||||
monthId := strings.Index(str, "MONTH")
|
||||
toId := strings.Index(str, "TO")
|
||||
var err error
|
||||
if toId == -1 {
|
||||
if yearId != -1 && monthId == -1 {
|
||||
ym._type = QUA_Y
|
||||
ym.leadScale, err = ym.getLeadPrec(str, yearId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if monthId != -1 && yearId == -1 {
|
||||
ym._type = QUA_MO
|
||||
ym.leadScale, err = ym.getLeadPrec(str, monthId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
} else {
|
||||
if yearId == -1 || monthId == -1 {
|
||||
return ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
ym._type = QUA_YM
|
||||
ym.leadScale, err = ym.getLeadPrec(str, yearId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ym.scaleForSvr = (int(ym._type) << 8) + (ym.leadScale << 4)
|
||||
timeVals, err := ym.getTimeValue(ret[1], int(ym._type))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ym.years = timeVals[0]
|
||||
ym.months = timeVals[1]
|
||||
return ym.checkScale(ym.leadScale)
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) getLeadPrec(str string, startIndex int) (int, error) {
|
||||
if ym.isLeadScaleSet {
|
||||
return ym.leadScale, nil
|
||||
}
|
||||
|
||||
leftBtId := strings.Index(str[startIndex:], "(")
|
||||
rightBtId := strings.Index(str[startIndex:], ")")
|
||||
leadPrec := 0
|
||||
|
||||
if rightBtId == -1 && leftBtId == -1 {
|
||||
leftBtId += startIndex
|
||||
rightBtId += startIndex
|
||||
l := strings.Index(str, "'")
|
||||
var r int
|
||||
var dataStr string
|
||||
if l != -1 {
|
||||
r = strings.Index(str[l+1:], "'")
|
||||
if r != -1 {
|
||||
r += l + 1
|
||||
}
|
||||
} else {
|
||||
r = -1
|
||||
}
|
||||
|
||||
if r != -1 {
|
||||
dataStr = strings.TrimSpace(str[l+1 : r])
|
||||
} else {
|
||||
dataStr = ""
|
||||
}
|
||||
|
||||
if dataStr != "" {
|
||||
sign := dataStr[0]
|
||||
if sign == '+' || sign == '-' {
|
||||
dataStr = strings.TrimSpace(dataStr[1:])
|
||||
}
|
||||
end := strings.Index(dataStr, "-")
|
||||
|
||||
if end != -1 {
|
||||
dataStr = dataStr[:end]
|
||||
}
|
||||
|
||||
leadPrec = len(dataStr)
|
||||
} else {
|
||||
leadPrec = 2
|
||||
}
|
||||
} else if rightBtId != -1 && leftBtId != -1 && rightBtId > leftBtId+1 {
|
||||
leftBtId += startIndex
|
||||
rightBtId += startIndex
|
||||
strPrec := strings.TrimSpace(str[leftBtId+1 : rightBtId])
|
||||
temp, err := strconv.ParseInt(strPrec, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
leadPrec = int(temp)
|
||||
} else {
|
||||
return 0, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
|
||||
return leadPrec, nil
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) checkScale(prec int) error {
|
||||
switch ym._type {
|
||||
case QUA_Y:
|
||||
if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) {
|
||||
return ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
case QUA_YM:
|
||||
if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) {
|
||||
return ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
|
||||
if int64(math.Abs(float64(ym.months))) > 11 {
|
||||
return ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
|
||||
case QUA_MO:
|
||||
if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10)) {
|
||||
return ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) getTimeValue(subStr string, _type int) ([]int, error) {
|
||||
hasQuate := false
|
||||
if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' {
|
||||
hasQuate = true
|
||||
subStr = strings.TrimSpace(subStr[1 : len(subStr)-1])
|
||||
}
|
||||
|
||||
negative := false
|
||||
if strings.Index(subStr, "-") == 0 {
|
||||
negative = true
|
||||
subStr = subStr[1:]
|
||||
} else if strings.Index(subStr, "+") == 0 {
|
||||
negative = false
|
||||
subStr = subStr[1:]
|
||||
}
|
||||
|
||||
if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' {
|
||||
hasQuate = true
|
||||
subStr = strings.TrimSpace(subStr[1 : len(subStr)-1])
|
||||
}
|
||||
|
||||
if !hasQuate {
|
||||
return nil, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
|
||||
lastSignIndex := strings.LastIndex(subStr, "-")
|
||||
|
||||
list := make([]string, 2)
|
||||
if lastSignIndex == -1 || lastSignIndex == 0 {
|
||||
list[0] = subStr
|
||||
list[1] = ""
|
||||
} else {
|
||||
list[0] = subStr[0:lastSignIndex]
|
||||
list[1] = subStr[lastSignIndex+1:]
|
||||
}
|
||||
|
||||
var yearVal, monthVal int64
|
||||
var err error
|
||||
if ym._type == QUA_YM {
|
||||
yearVal, err = strconv.ParseInt(list[0], 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if util.StringUtil.EqualsIgnoreCase(list[1], "") {
|
||||
monthVal = 0
|
||||
} else {
|
||||
monthVal, err = strconv.ParseInt(list[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if negative {
|
||||
yearVal *= -1
|
||||
monthVal *= -1
|
||||
}
|
||||
|
||||
if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) {
|
||||
return nil, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
} else if ym._type == QUA_Y {
|
||||
yearVal, err = strconv.ParseInt(list[0], 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
monthVal = 0
|
||||
|
||||
if negative {
|
||||
yearVal *= -1
|
||||
}
|
||||
|
||||
if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) {
|
||||
return nil, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
} else {
|
||||
yearVal = 0
|
||||
monthVal, err = strconv.ParseInt(list[0], 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if negative {
|
||||
monthVal *= -1
|
||||
}
|
||||
|
||||
if monthVal > int64(math.Pow10(ym.leadScale))-1 || monthVal < 1-int64(math.Pow10(ym.leadScale)) {
|
||||
return nil, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
}
|
||||
|
||||
ret := make([]int, 2)
|
||||
ret[0] = int(yearVal)
|
||||
ret[1] = int(monthVal)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) encode(scale int) ([]byte, error) {
|
||||
if scale == 0 {
|
||||
scale = ym.scaleForSvr
|
||||
}
|
||||
year, month := ym.years, ym.months
|
||||
if err := ym.checkScale(ym.leadScale); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if scale != ym.scaleForSvr {
|
||||
convertYM, err := ym.convertTo(scale)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
year = convertYM.years
|
||||
month = convertYM.months
|
||||
} else {
|
||||
if err := ym.checkScale(ym.leadScale); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
bytes := make([]byte, 12)
|
||||
Dm_build_1346.Dm_build_1362(bytes, 0, int32(year))
|
||||
Dm_build_1346.Dm_build_1362(bytes, 4, int32(month))
|
||||
Dm_build_1346.Dm_build_1362(bytes, 8, int32(scale))
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) convertTo(scale int) (*DmIntervalYM, error) {
|
||||
destType := (scale & 0x0000FF00) >> 8
|
||||
leadPrec := (scale >> 4) & 0x0000000F
|
||||
totalMonths := ym.years*12 + ym.months
|
||||
year := 0
|
||||
month := 0
|
||||
switch destType {
|
||||
case QUA_Y:
|
||||
year = totalMonths / 12
|
||||
|
||||
if totalMonths%12 >= 6 {
|
||||
year++
|
||||
} else if totalMonths%12 <= -6 {
|
||||
year--
|
||||
}
|
||||
if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) {
|
||||
return nil, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
case QUA_YM:
|
||||
year = totalMonths / 12
|
||||
month = totalMonths % 12
|
||||
if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) {
|
||||
return nil, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
case QUA_MO:
|
||||
month = totalMonths
|
||||
if leadPrec < len(strconv.Itoa(int(math.Abs(float64(month))))) {
|
||||
return nil, ECGO_INVALID_TIME_INTERVAL.throw()
|
||||
}
|
||||
}
|
||||
return &DmIntervalYM{
|
||||
_type: byte(destType),
|
||||
years: year,
|
||||
months: month,
|
||||
scaleForSvr: scale,
|
||||
leadScale: (scale >> 4) & 0x0000000F,
|
||||
Valid: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ym *DmIntervalYM) checkValid() error {
|
||||
if !ym.Valid {
|
||||
return ECGO_IS_NULL.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DmIntervalYM) GormDataType() string {
|
||||
return "INTERVAL YEAR TO MONTH"
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import "strings"
|
||||
|
||||
type DmResult struct {
|
||||
filterable
|
||||
dmStmt *DmStatement
|
||||
affectedRows int64
|
||||
insertId int64
|
||||
}
|
||||
|
||||
func newDmResult(bs *DmStatement, execInfo *execRetInfo) *DmResult {
|
||||
result := DmResult{}
|
||||
result.resetFilterable(&bs.filterable)
|
||||
result.dmStmt = bs
|
||||
result.affectedRows = execInfo.updateCount
|
||||
|
||||
if execInfo.lastInsertId == 0 && execInfo.hasResultSet && strings.Index(execInfo.nativeSQL, "/*DMGORM-UPSERT*/") == 0 {
|
||||
if len(execInfo.rsDatas) > 0 && len(execInfo.rsDatas[0]) > 0 {
|
||||
result.insertId = Dm_build_1346.Dm_build_1576(execInfo.rsDatas[0][1])
|
||||
} else {
|
||||
result.insertId = 0
|
||||
}
|
||||
} else {
|
||||
result.insertId = execInfo.lastInsertId
|
||||
}
|
||||
result.idGenerator = dmResultIDGenerator
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func (r *DmResult) LastInsertId() (int64, error) {
|
||||
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.lastInsertId()
|
||||
}
|
||||
return r.filterChain.reset().DmResultLastInsertId(r)
|
||||
}
|
||||
|
||||
func (r *DmResult) RowsAffected() (int64, error) {
|
||||
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.rowsAffected()
|
||||
}
|
||||
return r.filterChain.reset().DmResultRowsAffected(r)
|
||||
}
|
||||
|
||||
func (result *DmResult) lastInsertId() (int64, error) {
|
||||
return result.insertId, nil
|
||||
}
|
||||
|
||||
func (result *DmResult) rowsAffected() (int64, error) {
|
||||
return result.affectedRows, nil
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
// This is a mirror of golang.org/x/crypto/internal/subtle.
|
||||
package security
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// AnyOverlap reports whether x and y share memory at any (not necessarily
|
||||
// corresponding) index. The memory beyond the slice length is ignored.
|
||||
func AnyOverlap(x, y []byte) bool {
|
||||
return len(x) > 0 && len(y) > 0 &&
|
||||
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
|
||||
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
|
||||
}
|
||||
|
||||
// InexactOverlap reports whether x and y share memory at any non-corresponding
|
||||
// index. The memory beyond the slice length is ignored. Note that x and y can
|
||||
// have different lengths and still not have any inexact overlap.
|
||||
//
|
||||
// InexactOverlap can be used to implement the requirements of the crypto/cipher
|
||||
// AEAD, Block, BlockMode and Stream interfaces.
|
||||
func InexactOverlap(x, y []byte) bool {
|
||||
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
|
||||
return false
|
||||
}
|
||||
return AnyOverlap(x, y)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
type Cipher interface {
|
||||
Encrypt(plaintext []byte, genDigest bool) []byte
|
||||
Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error)
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type dhGroup struct {
|
||||
p *big.Int
|
||||
g *big.Int
|
||||
}
|
||||
|
||||
func newDhGroup(prime, generator *big.Int) *dhGroup {
|
||||
return &dhGroup{
|
||||
p: prime,
|
||||
g: generator,
|
||||
}
|
||||
}
|
||||
|
||||
func (dg *dhGroup) P() *big.Int {
|
||||
p := new(big.Int)
|
||||
p.Set(dg.p)
|
||||
return p
|
||||
}
|
||||
|
||||
func (dg *dhGroup) G() *big.Int {
|
||||
g := new(big.Int)
|
||||
g.Set(dg.g)
|
||||
return g
|
||||
}
|
||||
|
||||
// 生成本地公私钥
|
||||
func (dg *dhGroup) GeneratePrivateKey(randReader io.Reader) (key *DhKey, err error) {
|
||||
if randReader == nil {
|
||||
randReader = rand.Reader
|
||||
}
|
||||
// 0 < x < p
|
||||
x, err := rand.Int(randReader, dg.p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
zero := big.NewInt(0)
|
||||
for x.Cmp(zero) == 0 {
|
||||
x, err = rand.Int(randReader, dg.p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
key = new(DhKey)
|
||||
key.x = x
|
||||
|
||||
// y = g ^ x mod p
|
||||
key.y = new(big.Int).Exp(dg.g, x, dg.p)
|
||||
key.group = dg
|
||||
return
|
||||
}
|
||||
|
||||
func (dg *dhGroup) ComputeKey(pubkey *DhKey, privkey *DhKey) (kye *DhKey, err error) {
|
||||
if dg.p == nil {
|
||||
err = errors.New("DH: invalid group")
|
||||
return
|
||||
}
|
||||
if pubkey.y == nil {
|
||||
err = errors.New("DH: invalid public key")
|
||||
return
|
||||
}
|
||||
if pubkey.y.Sign() <= 0 || pubkey.y.Cmp(dg.p) >= 0 {
|
||||
err = errors.New("DH parameter out of bounds")
|
||||
return
|
||||
}
|
||||
if privkey.x == nil {
|
||||
err = errors.New("DH: invalid private key")
|
||||
return
|
||||
}
|
||||
k := new(big.Int).Exp(pubkey.y, privkey.x, dg.p)
|
||||
key := new(DhKey)
|
||||
key.y = k
|
||||
key.group = dg
|
||||
return
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import "math/big"
|
||||
|
||||
type DhKey struct {
|
||||
x *big.Int
|
||||
y *big.Int
|
||||
group *dhGroup
|
||||
}
|
||||
|
||||
func newPublicKey(s []byte) *DhKey {
|
||||
key := new(DhKey)
|
||||
key.y = new(big.Int).SetBytes(s)
|
||||
return key
|
||||
}
|
||||
|
||||
func (dk *DhKey) GetX() *big.Int {
|
||||
x := new(big.Int)
|
||||
x.Set(dk.x)
|
||||
return x
|
||||
}
|
||||
|
||||
func (dk *DhKey) GetY() *big.Int {
|
||||
y := new(big.Int)
|
||||
y.Set(dk.y)
|
||||
return y
|
||||
}
|
||||
|
||||
func (dk *DhKey) GetYBytes() []byte {
|
||||
if dk.y == nil {
|
||||
return nil
|
||||
}
|
||||
if dk.group != nil {
|
||||
blen := (dk.group.p.BitLen() + 7) / 8
|
||||
ret := make([]byte, blen)
|
||||
copyWithLeftPad(ret, dk.y.Bytes())
|
||||
return ret
|
||||
}
|
||||
return dk.y.Bytes()
|
||||
}
|
||||
|
||||
func (dk *DhKey) GetYString() string {
|
||||
if dk.y == nil {
|
||||
return ""
|
||||
}
|
||||
return dk.y.String()
|
||||
}
|
||||
|
||||
func (dk *DhKey) IsPrivateKey() bool {
|
||||
return dk.x != nil
|
||||
}
|
||||
|
||||
func copyWithLeftPad(dest, src []byte) {
|
||||
numPaddingBytes := len(dest) - len(src)
|
||||
for i := 0; i < numPaddingBytes; i++ {
|
||||
dest[i] = 0
|
||||
}
|
||||
copy(dest[:numPaddingBytes], src)
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
// go官方没有实现ecb加密模式
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
)
|
||||
|
||||
type ecb struct {
|
||||
b cipher.Block
|
||||
blockSize int
|
||||
}
|
||||
|
||||
func newECB(b cipher.Block) *ecb {
|
||||
return &ecb{
|
||||
b: b,
|
||||
blockSize: b.BlockSize(),
|
||||
}
|
||||
}
|
||||
|
||||
type ecbEncrypter ecb
|
||||
|
||||
func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
|
||||
return (*ecbEncrypter)(newECB(b))
|
||||
}
|
||||
|
||||
func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
|
||||
|
||||
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
|
||||
if len(src)%x.blockSize != 0 {
|
||||
panic("dm/security: input not full blocks")
|
||||
}
|
||||
if len(dst) < len(src) {
|
||||
panic("dm/security: output smaller than input")
|
||||
}
|
||||
if InexactOverlap(dst[:len(src)], src) {
|
||||
panic("dm/security: invalid buffer overlap")
|
||||
}
|
||||
for bs, be := 0, x.blockSize; bs < len(src); bs, be = bs+x.blockSize, be+x.blockSize {
|
||||
x.b.Encrypt(dst[bs:be], src[bs:be])
|
||||
}
|
||||
}
|
||||
|
||||
type ecbDecrypter ecb
|
||||
|
||||
func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
|
||||
return (*ecbDecrypter)(newECB(b))
|
||||
}
|
||||
|
||||
func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
|
||||
|
||||
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
|
||||
if len(src)%x.blockSize != 0 {
|
||||
panic("dm/security: input not full blocks")
|
||||
}
|
||||
if len(dst) < len(src) {
|
||||
panic("dm/security: output smaller than input")
|
||||
}
|
||||
if InexactOverlap(dst[:len(src)], src) {
|
||||
panic("dm/security: invalid buffer overlap")
|
||||
}
|
||||
for bs, be := 0, x.blockSize; bs < len(src); bs, be = bs+x.blockSize, be+x.blockSize {
|
||||
x.b.Decrypt(dst[bs:be], src[bs:be])
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const (
|
||||
DH_KEY_LENGTH int = 64
|
||||
/* 低7位用于保存分组加密算法中的工作模式 */
|
||||
WORK_MODE_MASK int = 0x007f
|
||||
ECB_MODE int = 0x1
|
||||
CBC_MODE int = 0x2
|
||||
CFB_MODE int = 0x4
|
||||
OFB_MODE int = 0x8
|
||||
/* 高位保存加密算法 */
|
||||
ALGO_MASK int = 0xff80
|
||||
DES int = 0x0080
|
||||
DES3 int = 0x0100
|
||||
AES128 int = 0x0200
|
||||
AES192 int = 0x0400
|
||||
AES256 int = 0x0800
|
||||
RC4 int = 0x1000
|
||||
MD5 int = 0x1100
|
||||
|
||||
// 用户名密码加密算法
|
||||
DES_CFB int = 132
|
||||
// 消息加密摘要长度
|
||||
MD5_DIGEST_SIZE int = 16
|
||||
|
||||
MIN_EXTERNAL_CIPHER_ID int = 5000
|
||||
)
|
||||
|
||||
var dhParaP = "C009D877BAF5FAF416B7F778E6115DCB90D65217DCC2F08A9DFCB5A192C593EBAB02929266B8DBFC2021039FDBD4B7FDE2B996E00008F57AE6EFB4ED3F17B6D3"
|
||||
var dhParaG = "5"
|
||||
var defaultIV = []byte{0x20, 0x21, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
|
||||
0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
|
||||
0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20}
|
||||
var p *big.Int
|
||||
var g *big.Int
|
||||
|
||||
func NewClientKeyPair() (key *DhKey, err error) {
|
||||
p, _ = new(big.Int).SetString(dhParaP, 16)
|
||||
g, _ = new(big.Int).SetString(dhParaG, 16)
|
||||
dhGroup := newDhGroup(p, g)
|
||||
key, err = dhGroup.GeneratePrivateKey(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func ComputeSessionKey(clientPrivKey *DhKey, serverPubKey []byte) []byte {
|
||||
serverKeyX := bytes2Bn(serverPubKey)
|
||||
clientPrivKeyX := clientPrivKey.GetX()
|
||||
sessionKeyBN := serverKeyX.Exp(serverKeyX, clientPrivKeyX, p)
|
||||
return Bn2Bytes(sessionKeyBN, 0)
|
||||
}
|
||||
|
||||
func bytes2Bn(bnBytesSrc []byte) *big.Int {
|
||||
if bnBytesSrc == nil {
|
||||
return nil
|
||||
}
|
||||
if bnBytesSrc[0] == 0 {
|
||||
return new(big.Int).SetBytes(bnBytesSrc)
|
||||
}
|
||||
validBytesCount := len(bnBytesSrc) + 1
|
||||
bnBytesTo := make([]byte, validBytesCount)
|
||||
bnBytesTo[0] = 0
|
||||
copy(bnBytesTo[1:validBytesCount], bnBytesSrc)
|
||||
return new(big.Int).SetBytes(bnBytesTo)
|
||||
}
|
||||
|
||||
func Bn2Bytes(bn *big.Int, bnLen int) []byte {
|
||||
var bnBytesSrc, bnBytesTemp, bnBytesTo []byte
|
||||
var leading_zero_count int
|
||||
validBytesCount := 0
|
||||
if bn == nil {
|
||||
return nil
|
||||
}
|
||||
bnBytesSrc = bn.Bytes()
|
||||
|
||||
// 去除首位0
|
||||
if bnBytesSrc[0] != 0 {
|
||||
bnBytesTemp = bnBytesSrc
|
||||
validBytesCount = len(bnBytesTemp)
|
||||
} else {
|
||||
validBytesCount = len(bnBytesSrc) - 1
|
||||
bnBytesTemp = make([]byte, validBytesCount)
|
||||
copy(bnBytesTemp, bnBytesSrc[1:validBytesCount+1])
|
||||
}
|
||||
|
||||
if bnLen == 0 {
|
||||
leading_zero_count = 0
|
||||
} else {
|
||||
leading_zero_count = bnLen - validBytesCount
|
||||
}
|
||||
// 如果位数不足DH_KEY_LENGTH则在前面补0
|
||||
if leading_zero_count > 0 {
|
||||
bnBytesTo = make([]byte, DH_KEY_LENGTH)
|
||||
i := 0
|
||||
for i = 0; i < leading_zero_count; i++ {
|
||||
bnBytesTo[i] = 0
|
||||
}
|
||||
copy(bnBytesTo[i:i+validBytesCount], bnBytesTemp)
|
||||
} else {
|
||||
bnBytesTo = bnBytesTemp
|
||||
}
|
||||
return bnBytesTo
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/md5"
|
||||
"crypto/rc4"
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type SymmCipher struct {
|
||||
encryptCipher interface{} //cipher.BlockMode | cipher.Stream
|
||||
decryptCipher interface{} //cipher.BlockMode | cipher.Stream
|
||||
key []byte
|
||||
block cipher.Block // 分组加密算法
|
||||
algorithmType int
|
||||
workMode int
|
||||
needPadding bool
|
||||
}
|
||||
|
||||
func NewSymmCipher(algorithmID int, key []byte) (SymmCipher, error) {
|
||||
var sc SymmCipher
|
||||
var err error
|
||||
sc.key = key
|
||||
sc.algorithmType = algorithmID & ALGO_MASK
|
||||
sc.workMode = algorithmID & WORK_MODE_MASK
|
||||
switch sc.algorithmType {
|
||||
case AES128:
|
||||
if sc.block, err = aes.NewCipher(key[:16]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
case AES192:
|
||||
if sc.block, err = aes.NewCipher(key[:24]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
case AES256:
|
||||
if sc.block, err = aes.NewCipher(key[:32]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
case DES:
|
||||
if sc.block, err = des.NewCipher(key[:8]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
case DES3:
|
||||
var tripleDESKey []byte
|
||||
tripleDESKey = append(tripleDESKey, key[:16]...)
|
||||
tripleDESKey = append(tripleDESKey, key[:8]...)
|
||||
if sc.block, err = des.NewTripleDESCipher(tripleDESKey); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
case RC4:
|
||||
if sc.encryptCipher, err = rc4.NewCipher(key[:16]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
if sc.decryptCipher, err = rc4.NewCipher(key[:16]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
return sc, nil
|
||||
default:
|
||||
return sc, errors.New("invalidCipher")
|
||||
}
|
||||
blockSize := sc.block.BlockSize()
|
||||
if sc.encryptCipher, err = sc.getEncrypter(sc.workMode, sc.block, defaultIV[:blockSize]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
if sc.decryptCipher, err = sc.getDecrypter(sc.workMode, sc.block, defaultIV[:blockSize]); err != nil {
|
||||
return sc, err
|
||||
}
|
||||
return sc, nil
|
||||
}
|
||||
|
||||
func (sc SymmCipher) Encrypt(plaintext []byte, genDigest bool) []byte {
|
||||
// 执行过加密后,IV值变了,需要重新初始化encryptCipher对象(因为没有类似resetIV的方法)
|
||||
if sc.algorithmType != RC4 {
|
||||
sc.encryptCipher, _ = sc.getEncrypter(sc.workMode, sc.block, defaultIV[:sc.block.BlockSize()])
|
||||
} else {
|
||||
sc.encryptCipher, _ = rc4.NewCipher(sc.key[:16])
|
||||
}
|
||||
// 填充
|
||||
var paddingtext = make([]byte, len(plaintext))
|
||||
copy(paddingtext, plaintext)
|
||||
if sc.needPadding {
|
||||
paddingtext = pkcs5Padding(paddingtext)
|
||||
}
|
||||
|
||||
ret := make([]byte, len(paddingtext))
|
||||
|
||||
if v, ok := sc.encryptCipher.(cipher.Stream); ok {
|
||||
v.XORKeyStream(ret, paddingtext)
|
||||
} else if v, ok := sc.encryptCipher.(cipher.BlockMode); ok {
|
||||
v.CryptBlocks(ret, paddingtext)
|
||||
}
|
||||
|
||||
// md5摘要
|
||||
if genDigest {
|
||||
digest := md5.Sum(plaintext)
|
||||
encrypt := ret
|
||||
ret = make([]byte, len(encrypt)+len(digest))
|
||||
copy(ret[:len(encrypt)], encrypt)
|
||||
copy(ret[len(encrypt):], digest[:])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (sc SymmCipher) Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) {
|
||||
// 执行过解密后,IV值变了,需要重新初始化decryptCipher对象(因为没有类似resetIV的方法)
|
||||
if sc.algorithmType != RC4 {
|
||||
sc.decryptCipher, _ = sc.getDecrypter(sc.workMode, sc.block, defaultIV[:sc.block.BlockSize()])
|
||||
} else {
|
||||
sc.decryptCipher, _ = rc4.NewCipher(sc.key[:16])
|
||||
}
|
||||
var ret []byte
|
||||
if checkDigest {
|
||||
var digest = ciphertext[len(ciphertext)-MD5_DIGEST_SIZE:]
|
||||
ret = ciphertext[:len(ciphertext)-MD5_DIGEST_SIZE]
|
||||
ret = sc.decrypt(ret)
|
||||
var msgDigest = md5.Sum(ret)
|
||||
if !reflect.DeepEqual(msgDigest[:], digest) {
|
||||
return nil, errors.New("Decrypt failed/Digest not match\n")
|
||||
}
|
||||
} else {
|
||||
ret = sc.decrypt(ciphertext)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (sc SymmCipher) decrypt(ciphertext []byte) []byte {
|
||||
ret := make([]byte, len(ciphertext))
|
||||
if v, ok := sc.decryptCipher.(cipher.Stream); ok {
|
||||
v.XORKeyStream(ret, ciphertext)
|
||||
} else if v, ok := sc.decryptCipher.(cipher.BlockMode); ok {
|
||||
v.CryptBlocks(ret, ciphertext)
|
||||
}
|
||||
// 去除填充
|
||||
if sc.needPadding {
|
||||
ret = pkcs5UnPadding(ret)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (sc *SymmCipher) getEncrypter(workMode int, block cipher.Block, iv []byte) (ret interface{}, err error) {
|
||||
switch workMode {
|
||||
case ECB_MODE:
|
||||
ret = NewECBEncrypter(block)
|
||||
sc.needPadding = true
|
||||
case CBC_MODE:
|
||||
ret = cipher.NewCBCEncrypter(block, iv)
|
||||
sc.needPadding = true
|
||||
case CFB_MODE:
|
||||
ret = cipher.NewCFBEncrypter(block, iv)
|
||||
sc.needPadding = false
|
||||
case OFB_MODE:
|
||||
ret = cipher.NewOFB(block, iv)
|
||||
sc.needPadding = false
|
||||
default:
|
||||
err = errors.New("invalidCipherMode")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (sc *SymmCipher) getDecrypter(workMode int, block cipher.Block, iv []byte) (ret interface{}, err error) {
|
||||
switch workMode {
|
||||
case ECB_MODE:
|
||||
ret = NewECBDecrypter(block)
|
||||
sc.needPadding = true
|
||||
case CBC_MODE:
|
||||
ret = cipher.NewCBCDecrypter(block, iv)
|
||||
sc.needPadding = true
|
||||
case CFB_MODE:
|
||||
ret = cipher.NewCFBDecrypter(block, iv)
|
||||
sc.needPadding = false
|
||||
case OFB_MODE:
|
||||
ret = cipher.NewOFB(block, iv)
|
||||
sc.needPadding = false
|
||||
default:
|
||||
err = errors.New("invalidCipherMode")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 补码
|
||||
func pkcs77Padding(ciphertext []byte, blocksize int) []byte {
|
||||
padding := blocksize - len(ciphertext)%blocksize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
// 去码
|
||||
func pkcs7UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:length-unpadding]
|
||||
}
|
||||
|
||||
// 补码
|
||||
func pkcs5Padding(ciphertext []byte) []byte {
|
||||
return pkcs77Padding(ciphertext, 8)
|
||||
}
|
||||
|
||||
// 去码
|
||||
func pkcs5UnPadding(ciphertext []byte) []byte {
|
||||
return pkcs7UnPadding(ciphertext)
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type ThirdPartCipher struct {
|
||||
encryptType int // 外部加密算法id
|
||||
encryptName string // 外部加密算法名称
|
||||
hashType int
|
||||
key []byte
|
||||
cipherCount int // 外部加密算法个数
|
||||
//innerId int // 外部加密算法内部id
|
||||
blockSize int // 分组块大小
|
||||
khSize int // key/hash大小
|
||||
}
|
||||
|
||||
func NewThirdPartCipher(encryptType int, key []byte, cipherPath string, hashType int) (ThirdPartCipher, error) {
|
||||
var tpc = ThirdPartCipher{
|
||||
encryptType: encryptType,
|
||||
key: key,
|
||||
hashType: hashType,
|
||||
cipherCount: -1,
|
||||
}
|
||||
var err error
|
||||
err = initThirdPartCipher(cipherPath)
|
||||
if err != nil {
|
||||
return tpc, err
|
||||
}
|
||||
tpc.getCount()
|
||||
if err = tpc.getInfo(); err != nil {
|
||||
return tpc, err
|
||||
}
|
||||
return tpc, nil
|
||||
}
|
||||
|
||||
func (tpc *ThirdPartCipher) getCount() int {
|
||||
if tpc.cipherCount == -1 {
|
||||
tpc.cipherCount = cipherGetCount()
|
||||
}
|
||||
return tpc.cipherCount
|
||||
}
|
||||
|
||||
func (tpc *ThirdPartCipher) getInfo() error {
|
||||
var cipher_id, ty, blk_size, kh_size int
|
||||
//var strptr, _ = syscall.UTF16PtrFromString(tpc.encryptName)
|
||||
var strptr *uint16 = new(uint16)
|
||||
for i := 1; i <= tpc.getCount(); i++ {
|
||||
cipherGetInfo(uintptr(i), uintptr(unsafe.Pointer(&cipher_id)), uintptr(unsafe.Pointer(&strptr)),
|
||||
uintptr(unsafe.Pointer(&ty)), uintptr(unsafe.Pointer(&blk_size)), uintptr(unsafe.Pointer(&kh_size)))
|
||||
if tpc.encryptType == cipher_id {
|
||||
tpc.blockSize = blk_size
|
||||
tpc.khSize = kh_size
|
||||
tpc.encryptName = string(uintptr2bytes(uintptr(unsafe.Pointer(strptr))))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("ThirdPartyCipher: cipher id:%d not found", tpc.encryptType)
|
||||
}
|
||||
|
||||
func (tpc ThirdPartCipher) Encrypt(plaintext []byte, genDigest bool) []byte {
|
||||
var tmp_para uintptr
|
||||
cipherEncryptInit(uintptr(tpc.encryptType), uintptr(unsafe.Pointer(&tpc.key[0])), uintptr(len(tpc.key)), tmp_para)
|
||||
|
||||
ciphertextLen := cipherGetCipherTextSize(uintptr(tpc.encryptType), tmp_para, uintptr(len(plaintext)))
|
||||
|
||||
ciphertext := make([]byte, ciphertextLen)
|
||||
ret := cipherEncrypt(uintptr(tpc.encryptType), tmp_para, uintptr(unsafe.Pointer(&plaintext[0])), uintptr(len(plaintext)),
|
||||
uintptr(unsafe.Pointer(&ciphertext[0])), uintptr(len(ciphertext)))
|
||||
ciphertext = ciphertext[:ret]
|
||||
|
||||
cipherClean(uintptr(tpc.encryptType), tmp_para)
|
||||
// md5摘要
|
||||
if genDigest {
|
||||
digest := md5.Sum(plaintext)
|
||||
encrypt := ciphertext
|
||||
ciphertext = make([]byte, len(encrypt)+len(digest))
|
||||
copy(ciphertext[:len(encrypt)], encrypt)
|
||||
copy(ciphertext[len(encrypt):], digest[:])
|
||||
}
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
func (tpc ThirdPartCipher) Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) {
|
||||
var ret []byte
|
||||
if checkDigest {
|
||||
var digest = ciphertext[len(ciphertext)-MD5_DIGEST_SIZE:]
|
||||
ret = ciphertext[:len(ciphertext)-MD5_DIGEST_SIZE]
|
||||
ret = tpc.decrypt(ret)
|
||||
var msgDigest = md5.Sum(ret)
|
||||
if !reflect.DeepEqual(msgDigest[:], digest) {
|
||||
return nil, errors.New("Decrypt failed/Digest not match\n")
|
||||
}
|
||||
} else {
|
||||
ret = tpc.decrypt(ciphertext)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (tpc ThirdPartCipher) decrypt(ciphertext []byte) []byte {
|
||||
var tmp_para uintptr
|
||||
|
||||
cipherDecryptInit(uintptr(tpc.encryptType), uintptr(unsafe.Pointer(&tpc.key[0])), uintptr(len(tpc.key)), tmp_para)
|
||||
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
ret := cipherDecrypt(uintptr(tpc.encryptType), tmp_para, uintptr(unsafe.Pointer(&ciphertext[0])), uintptr(len(ciphertext)),
|
||||
uintptr(unsafe.Pointer(&plaintext[0])), uintptr(len(plaintext)))
|
||||
plaintext = plaintext[:ret]
|
||||
|
||||
cipherClean(uintptr(tpc.encryptType), tmp_para)
|
||||
return plaintext
|
||||
}
|
||||
|
||||
func addBufSize(buf []byte, newCap int) []byte {
|
||||
newBuf := make([]byte, newCap)
|
||||
copy(newBuf, buf)
|
||||
return newBuf
|
||||
}
|
||||
|
||||
func uintptr2bytes(p uintptr) []byte {
|
||||
buf := make([]byte, 64)
|
||||
i := 0
|
||||
for b := (*byte)(unsafe.Pointer(p)); *b != 0; i++ {
|
||||
if i > cap(buf) {
|
||||
buf = addBufSize(buf, i*2)
|
||||
}
|
||||
buf[i] = *b
|
||||
// byte占1字节
|
||||
p++
|
||||
b = (*byte)(unsafe.Pointer(p))
|
||||
}
|
||||
return buf[:i]
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import "plugin"
|
||||
|
||||
var (
|
||||
dmCipherEncryptSo *plugin.Plugin
|
||||
cipherGetCountProc plugin.Symbol
|
||||
cipherGetInfoProc plugin.Symbol
|
||||
cipherEncryptInitProc plugin.Symbol
|
||||
cipherGetCipherTextSizeProc plugin.Symbol
|
||||
cipherEncryptProc plugin.Symbol
|
||||
cipherCleanupProc plugin.Symbol
|
||||
cipherDecryptInitProc plugin.Symbol
|
||||
cipherDecryptProc plugin.Symbol
|
||||
)
|
||||
|
||||
func initThirdPartCipher(cipherPath string) (err error) {
|
||||
if dmCipherEncryptSo, err = plugin.Open(cipherPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherGetCountProc, err = dmCipherEncryptSo.Lookup("cipher_get_count"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherGetInfoProc, err = dmCipherEncryptSo.Lookup("cipher_get_info"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherEncryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt_init"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherGetCipherTextSizeProc, err = dmCipherEncryptSo.Lookup("cipher_get_cipher_text_size"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherEncryptProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherCleanupProc, err = dmCipherEncryptSo.Lookup("cipher_cleanup"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherDecryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt_init"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherDecryptProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cipherGetCount() int {
|
||||
ret := cipherGetCountProc.(func() interface{})()
|
||||
return ret.(int)
|
||||
}
|
||||
|
||||
func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) {
|
||||
ret := cipherGetInfoProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(seqno, cipherId, cipherName, _type, blkSize, khSIze)
|
||||
if ret.(int) == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_get_info failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) {
|
||||
ret := cipherEncryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara)
|
||||
if ret.(int) == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_encrypt_init failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr {
|
||||
ciphertextLen := cipherGetCipherTextSizeProc.(func(uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainTextSize)
|
||||
return ciphertextLen.(uintptr)
|
||||
}
|
||||
|
||||
func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr {
|
||||
ret := cipherEncryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize)
|
||||
return ret.(uintptr)
|
||||
}
|
||||
|
||||
func cipherClean(cipherId, cipherPara uintptr) {
|
||||
cipherEncryptProc.(func(uintptr, uintptr))(cipherId, cipherPara)
|
||||
}
|
||||
|
||||
func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) {
|
||||
ret := cipherDecryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara)
|
||||
if ret.(int) == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_decrypt_init failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr {
|
||||
ret := cipherDecryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize)
|
||||
return ret.(uintptr)
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import "plugin"
|
||||
|
||||
var (
|
||||
dmCipherEncryptSo *plugin.Plugin
|
||||
cipherGetCountProc plugin.Symbol
|
||||
cipherGetInfoProc plugin.Symbol
|
||||
cipherEncryptInitProc plugin.Symbol
|
||||
cipherGetCipherTextSizeProc plugin.Symbol
|
||||
cipherEncryptProc plugin.Symbol
|
||||
cipherCleanupProc plugin.Symbol
|
||||
cipherDecryptInitProc plugin.Symbol
|
||||
cipherDecryptProc plugin.Symbol
|
||||
)
|
||||
|
||||
func initThirdPartCipher(cipherPath string) (err error) {
|
||||
if dmCipherEncryptSo, err = plugin.Open(cipherPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherGetCountProc, err = dmCipherEncryptSo.Lookup("cipher_get_count"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherGetInfoProc, err = dmCipherEncryptSo.Lookup("cipher_get_info"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherEncryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt_init"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherGetCipherTextSizeProc, err = dmCipherEncryptSo.Lookup("cipher_get_cipher_text_size"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherEncryptProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherCleanupProc, err = dmCipherEncryptSo.Lookup("cipher_cleanup"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherDecryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt_init"); err != nil {
|
||||
return err
|
||||
}
|
||||
if cipherDecryptProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cipherGetCount() int {
|
||||
ret := cipherGetCountProc.(func() interface{})()
|
||||
return ret.(int)
|
||||
}
|
||||
|
||||
func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) {
|
||||
ret := cipherGetInfoProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(seqno, cipherId, cipherName, _type, blkSize, khSIze)
|
||||
if ret.(int) == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_get_info failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) {
|
||||
ret := cipherEncryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara)
|
||||
if ret.(int) == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_encrypt_init failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr {
|
||||
ciphertextLen := cipherGetCipherTextSizeProc.(func(uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainTextSize)
|
||||
return ciphertextLen.(uintptr)
|
||||
}
|
||||
|
||||
func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr {
|
||||
ret := cipherEncryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize)
|
||||
return ret.(uintptr)
|
||||
}
|
||||
|
||||
func cipherClean(cipherId, cipherPara uintptr) {
|
||||
cipherEncryptProc.(func(uintptr, uintptr))(cipherId, cipherPara)
|
||||
}
|
||||
|
||||
func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) {
|
||||
ret := cipherDecryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara)
|
||||
if ret.(int) == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_decrypt_init failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr {
|
||||
ret := cipherDecryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize)
|
||||
return ret.(uintptr)
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
dmCipherEncryptDLL *syscall.LazyDLL
|
||||
cipherGetCountProc *syscall.LazyProc
|
||||
cipherGetInfoProc *syscall.LazyProc
|
||||
cipherEncryptInitProc *syscall.LazyProc
|
||||
cipherGetCipherTextSizeProc *syscall.LazyProc
|
||||
cipherEncryptProc *syscall.LazyProc
|
||||
cipherCleanupProc *syscall.LazyProc
|
||||
cipherDecryptInitProc *syscall.LazyProc
|
||||
cipherDecryptProc *syscall.LazyProc
|
||||
)
|
||||
|
||||
func initThirdPartCipher(cipherPath string) error {
|
||||
dmCipherEncryptDLL = syscall.NewLazyDLL(cipherPath)
|
||||
if err := dmCipherEncryptDLL.Load(); err != nil {
|
||||
return err
|
||||
}
|
||||
cipherGetCountProc = dmCipherEncryptDLL.NewProc("cipher_get_count")
|
||||
cipherGetInfoProc = dmCipherEncryptDLL.NewProc("cipher_get_info")
|
||||
cipherEncryptInitProc = dmCipherEncryptDLL.NewProc("cipher_encrypt_init")
|
||||
cipherGetCipherTextSizeProc = dmCipherEncryptDLL.NewProc("cipher_get_cipher_text_size")
|
||||
cipherEncryptProc = dmCipherEncryptDLL.NewProc("cipher_encrypt")
|
||||
cipherCleanupProc = dmCipherEncryptDLL.NewProc("cipher_cleanup")
|
||||
cipherDecryptInitProc = dmCipherEncryptDLL.NewProc("cipher_decrypt_init")
|
||||
cipherDecryptProc = dmCipherEncryptDLL.NewProc("cipher_decrypt")
|
||||
return nil
|
||||
}
|
||||
|
||||
func cipherGetCount() int {
|
||||
ret, _, _ := cipherGetCountProc.Call()
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) {
|
||||
ret, _, _ := cipherGetInfoProc.Call(seqno, cipherId, cipherName, _type, blkSize, khSIze)
|
||||
if ret == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_get_info failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) {
|
||||
ret, _, _ := cipherEncryptInitProc.Call(cipherId, key, keySize, cipherPara)
|
||||
if ret == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_encrypt_init failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr {
|
||||
ciphertextLen, _, _ := cipherGetCipherTextSizeProc.Call(cipherId, cipherPara, plainTextSize)
|
||||
return ciphertextLen
|
||||
}
|
||||
|
||||
func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr {
|
||||
ret, _, _ := cipherEncryptProc.Call(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize)
|
||||
return ret
|
||||
}
|
||||
|
||||
func cipherClean(cipherId, cipherPara uintptr) {
|
||||
_, _, _ = cipherCleanupProc.Call(cipherId, cipherPara)
|
||||
}
|
||||
|
||||
func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) {
|
||||
ret, _, _ := cipherDecryptInitProc.Call(cipherId, key, keySize, cipherPara)
|
||||
if ret == 0 {
|
||||
panic("ThirdPartyCipher: call cipher_decrypt_init failed")
|
||||
}
|
||||
}
|
||||
|
||||
func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr {
|
||||
ret, _, _ := cipherDecryptProc.Call(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize)
|
||||
return ret
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//var dmHome = flag.String("DM_HOME", "", "Where DMDB installed")
|
||||
var flagLock = sync.Mutex{}
|
||||
|
||||
func NewTLSFromTCP(conn net.Conn, sslCertPath string, sslKeyPath string, user string) (*tls.Conn, error) {
|
||||
if sslCertPath == "" && sslKeyPath == "" {
|
||||
// 用户必须手动指定ssl文件和签名(.cert文件)
|
||||
return nil, errors.New("sslCertPath and sslKeyPath can not be empty!")
|
||||
|
||||
}
|
||||
cer, err := tls.LoadX509KeyPair(sslCertPath, sslKeyPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
Certificates: []tls.Certificate{cer},
|
||||
}
|
||||
tlsConn := tls.Client(conn, conf)
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tlsConn, nil
|
||||
}
|
||||
+522
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DmRows struct {
|
||||
filterable
|
||||
CurrentRows *innerRows
|
||||
finish func()
|
||||
}
|
||||
|
||||
func (r *DmRows) Columns() []string {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return nil
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.columns()
|
||||
}
|
||||
return r.filterChain.reset().DmRowsColumns(r)
|
||||
}
|
||||
|
||||
func (r *DmRows) Close() error {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.close()
|
||||
}
|
||||
return r.filterChain.reset().DmRowsClose(r)
|
||||
}
|
||||
|
||||
func (r *DmRows) Next(dest []driver.Value) error {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.next(dest)
|
||||
}
|
||||
return r.filterChain.reset().DmRowsNext(r, dest)
|
||||
}
|
||||
|
||||
func (r *DmRows) HasNextResultSet() bool {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return false
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.hasNextResultSet()
|
||||
}
|
||||
return r.filterChain.reset().DmRowsHasNextResultSet(r)
|
||||
}
|
||||
|
||||
func (r *DmRows) NextResultSet() error {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.nextResultSet()
|
||||
}
|
||||
return r.filterChain.reset().DmRowsNextResultSet(r)
|
||||
}
|
||||
|
||||
func (r *DmRows) ColumnTypeScanType(index int) reflect.Type {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return nil
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.columnTypeScanType(index)
|
||||
}
|
||||
return r.filterChain.reset().DmRowsColumnTypeScanType(r, index)
|
||||
}
|
||||
|
||||
func (r *DmRows) ColumnTypeDatabaseTypeName(index int) string {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return ""
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.columnTypeDatabaseTypeName(index)
|
||||
}
|
||||
return r.filterChain.reset().DmRowsColumnTypeDatabaseTypeName(r, index)
|
||||
}
|
||||
|
||||
func (r *DmRows) ColumnTypeLength(index int) (length int64, ok bool) {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return -1, false
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.columnTypeLength(index)
|
||||
}
|
||||
return r.filterChain.reset().DmRowsColumnTypeLength(r, index)
|
||||
}
|
||||
|
||||
func (r *DmRows) ColumnTypeNullable(index int) (nullable, ok bool) {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return false, false
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.columnTypeNullable(index)
|
||||
}
|
||||
return r.filterChain.reset().DmRowsColumnTypeNullable(r, index)
|
||||
}
|
||||
|
||||
func (r *DmRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
|
||||
if err := r.CurrentRows.dmStmt.checkClosed(); err != nil {
|
||||
return -1, -1, false
|
||||
}
|
||||
if len(r.filterChain.filters) == 0 {
|
||||
return r.columnTypePrecisionScale(index)
|
||||
}
|
||||
return r.filterChain.reset().DmRowsColumnTypePrecisionScale(r, index)
|
||||
}
|
||||
|
||||
func (dest *DmRows) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmRows)
|
||||
return nil
|
||||
case *DmRows:
|
||||
*dest = *src
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN
|
||||
}
|
||||
}
|
||||
|
||||
func (rows *DmRows) columns() []string {
|
||||
return rows.CurrentRows.Columns()
|
||||
}
|
||||
|
||||
func (rows *DmRows) close() error {
|
||||
if f := rows.finish; f != nil {
|
||||
f()
|
||||
rows.finish = nil
|
||||
}
|
||||
return rows.CurrentRows.Close()
|
||||
}
|
||||
|
||||
func (rows *DmRows) next(dest []driver.Value) error {
|
||||
return rows.CurrentRows.Next(dest)
|
||||
}
|
||||
|
||||
func (rows *DmRows) hasNextResultSet() bool {
|
||||
return rows.CurrentRows.HasNextResultSet()
|
||||
}
|
||||
|
||||
func (rows *DmRows) nextResultSet() error {
|
||||
return rows.CurrentRows.NextResultSet()
|
||||
}
|
||||
|
||||
func (rows *DmRows) columnTypeScanType(index int) reflect.Type {
|
||||
return rows.CurrentRows.ColumnTypeScanType(index)
|
||||
}
|
||||
|
||||
func (rows *DmRows) columnTypeDatabaseTypeName(index int) string {
|
||||
return rows.CurrentRows.ColumnTypeDatabaseTypeName(index)
|
||||
}
|
||||
|
||||
func (rows *DmRows) columnTypeLength(index int) (length int64, ok bool) {
|
||||
return rows.CurrentRows.ColumnTypeLength(index)
|
||||
}
|
||||
|
||||
func (rows *DmRows) columnTypeNullable(index int) (nullable, ok bool) {
|
||||
return rows.CurrentRows.ColumnTypeNullable(index)
|
||||
}
|
||||
|
||||
func (rows *DmRows) columnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
|
||||
return rows.CurrentRows.ColumnTypePrecisionScale(index)
|
||||
}
|
||||
|
||||
type innerRows struct {
|
||||
dmStmt *DmStatement
|
||||
|
||||
id int16
|
||||
|
||||
columns []column
|
||||
|
||||
datas [][][]byte
|
||||
|
||||
datasOffset int
|
||||
|
||||
datasStartPos int64
|
||||
|
||||
currentPos int64
|
||||
|
||||
totalRowCount int64
|
||||
|
||||
fetchSize int
|
||||
|
||||
sizeOfRow int
|
||||
|
||||
isBdta bool
|
||||
|
||||
nextExecInfo *execRetInfo
|
||||
|
||||
next *innerRows
|
||||
|
||||
dmRows *DmRows
|
||||
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) checkClosed() error {
|
||||
if innerRows.closed {
|
||||
return ECGO_RESULTSET_CLOSED.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) Columns() []string {
|
||||
if err := innerRows.checkClosed(); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
columnNames := make([]string, len(innerRows.columns))
|
||||
nameCase := innerRows.dmStmt.dmConn.dmConnector.columnNameCase
|
||||
|
||||
for i, column := range innerRows.columns {
|
||||
if nameCase == COLUMN_NAME_NATURAL_CASE {
|
||||
columnNames[i] = column.name
|
||||
} else if nameCase == COLUMN_NAME_UPPER_CASE {
|
||||
columnNames[i] = strings.ToUpper(column.name)
|
||||
} else if nameCase == COLUMN_NAME_LOWER_CASE {
|
||||
columnNames[i] = strings.ToLower(column.name)
|
||||
} else {
|
||||
columnNames[i] = column.name
|
||||
}
|
||||
}
|
||||
|
||||
return columnNames
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) Close() error {
|
||||
if innerRows.closed {
|
||||
return nil
|
||||
}
|
||||
|
||||
innerRows.closed = true
|
||||
|
||||
if innerRows.dmStmt.innerUsed {
|
||||
innerRows.dmStmt.close()
|
||||
} else {
|
||||
delete(innerRows.dmStmt.rsMap, innerRows.id)
|
||||
}
|
||||
|
||||
innerRows.dmStmt = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) Next(dest []driver.Value) error {
|
||||
err := innerRows.checkClosed()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if innerRows.totalRowCount == 0 || innerRows.currentPos >= innerRows.totalRowCount {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
if innerRows.currentPos+1 == innerRows.totalRowCount {
|
||||
innerRows.currentPos++
|
||||
innerRows.datasOffset++
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
if innerRows.currentPos+1 < innerRows.datasStartPos || innerRows.currentPos+1 >= innerRows.datasStartPos+int64(len(innerRows.datas)) {
|
||||
if innerRows.fetchData(innerRows.currentPos + 1) {
|
||||
innerRows.currentPos++
|
||||
err := innerRows.getRowData(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
innerRows.currentPos++
|
||||
innerRows.datasOffset++
|
||||
return io.EOF
|
||||
}
|
||||
} else {
|
||||
innerRows.currentPos++
|
||||
innerRows.datasOffset++
|
||||
err := innerRows.getRowData(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) HasNextResultSet() bool {
|
||||
err := innerRows.checkClosed()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if innerRows.nextExecInfo != nil {
|
||||
return innerRows.nextExecInfo.hasResultSet
|
||||
}
|
||||
|
||||
innerRows.nextExecInfo, err = innerRows.dmStmt.dmConn.Access.Dm_build_543(innerRows.dmStmt, 0)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if innerRows.nextExecInfo.hasResultSet {
|
||||
innerRows.next = newInnerRows(innerRows.id+1, innerRows.dmStmt, innerRows.nextExecInfo)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) NextResultSet() error {
|
||||
err := innerRows.checkClosed()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if innerRows.nextExecInfo == nil {
|
||||
innerRows.HasNextResultSet()
|
||||
}
|
||||
|
||||
if innerRows.next == nil {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
innerRows.next.dmRows = innerRows.dmRows
|
||||
innerRows.dmRows.CurrentRows = innerRows.next
|
||||
return nil
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) ColumnTypeScanType(index int) reflect.Type {
|
||||
if err := innerRows.checkClosed(); err != nil {
|
||||
return nil
|
||||
}
|
||||
if column := innerRows.checkIndex(index); column != nil {
|
||||
return column.ScanType()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) ColumnTypeDatabaseTypeName(index int) string {
|
||||
if err := innerRows.checkClosed(); err != nil {
|
||||
return ""
|
||||
}
|
||||
if column := innerRows.checkIndex(index); column != nil {
|
||||
return column.typeName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) ColumnTypeLength(index int) (length int64, ok bool) {
|
||||
if err := innerRows.checkClosed(); err != nil {
|
||||
return 0, false
|
||||
}
|
||||
if column := innerRows.checkIndex(index); column != nil {
|
||||
return column.Length()
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) ColumnTypeNullable(index int) (nullable, ok bool) {
|
||||
if err := innerRows.checkClosed(); err != nil {
|
||||
return false, false
|
||||
}
|
||||
if column := innerRows.checkIndex(index); column != nil {
|
||||
return column.nullable, true
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
|
||||
if err := innerRows.checkClosed(); err != nil {
|
||||
return 0, 0, false
|
||||
}
|
||||
if column := innerRows.checkIndex(index); column != nil {
|
||||
return column.PrecisionScale()
|
||||
}
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
func newDmRows(currentRows *innerRows) *DmRows {
|
||||
dr := new(DmRows)
|
||||
dr.resetFilterable(¤tRows.dmStmt.filterable)
|
||||
dr.CurrentRows = currentRows
|
||||
dr.idGenerator = dmRowsIDGenerator
|
||||
currentRows.dmRows = dr
|
||||
return dr
|
||||
}
|
||||
|
||||
func newInnerRows(id int16, stmt *DmStatement, execInfo *execRetInfo) *innerRows {
|
||||
rows := new(innerRows)
|
||||
rows.id = id
|
||||
rows.dmStmt = stmt
|
||||
rows.columns = stmt.columns
|
||||
rows.datas = execInfo.rsDatas
|
||||
rows.totalRowCount = execInfo.updateCount
|
||||
rows.isBdta = execInfo.rsBdta
|
||||
rows.fetchSize = stmt.fetchSize
|
||||
|
||||
if len(execInfo.rsDatas) == 0 {
|
||||
rows.sizeOfRow = 0
|
||||
} else {
|
||||
rows.sizeOfRow = execInfo.rsSizeof / len(execInfo.rsDatas)
|
||||
}
|
||||
|
||||
rows.currentPos = -1
|
||||
rows.datasOffset = -1
|
||||
rows.datasStartPos = 0
|
||||
|
||||
rows.nextExecInfo = nil
|
||||
rows.next = nil
|
||||
|
||||
if rows.dmStmt.rsMap != nil {
|
||||
rows.dmStmt.rsMap[rows.id] = rows
|
||||
}
|
||||
|
||||
if stmt.dmConn.dmConnector.enRsCache && execInfo.rsCacheOffset > 0 &&
|
||||
int64(len(execInfo.rsDatas)) == execInfo.updateCount {
|
||||
rp.put(stmt, stmt.nativeSql, execInfo)
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
func newLocalInnerRows(stmt *DmStatement, columns []column, rsDatas [][][]byte) *innerRows {
|
||||
rows := new(innerRows)
|
||||
rows.id = 0
|
||||
rows.dmStmt = stmt
|
||||
rows.fetchSize = stmt.fetchSize
|
||||
|
||||
if columns == nil {
|
||||
rows.columns = make([]column, 0)
|
||||
} else {
|
||||
rows.columns = columns
|
||||
}
|
||||
|
||||
if rsDatas == nil {
|
||||
rows.datas = make([][][]byte, 0)
|
||||
rows.totalRowCount = 0
|
||||
} else {
|
||||
rows.datas = rsDatas
|
||||
rows.totalRowCount = int64(len(rsDatas))
|
||||
}
|
||||
|
||||
rows.isBdta = false
|
||||
return rows
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) checkIndex(index int) *column {
|
||||
if index < 0 || index > len(innerRows.columns)-1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &innerRows.columns[index]
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) fetchData(startPos int64) bool {
|
||||
execInfo, err := innerRows.dmStmt.dmConn.Access.Dm_build_550(innerRows, startPos)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
innerRows.totalRowCount = execInfo.updateCount
|
||||
if execInfo.rsDatas != nil {
|
||||
innerRows.datas = execInfo.rsDatas
|
||||
innerRows.datasStartPos = startPos
|
||||
innerRows.datasOffset = 0
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) getRowData(dest []driver.Value) (err error) {
|
||||
for i, column := range innerRows.columns {
|
||||
|
||||
if i <= len(dest)-1 {
|
||||
if column.colType == CURSOR {
|
||||
var tmpExecInfo *execRetInfo
|
||||
tmpExecInfo, err = innerRows.dmStmt.dmConn.Access.Dm_build_543(innerRows.dmStmt, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tmpExecInfo.hasResultSet {
|
||||
dest[i] = newDmRows(newInnerRows(innerRows.id+1, innerRows.dmStmt, tmpExecInfo))
|
||||
} else {
|
||||
dest[i] = nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
dest[i], err = column.getColumnData(innerRows.datas[innerRows.datasOffset][i+1], innerRows.dmStmt.dmConn)
|
||||
innerRows.columns[i].isBdta = innerRows.isBdta
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (innerRows *innerRows) getRowCount() int64 {
|
||||
innerRows.checkClosed()
|
||||
|
||||
if innerRows.totalRowCount == INT64_MAX {
|
||||
return -1
|
||||
}
|
||||
|
||||
return innerRows.totalRowCount
|
||||
}
|
||||
+1590
File diff suppressed because it is too large
Load Diff
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
func Split(s string, sep string) []string {
|
||||
var foot = make([]int, len(s)) // 足够的元素个数
|
||||
var count, sLen, sepLen = 0, len(s), len(sep)
|
||||
for i := 0; i < sLen; i++ {
|
||||
// 处理 s == “-9999-1" && seperators == "-"情况
|
||||
if i == 0 && sLen >= sepLen {
|
||||
if s[0:sepLen] == sep {
|
||||
i += sepLen - 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
for j := 0; j < sepLen; j++ {
|
||||
if s[i] == sep[j] {
|
||||
foot[count] = i
|
||||
count++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
var ret = make([]string, count+1)
|
||||
if count == 0 {
|
||||
ret[0] = s
|
||||
return ret
|
||||
}
|
||||
ret[0] = s[0:foot[0]]
|
||||
for i := 1; i < count; i++ {
|
||||
ret[i] = s[foot[i-1]+1 : foot[i]]
|
||||
}
|
||||
ret[count] = s[foot[count-1]+1:]
|
||||
return ret
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
PathSeparator = string(os.PathSeparator)
|
||||
PathListSeparator = string(os.PathListSeparator)
|
||||
)
|
||||
|
||||
var (
|
||||
goRoot = build.Default.GOROOT
|
||||
goPath = build.Default.GOPATH //获取实际编译时的GOPATH值
|
||||
)
|
||||
|
||||
type fileUtil struct {
|
||||
}
|
||||
|
||||
var FileUtil = &fileUtil{}
|
||||
|
||||
func (fileUtil *fileUtil) Exists(path string) bool {
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (fileUtil *fileUtil) Search(relativePath string) (path string) {
|
||||
if strings.Contains(runtime.GOOS, "windows") {
|
||||
relativePath = strings.ReplaceAll(relativePath, "/", "\\")
|
||||
}
|
||||
|
||||
if fileUtil.Exists(goPath) {
|
||||
for _, s := range strings.Split(goPath, PathListSeparator) {
|
||||
path = s + PathSeparator + "src" + PathSeparator + relativePath
|
||||
if fileUtil.Exists(path) {
|
||||
return path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if fileUtil.Exists(goPath) {
|
||||
for _, s := range strings.Split(goPath, PathListSeparator) {
|
||||
path = s + PathSeparator + "pkg" + PathSeparator + relativePath
|
||||
if fileUtil.Exists(path) {
|
||||
return path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if workDir, _ := os.Getwd(); fileUtil.Exists(workDir) {
|
||||
// path = workDir + PathSeparator + "src" + PathSeparator + relativePath
|
||||
// if fileUtil.Exists(path) {
|
||||
// return path
|
||||
// }
|
||||
//}
|
||||
|
||||
//if fileUtil.Exists(goRoot) {
|
||||
// path = goRoot + PathSeparator + "src" + PathSeparator + relativePath
|
||||
// if fileUtil.Exists(path) {
|
||||
// return path
|
||||
// }
|
||||
//}
|
||||
|
||||
return ""
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package util
|
||||
|
||||
const (
|
||||
LINE_SEPARATOR = "\n"
|
||||
)
|
||||
|
||||
// 执行f并忽略panic
|
||||
func AbsorbPanic(f func()){
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
// TODO do something
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
func SliceEquals(src []byte, dest []byte) bool {
|
||||
if len(src) != len(dest) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, _ := range src {
|
||||
if src[i] != dest[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取两个数的最大公约数,由调用者确保m、n>=0;如果m或n为0,返回1
|
||||
func GCD(m int32, n int32) int32 {
|
||||
if m == 0 || n == 0 {
|
||||
return 1
|
||||
}
|
||||
r := m % n
|
||||
m = n
|
||||
n = r
|
||||
if r == 0 {
|
||||
return m
|
||||
} else {
|
||||
return GCD(m, n)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回切片中所有数的累加值
|
||||
func Sum(arr []int32) int32 {
|
||||
var sum int32 = 0
|
||||
for _, i := range arr {
|
||||
sum += i
|
||||
}
|
||||
return sum
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type stringutil struct{}
|
||||
|
||||
var StringUtil = &stringutil{}
|
||||
|
||||
/*----------------------------------------------------*/
|
||||
func (StringUtil *stringutil) LineSeparator() string {
|
||||
var lineSeparator string
|
||||
if strings.Contains(runtime.GOOS, "windows") {
|
||||
lineSeparator = "\r\n"
|
||||
} else if strings.Contains(runtime.GOOS, "mac") {
|
||||
lineSeparator = "\r"
|
||||
} else {
|
||||
lineSeparator = "\n"
|
||||
}
|
||||
|
||||
return lineSeparator
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) Equals(str1 string, str2 string) bool {
|
||||
return str1 == str2
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) EqualsIgnoreCase(str1 string, str2 string) bool {
|
||||
return strings.ToUpper(str1) == strings.ToUpper(str2)
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) StartsWith(s string, subStr string) bool {
|
||||
return strings.Index(s, subStr) == 0
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) StartWithIgnoreCase(s string, subStr string) bool {
|
||||
return strings.HasPrefix(strings.ToLower(s), strings.ToLower(subStr))
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) EndsWith(s string, subStr string) bool {
|
||||
return strings.LastIndex(s, subStr) == len(s)-1
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) IsDigit(str string) bool {
|
||||
if str == "" {
|
||||
return false
|
||||
}
|
||||
sz := len(str)
|
||||
for i := 0; i < sz; i++ {
|
||||
if unicode.IsDigit(rune(str[i])) {
|
||||
continue
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) FormatDir(dir string) string {
|
||||
dir = strings.TrimSpace(dir)
|
||||
if dir != "" {
|
||||
if !StringUtil.EndsWith(dir, PathSeparator) {
|
||||
dir += PathSeparator
|
||||
}
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) HexStringToBytes(s string) []byte {
|
||||
str := s
|
||||
|
||||
bs := make([]byte, 0)
|
||||
flag := false
|
||||
|
||||
if strings.Index(str, "0x") == 0 || strings.Index(str, "0X") == 0 {
|
||||
str = str[2:]
|
||||
}
|
||||
|
||||
if len(str) == 0 {
|
||||
return bs
|
||||
}
|
||||
|
||||
var bsChr []byte
|
||||
l := len(str)
|
||||
|
||||
if l%2 == 0 {
|
||||
bsChr = []byte(str)
|
||||
} else {
|
||||
l += 1
|
||||
bsChr = make([]byte, l)
|
||||
bsChr[0] = '0'
|
||||
for i := 0; i < l-1; i++ {
|
||||
bsChr[i+1] = str[i]
|
||||
}
|
||||
}
|
||||
|
||||
bs = make([]byte, l/2)
|
||||
|
||||
pos := 0
|
||||
for i := 0; i < len(bsChr); i += 2 {
|
||||
bt := convertHex(bsChr[i])
|
||||
bt2 := convertHex(bsChr[i+1])
|
||||
if int(bt) == 0xff || int(bt2) == 0xff {
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
|
||||
bs[pos] = byte(bt*16 + bt2)
|
||||
pos++
|
||||
}
|
||||
|
||||
if flag {
|
||||
bs = ([]byte)(str)
|
||||
}
|
||||
|
||||
return bs
|
||||
}
|
||||
|
||||
func convertHex(chr byte) byte {
|
||||
if chr >= '0' && chr <= '9' {
|
||||
return chr - '0'
|
||||
} else if chr >= 'a' && chr <= 'f' {
|
||||
return chr - 'a' + 10
|
||||
} else if chr >= 'A' && chr <= 'F' {
|
||||
return chr - 'A' + 10
|
||||
} else {
|
||||
return 0xff
|
||||
}
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) BytesToHexString(bs []byte, pre bool) string {
|
||||
if bs == nil {
|
||||
return ""
|
||||
}
|
||||
if len(bs) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
hexDigits := "0123456789ABCDEF"
|
||||
ret := new(strings.Builder)
|
||||
for _, b := range bs {
|
||||
ret.WriteByte(hexDigits[0x0F&(b>>4)])
|
||||
ret.WriteByte(hexDigits[0x0F&b])
|
||||
}
|
||||
if pre {
|
||||
return "0x" + ret.String()
|
||||
}
|
||||
return ret.String()
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) ProcessSingleQuoteOfName(name string) string {
|
||||
return StringUtil.processQuoteOfName(name, "'")
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) ProcessDoubleQuoteOfName(name string) string {
|
||||
return StringUtil.processQuoteOfName(name, "\"")
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) processQuoteOfName(name string, quote string) string {
|
||||
if quote == "" || name == "" {
|
||||
return name
|
||||
}
|
||||
|
||||
temp := name
|
||||
result := bytes.NewBufferString("")
|
||||
index := -1
|
||||
quetoLength := len(quote)
|
||||
index = strings.Index(temp, quote)
|
||||
for index != -1 {
|
||||
result.WriteString(temp[:index+quetoLength])
|
||||
result.WriteString(quote)
|
||||
temp = temp[index+quetoLength:]
|
||||
index = strings.Index(temp, quote)
|
||||
}
|
||||
result.WriteString(temp)
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) FormatTime() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func (StringUtil *stringutil) SubstringBetween(str string, open string, close string) string {
|
||||
if str == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
iopen := -1
|
||||
if open != "" {
|
||||
iopen = strings.Index(str, open)
|
||||
}
|
||||
|
||||
iclose := -1
|
||||
if close != "" {
|
||||
iclose = strings.LastIndex(str, close)
|
||||
}
|
||||
|
||||
if iopen == -1 && iclose == -1 {
|
||||
return ""
|
||||
} else if iopen == -1 {
|
||||
return str[0:iclose]
|
||||
} else if iclose == -1 {
|
||||
return str[iopen:]
|
||||
} else {
|
||||
return str[iopen:iclose]
|
||||
}
|
||||
}
|
||||
|
||||
//bug656976 在常量参数化时,将\+任意字符的两个字符解析成一个转义后字符,如:
|
||||
// 字符串参数'a\nb'解析成字符串参数'a换行b'
|
||||
func (StringUtil *stringutil) Translate(s string) string {
|
||||
if !strings.ContainsRune(s, '\\') {
|
||||
return s
|
||||
}
|
||||
reader := strings.NewReader(s)
|
||||
trans := bytes.NewBufferString("")
|
||||
|
||||
for {
|
||||
curRune, _, err := reader.ReadRune()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if curRune != '\\' {
|
||||
trans.WriteRune(curRune)
|
||||
} else {
|
||||
//转义规则参考mysql,'\'作为转义符必须消除,不管是否作为有真正含义的特殊字符,如\x也需要变化为x
|
||||
nextRune, _, err := reader.ReadRune()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
switch nextRune {
|
||||
case 'b':
|
||||
trans.WriteRune('\b')
|
||||
break
|
||||
case 'f':
|
||||
trans.WriteRune('\f')
|
||||
break
|
||||
case 'n':
|
||||
trans.WriteRune('\n')
|
||||
break
|
||||
case 'r':
|
||||
trans.WriteRune('\r')
|
||||
break
|
||||
case 't':
|
||||
trans.WriteRune('\t')
|
||||
break
|
||||
default:
|
||||
trans.WriteRune(nextRune)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return trans.String()
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import "database/sql/driver"
|
||||
|
||||
type DmStruct struct {
|
||||
TypeData
|
||||
m_strctDesc *StructDescriptor // 结构体的描述信息
|
||||
|
||||
m_attribs []TypeData // 各属性值
|
||||
|
||||
m_objCount int // 一个数组项中存在对象类型的个数(class、动态数组)
|
||||
|
||||
m_strCount int // 一个数组项中存在字符串类型的个数
|
||||
|
||||
typeName string
|
||||
|
||||
elements []interface{}
|
||||
|
||||
// Valid为false代表DmArray数据在数据库中为NULL
|
||||
Valid bool
|
||||
}
|
||||
|
||||
// 数据库自定义类型Struct构造函数,typeName为库中定义的类型名称,elements为该类型每个字段的值
|
||||
//
|
||||
// 例如,自定义类型语句为:create or replace type myType as object (a1 int, a2 varchar);
|
||||
//
|
||||
// 则绑入绑出的go对象为: val := dm.NewDmStruct("myType", []interface{} {123, "abc"})
|
||||
func NewDmStruct(typeName string, elements []interface{}) *DmStruct {
|
||||
ds := new(DmStruct)
|
||||
ds.typeName = typeName
|
||||
ds.elements = elements
|
||||
ds.Valid = true
|
||||
return ds
|
||||
}
|
||||
|
||||
func (ds *DmStruct) create(dc *DmConnection) (*DmStruct, error) {
|
||||
desc, err := newStructDescriptor(ds.typeName, dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ds.createByStructDescriptor(desc, dc)
|
||||
}
|
||||
|
||||
func newDmStructByTypeData(atData []TypeData, desc *TypeDescriptor) *DmStruct {
|
||||
ds := new(DmStruct)
|
||||
ds.Valid = true
|
||||
ds.initTypeData()
|
||||
ds.m_strctDesc = newStructDescriptorByTypeDescriptor(desc)
|
||||
ds.m_attribs = atData
|
||||
return ds
|
||||
}
|
||||
|
||||
func (dest *DmStruct) Scan(src interface{}) error {
|
||||
if dest == nil {
|
||||
return ECGO_STORE_IN_NIL_POINTER.throw()
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmStruct)
|
||||
// 将Valid标志置false表示数据库中该列为NULL
|
||||
(*dest).Valid = false
|
||||
return nil
|
||||
case *DmStruct:
|
||||
*dest = *src
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN.throw()
|
||||
}
|
||||
}
|
||||
|
||||
func (dt DmStruct) Value() (driver.Value, error) {
|
||||
if !dt.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return dt, nil
|
||||
}
|
||||
|
||||
func (ds *DmStruct) getAttribsTypeData() []TypeData {
|
||||
return ds.m_attribs
|
||||
}
|
||||
|
||||
func (ds *DmStruct) createByStructDescriptor(desc *StructDescriptor, conn *DmConnection) (*DmStruct, error) {
|
||||
ds.initTypeData()
|
||||
|
||||
if nil == desc {
|
||||
return nil, ECGO_INVALID_PARAMETER_VALUE.throw()
|
||||
}
|
||||
|
||||
ds.m_strctDesc = desc
|
||||
if nil == ds.elements {
|
||||
ds.m_attribs = make([]TypeData, desc.getSize())
|
||||
} else {
|
||||
if desc.getSize() != len(ds.elements) && desc.getObjId() != 4 {
|
||||
return nil, ECGO_STRUCT_MEM_NOT_MATCH.throw()
|
||||
}
|
||||
var err error
|
||||
ds.m_attribs, err = TypeDataSV.toStruct(ds.elements, ds.m_strctDesc.m_typeDesc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
// 获取Struct对象在数据库中的类型名称
|
||||
func (ds *DmStruct) GetSQLTypeName() (string, error) {
|
||||
return ds.m_strctDesc.m_typeDesc.getFulName()
|
||||
}
|
||||
|
||||
// 获取Struct对象中的各个字段的值
|
||||
func (ds *DmStruct) GetAttributes() ([]interface{}, error) {
|
||||
return TypeDataSV.toJavaArrayByDmStruct(ds)
|
||||
}
|
||||
|
||||
func (ds *DmStruct) checkCol(col int) error {
|
||||
if col < 1 || col > len(ds.m_attribs) {
|
||||
return ECGO_INVALID_SEQUENCE_NUMBER.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取指定索引的成员变量值,以TypeData的形式给出,col 1 based
|
||||
func (ds *DmStruct) getAttrValue(col int) (*TypeData, error) {
|
||||
err := ds.checkCol(col)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ds.m_attribs[col-1], nil
|
||||
}
|
||||
|
||||
func (ds *DmStruct) checkValid() error {
|
||||
if !ds.Valid {
|
||||
return ECGO_IS_NULL.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Seconds_1900_1970 = 2209017600
|
||||
|
||||
OFFSET_YEAR = 0
|
||||
|
||||
OFFSET_MONTH = 1
|
||||
|
||||
OFFSET_DAY = 2
|
||||
|
||||
OFFSET_HOUR = 3
|
||||
|
||||
OFFSET_MINUTE = 4
|
||||
|
||||
OFFSET_SECOND = 5
|
||||
|
||||
OFFSET_NANOSECOND = 6
|
||||
|
||||
OFFSET_TIMEZONE = 7
|
||||
|
||||
DT_LEN = 8
|
||||
|
||||
INVALID_VALUE = int(INT32_MIN)
|
||||
|
||||
NANOSECOND_DIGITS = 9
|
||||
|
||||
NANOSECOND_POW = 1000000000
|
||||
)
|
||||
|
||||
type DmTimestamp struct {
|
||||
dt []int
|
||||
dtype int
|
||||
scale int
|
||||
oracleFormatPattern string
|
||||
oracleDateLanguage int
|
||||
|
||||
// Valid为false代表DmArray数据在数据库中为NULL
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func newDmTimestampFromDt(dt []int, dtype int, scale int) *DmTimestamp {
|
||||
dmts := new(DmTimestamp)
|
||||
dmts.Valid = true
|
||||
dmts.dt = dt
|
||||
dmts.dtype = dtype
|
||||
dmts.scale = scale
|
||||
return dmts
|
||||
}
|
||||
|
||||
func newDmTimestampFromBytes(bytes []byte, column column, conn *DmConnection) *DmTimestamp {
|
||||
dmts := new(DmTimestamp)
|
||||
dmts.Valid = true
|
||||
dmts.dt = decode(bytes, column.isBdta, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone))
|
||||
|
||||
if isLocalTimeZone(int(column.colType), int(column.scale)) {
|
||||
dmts.scale = getLocalTimeZoneScale(int(column.colType), int(column.scale))
|
||||
} else {
|
||||
dmts.scale = int(column.scale)
|
||||
}
|
||||
|
||||
dmts.dtype = int(column.colType)
|
||||
dmts.scale = int(column.scale)
|
||||
dmts.oracleDateLanguage = int(conn.OracleDateLanguage)
|
||||
switch column.colType {
|
||||
case DATE:
|
||||
dmts.oracleFormatPattern = conn.FormatDate
|
||||
case TIME:
|
||||
dmts.oracleFormatPattern = conn.FormatTime
|
||||
case TIME_TZ:
|
||||
dmts.oracleFormatPattern = conn.FormatTimeTZ
|
||||
case DATETIME, DATETIME2:
|
||||
dmts.oracleFormatPattern = conn.FormatTimestamp
|
||||
case DATETIME_TZ, DATETIME2_TZ:
|
||||
dmts.oracleFormatPattern = conn.FormatTimestampTZ
|
||||
}
|
||||
return dmts
|
||||
}
|
||||
|
||||
func NewDmTimestampFromString(str string) (*DmTimestamp, error) {
|
||||
dt := make([]int, DT_LEN)
|
||||
dtype, err := toDTFromString(strings.TrimSpace(str), dt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dtype == DATE {
|
||||
return newDmTimestampFromDt(dt, dtype, 0), nil
|
||||
}
|
||||
return newDmTimestampFromDt(dt, dtype, 6), nil
|
||||
}
|
||||
|
||||
func NewDmTimestampFromTime(time time.Time) *DmTimestamp {
|
||||
dt := toDTFromTime(time)
|
||||
return newDmTimestampFromDt(dt, DATETIME, 6)
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) ToTime() time.Time {
|
||||
_, tzs := time.Now().Zone()
|
||||
return toTimeFromDT(dmTimestamp.dt, tzs / 60)
|
||||
}
|
||||
|
||||
// 获取年月日时分秒毫秒时区
|
||||
func (dmTimestamp *DmTimestamp) GetDt() []int {
|
||||
return dmTimestamp.dt
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) CompareTo(ts DmTimestamp) int {
|
||||
if dmTimestamp.ToTime().Equal(ts.ToTime()) {
|
||||
return 0
|
||||
} else if dmTimestamp.ToTime().Before(ts.ToTime()) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) String() string {
|
||||
if dmTimestamp.oracleFormatPattern != "" {
|
||||
return dtToStringByOracleFormat(dmTimestamp.dt, dmTimestamp.oracleFormatPattern, int32(dmTimestamp.scale), dmTimestamp.oracleDateLanguage)
|
||||
}
|
||||
return dtToString(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale)
|
||||
}
|
||||
|
||||
func (dest *DmTimestamp) Scan(src interface{}) error {
|
||||
if dest == nil {
|
||||
return ECGO_STORE_IN_NIL_POINTER.throw()
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
*dest = *new(DmTimestamp)
|
||||
// 将Valid标志置false表示数据库中该列为NULL
|
||||
(*dest).Valid = false
|
||||
return nil
|
||||
case *DmTimestamp:
|
||||
*dest = *src
|
||||
return nil
|
||||
case time.Time:
|
||||
ret := NewDmTimestampFromTime(src)
|
||||
*dest = *ret
|
||||
return nil
|
||||
case string:
|
||||
ret, err := NewDmTimestampFromString(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*dest = *ret
|
||||
return nil
|
||||
default:
|
||||
return UNSUPPORTED_SCAN.throw()
|
||||
}
|
||||
}
|
||||
|
||||
func (dmTimestamp DmTimestamp) Value() (driver.Value, error) {
|
||||
if !dmTimestamp.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return dmTimestamp, nil
|
||||
}
|
||||
|
||||
//func (dmTimestamp *DmTimestamp) toBytes() ([]byte, error) {
|
||||
// return encode(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale, dmTimestamp.dt[OFFSET_TIMEZONE])
|
||||
//}
|
||||
|
||||
/**
|
||||
* 获取当前对象的年月日时分秒,如果原来没有decode会先decode;
|
||||
*/
|
||||
func (dmTimestamp *DmTimestamp) getDt() []int {
|
||||
return dmTimestamp.dt
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) getTime() int64 {
|
||||
_, tzs := time.Now().Zone()
|
||||
sec := toTimeFromDT(dmTimestamp.dt, tzs / 60).Unix()
|
||||
return sec + int64(dmTimestamp.dt[OFFSET_NANOSECOND])
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) setTime(time int64) {
|
||||
timeInMillis := (time / 1000) * 1000
|
||||
nanos := (int64)((time % 1000) * 1000000)
|
||||
if nanos < 0 {
|
||||
nanos = 1000000000 + nanos
|
||||
timeInMillis = (((time / 1000) - 1) * 1000)
|
||||
}
|
||||
dmTimestamp.dt = toDTFromUnix(timeInMillis, nanos)
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) setTimezone(tz int) error {
|
||||
// DM中合法的时区取值范围为-12:59至+14:00
|
||||
if tz <= -13*60 || tz > 14*60 {
|
||||
return ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
dmTimestamp.dt[OFFSET_TIMEZONE] = tz
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) getNano() int64 {
|
||||
return int64(dmTimestamp.dt[OFFSET_NANOSECOND] * 1000)
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) setNano(nano int64) {
|
||||
dmTimestamp.dt[OFFSET_NANOSECOND] = (int)(nano / 1000)
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) string() string {
|
||||
if dmTimestamp.oracleFormatPattern != "" {
|
||||
return dtToStringByOracleFormat(dmTimestamp.dt, dmTimestamp.oracleFormatPattern, int32(dmTimestamp.scale), dmTimestamp.oracleDateLanguage)
|
||||
}
|
||||
return dtToString(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale)
|
||||
}
|
||||
|
||||
func (dmTimestamp *DmTimestamp) checkValid() error {
|
||||
if !dmTimestamp.Valid {
|
||||
return ECGO_IS_NULL.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* for gorm v2 */
|
||||
func (d *DmTimestamp) GormDataType() string {
|
||||
return "TIMESTAMP"
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
STATUS_VALID_TIME = 20 * time.Second // ms
|
||||
|
||||
// sort 值
|
||||
SORT_SERVER_MODE_INVALID = -1 // 不允许连接的模式
|
||||
|
||||
SORT_SERVER_NOT_ALIVE = -2 // 站点无法连接
|
||||
|
||||
SORT_UNKNOWN = INT32_MAX // 站点还未连接过,模式未知
|
||||
|
||||
SORT_NORMAL = 30
|
||||
|
||||
SORT_PRIMARY = 20
|
||||
|
||||
SORT_STANDBY = 10
|
||||
|
||||
// OPEN>MOUNT>SUSPEND
|
||||
SORT_OPEN = 3
|
||||
|
||||
SORT_MOUNT = 2
|
||||
|
||||
SORT_SUSPEND = 1
|
||||
)
|
||||
|
||||
type ep struct {
|
||||
host string
|
||||
port int32
|
||||
alive bool
|
||||
statusRefreshTs int64 // 状态更新的时间点
|
||||
serverMode int32
|
||||
serverStatus int32
|
||||
dscControl bool
|
||||
sort int32
|
||||
epSeqno int32
|
||||
epStatus int32
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func newEP(host string, port int32) *ep {
|
||||
ep := new(ep)
|
||||
ep.host = host
|
||||
ep.port = port
|
||||
ep.serverMode = -1
|
||||
ep.serverStatus = -1
|
||||
ep.sort = SORT_UNKNOWN
|
||||
return ep
|
||||
}
|
||||
|
||||
func (ep *ep) getSort(checkTime bool) int32 {
|
||||
if checkTime {
|
||||
if time.Now().UnixNano()-ep.statusRefreshTs < int64(STATUS_VALID_TIME) {
|
||||
return ep.sort
|
||||
} else {
|
||||
return SORT_UNKNOWN
|
||||
}
|
||||
}
|
||||
return ep.sort
|
||||
}
|
||||
|
||||
func (ep *ep) calcSort(loginMode int32) int32 {
|
||||
var sort int32 = 0
|
||||
switch loginMode {
|
||||
case LOGIN_MODE_PRIMARY_FIRST:
|
||||
{
|
||||
// 主机优先:PRIMARY>NORMAL>STANDBY
|
||||
switch ep.serverMode {
|
||||
case SERVER_MODE_NORMAL:
|
||||
sort += SORT_NORMAL * 10
|
||||
case SERVER_MODE_PRIMARY:
|
||||
sort += SORT_PRIMARY * 100
|
||||
case SERVER_MODE_STANDBY:
|
||||
sort += SORT_STANDBY
|
||||
}
|
||||
}
|
||||
case LOGIN_MODE_STANDBY_FIRST:
|
||||
{
|
||||
// STANDBY优先: STANDBY>PRIMARY>NORMAL
|
||||
switch ep.serverMode {
|
||||
case SERVER_MODE_NORMAL:
|
||||
sort += SORT_NORMAL
|
||||
case SERVER_MODE_PRIMARY:
|
||||
sort += SORT_PRIMARY * 10
|
||||
case SERVER_MODE_STANDBY:
|
||||
sort += SORT_STANDBY * 100
|
||||
}
|
||||
}
|
||||
case LOGIN_MODE_NORMAL_FIRST:
|
||||
{
|
||||
// NORMAL优先: NORMAL>PRIMARY>STANDBY
|
||||
switch ep.serverMode {
|
||||
case SERVER_MODE_STANDBY:
|
||||
sort += SORT_STANDBY
|
||||
case SERVER_MODE_PRIMARY:
|
||||
sort += SORT_PRIMARY * 10
|
||||
case SERVER_MODE_NORMAL:
|
||||
sort += SORT_NORMAL * 100
|
||||
}
|
||||
}
|
||||
case LOGIN_MODE_PRIMARY_ONLY:
|
||||
if ep.serverMode != SERVER_MODE_PRIMARY {
|
||||
return SORT_SERVER_MODE_INVALID
|
||||
}
|
||||
sort += SORT_PRIMARY
|
||||
case LOGIN_MODE_STANDBY_ONLY:
|
||||
if ep.serverMode != SERVER_MODE_STANDBY {
|
||||
return SORT_SERVER_MODE_INVALID
|
||||
}
|
||||
sort += SORT_STANDBY
|
||||
}
|
||||
|
||||
switch ep.serverStatus {
|
||||
case SERVER_STATUS_MOUNT:
|
||||
sort += SORT_MOUNT
|
||||
case SERVER_STATUS_OPEN:
|
||||
sort += SORT_OPEN
|
||||
case SERVER_STATUS_SUSPEND:
|
||||
sort += SORT_SUSPEND
|
||||
}
|
||||
return sort
|
||||
}
|
||||
|
||||
func (ep *ep) refreshStatus(alive bool, conn *DmConnection) {
|
||||
ep.lock.Lock()
|
||||
defer ep.lock.Unlock()
|
||||
ep.alive = alive
|
||||
ep.statusRefreshTs = time.Now().UnixNano()
|
||||
if alive {
|
||||
ep.serverMode = conn.SvrMode
|
||||
ep.serverStatus = conn.SvrStat
|
||||
ep.dscControl = conn.dscControl
|
||||
ep.sort = ep.calcSort(int32(conn.dmConnector.loginMode))
|
||||
} else {
|
||||
ep.serverMode = -1
|
||||
ep.serverStatus = -1
|
||||
ep.dscControl = false
|
||||
ep.sort = SORT_SERVER_NOT_ALIVE
|
||||
}
|
||||
}
|
||||
|
||||
func (ep *ep) connect(connector *DmConnector) (*DmConnection, error) {
|
||||
connector.host = ep.host
|
||||
connector.port = ep.port
|
||||
conn, err := connector.connectSingle(context.Background())
|
||||
if err != nil {
|
||||
ep.refreshStatus(false, conn)
|
||||
return nil, err
|
||||
}
|
||||
ep.refreshStatus(true, conn)
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (ep *ep) getServerStatusDesc(serverStatus int32) string {
|
||||
ret := ""
|
||||
switch ep.serverStatus {
|
||||
case SERVER_STATUS_OPEN:
|
||||
ret = "OPEN"
|
||||
case SERVER_STATUS_MOUNT:
|
||||
ret = "MOUNT"
|
||||
case SERVER_STATUS_SUSPEND:
|
||||
ret = "SUSPEND"
|
||||
default:
|
||||
ret = "UNKNOWN"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ep *ep) getServerModeDesc(serverMode int32) string {
|
||||
ret := ""
|
||||
switch ep.serverMode {
|
||||
case SERVER_MODE_NORMAL:
|
||||
ret = "NORMAL"
|
||||
case SERVER_MODE_PRIMARY:
|
||||
ret = "PRIMARY"
|
||||
case SERVER_MODE_STANDBY:
|
||||
ret = "STANDBY"
|
||||
default:
|
||||
ret = "UNKNOWN"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ep *ep) String() string {
|
||||
dscControl := ")"
|
||||
if ep.dscControl {
|
||||
dscControl = ", DSC CONTROL)"
|
||||
}
|
||||
return strings.TrimSpace(ep.host) + ":" + strconv.Itoa(int(ep.port)) +
|
||||
" (" + ep.getServerModeDesc(ep.serverMode) + ", " + ep.getServerStatusDesc(ep.serverStatus) + dscControl
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
/**
|
||||
* dm_svc.conf中配置的服务名对应的一组实例, 以及相关属性和状态信息
|
||||
*
|
||||
* 需求:
|
||||
* 1. 连接均匀分布在各个节点上
|
||||
* 2. loginMode,loginStatus匹配
|
||||
* 3. 连接异常节点比较耗时,在DB列表中包含异常节点时异常连接尽量靠后,减少对建连接速度的影响
|
||||
*
|
||||
*
|
||||
* DB 连接顺序:
|
||||
* 1. well distribution,每次连接都从列表的下一个节点开始
|
||||
* 2. 用DB sort值按从大到小排序,sort为一个四位数XXXX,个位--serverStatus,十位--serverMode,共 有三种模式,最优先的 *100, 次优先的*10
|
||||
*/
|
||||
type epGroup struct {
|
||||
name string
|
||||
epList []*ep
|
||||
props *Properties
|
||||
epStartPos int32 // wellDistribute 起始位置
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func newEPGroup(name string, serverList []*ep) *epGroup {
|
||||
g := new(epGroup)
|
||||
g.name = name
|
||||
g.epList = serverList
|
||||
if serverList == nil || len(serverList) == 0 {
|
||||
g.epStartPos = -1
|
||||
} else {
|
||||
// 保证进程间均衡,起始位置采用随机值
|
||||
g.epStartPos = rand.Int31n(int32(len(serverList))) - 1
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *epGroup) connect(connector *DmConnector) (*DmConnection, error) {
|
||||
var dbSelector = g.getEPSelector(connector)
|
||||
var ex error = nil
|
||||
// 如果配置了loginMode的主、备等优先策略,而未找到最高优先级的节点时持续循环switchtimes次,如果最终还是没有找到最高优先级则选择次优先级的
|
||||
// 如果只有一个节点,无需switchTimes+1;多个节点时保证switchTimes轮尝试,最后一轮决定用哪个节点(由于节点已经按照模式优先级排序,最后一轮理论上就是连第一个节点)
|
||||
var cycleCount int32
|
||||
if len(g.epList) == 1 {
|
||||
cycleCount = connector.switchTimes
|
||||
} else {
|
||||
cycleCount = connector.switchTimes + 1
|
||||
}
|
||||
for i := int32(0); i < cycleCount; i++ {
|
||||
// 循环了一遍,如果没有符合要求的, 重新排序, 再尝试连接
|
||||
conn, err := g.traverseServerList(connector, dbSelector, i == 0, i == cycleCount-1)
|
||||
if err != nil {
|
||||
ex = err
|
||||
time.Sleep(time.Duration(connector.switchInterval) * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
return nil, ex
|
||||
}
|
||||
|
||||
func (g *epGroup) getEPSelector(connector *DmConnector) *epSelector {
|
||||
if connector.epSelector == TYPE_HEAD_FIRST {
|
||||
return newEPSelector(g.epList)
|
||||
} else {
|
||||
serverCount := int32(len(g.epList))
|
||||
sortEPs := make([]*ep, serverCount)
|
||||
g.lock.Lock()
|
||||
defer g.lock.Unlock()
|
||||
g.epStartPos = (g.epStartPos + 1) % serverCount
|
||||
for i := int32(0); i < serverCount; i++ {
|
||||
sortEPs[i] = g.epList[(i+g.epStartPos)%serverCount]
|
||||
}
|
||||
return newEPSelector(sortEPs)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定编号开始,遍历一遍服务名中的ip列表,只连接指定类型(主机或备机)的ip
|
||||
* @param servers
|
||||
* @param checkTime
|
||||
*
|
||||
* @exception
|
||||
* DBError.ECJDBC_INVALID_SERVER_MODE 有站点的模式不匹配
|
||||
* DBError.ECJDBC_COMMUNITION_ERROR 所有站点都连不上
|
||||
*/
|
||||
func (g *epGroup) traverseServerList(connector *DmConnector, epSelector *epSelector, first bool, last bool) (*DmConnection, error) {
|
||||
epList := epSelector.sortDBList(first)
|
||||
errorMsg := bytes.NewBufferString("")
|
||||
var ex error = nil // 第一个错误
|
||||
for _, server := range epList {
|
||||
conn, err := server.connect(connector)
|
||||
if err != nil {
|
||||
if ex == nil {
|
||||
ex = err
|
||||
}
|
||||
errorMsg.WriteString("[")
|
||||
errorMsg.WriteString(server.String())
|
||||
errorMsg.WriteString("]")
|
||||
errorMsg.WriteString(err.Error())
|
||||
errorMsg.WriteString(util.StringUtil.LineSeparator())
|
||||
continue
|
||||
}
|
||||
valid, err := epSelector.checkServerMode(conn, last)
|
||||
if err != nil {
|
||||
if ex == nil {
|
||||
ex = err
|
||||
}
|
||||
errorMsg.WriteString("[")
|
||||
errorMsg.WriteString(server.String())
|
||||
errorMsg.WriteString("]")
|
||||
errorMsg.WriteString(err.Error())
|
||||
errorMsg.WriteString(util.StringUtil.LineSeparator())
|
||||
continue
|
||||
}
|
||||
if !valid {
|
||||
conn.close()
|
||||
err = ECGO_INVALID_SERVER_MODE.throw()
|
||||
if ex == nil {
|
||||
ex = err
|
||||
}
|
||||
errorMsg.WriteString("[")
|
||||
errorMsg.WriteString(server.String())
|
||||
errorMsg.WriteString("]")
|
||||
errorMsg.WriteString(err.Error())
|
||||
errorMsg.WriteString(util.StringUtil.LineSeparator())
|
||||
continue
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
if ex != nil {
|
||||
return nil, ex
|
||||
}
|
||||
return nil, ECGO_COMMUNITION_ERROR.addDetail(errorMsg.String()).throw()
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import "sort"
|
||||
|
||||
const (
|
||||
TYPE_WELL_DISTRIBUTE = 0
|
||||
TYPE_HEAD_FIRST = 1
|
||||
)
|
||||
|
||||
type epSelector struct {
|
||||
dbs []*ep
|
||||
}
|
||||
|
||||
func newEPSelector(dbs []*ep) *epSelector {
|
||||
return &epSelector{dbs}
|
||||
}
|
||||
|
||||
func (s *epSelector) sortDBList(first bool) []*ep {
|
||||
if !first {
|
||||
// 按sort从大到小排序,相同sort值顺序不变
|
||||
sort.Slice(s.dbs, func(i, j int) bool {
|
||||
return s.dbs[i].getSort(first) > s.dbs[j].getSort(first)
|
||||
})
|
||||
}
|
||||
return s.dbs
|
||||
}
|
||||
|
||||
func (s *epSelector) checkServerMode(conn *DmConnection, last bool) (bool, error) {
|
||||
// 只连dsc control节点
|
||||
if conn.dmConnector.loginDscCtrl && !conn.dscControl {
|
||||
conn.close()
|
||||
return false, ECGO_INVALID_SERVER_MODE.throw()
|
||||
}
|
||||
// 模式不匹配, 这里使用的是连接之前的sort,连接之后server的状态可能发生改变sort也可能改变
|
||||
if conn.dmConnector.loginStatus > 0 && int(conn.SvrStat) != conn.dmConnector.loginStatus {
|
||||
conn.close()
|
||||
return false, ECGO_INVALID_SERVER_MODE.throw()
|
||||
}
|
||||
if last {
|
||||
switch conn.dmConnector.loginMode {
|
||||
case LOGIN_MODE_PRIMARY_ONLY:
|
||||
return conn.SvrMode == SERVER_MODE_PRIMARY, nil
|
||||
case LOGIN_MODE_STANDBY_ONLY:
|
||||
return conn.SvrMode == SERVER_MODE_STANDBY, nil
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
switch conn.dmConnector.loginMode {
|
||||
case LOGIN_MODE_NORMAL_FIRST:
|
||||
return conn.SvrMode == SERVER_MODE_NORMAL, nil
|
||||
case LOGIN_MODE_PRIMARY_FIRST, LOGIN_MODE_PRIMARY_ONLY:
|
||||
return conn.SvrMode == SERVER_MODE_PRIMARY, nil
|
||||
case LOGIN_MODE_STANDBY_FIRST, LOGIN_MODE_STANDBY_ONLY:
|
||||
return conn.SvrMode == SERVER_MODE_STANDBY, nil
|
||||
default:
|
||||
break
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"gitee.com/chunanyong/dm/i18n"
|
||||
)
|
||||
|
||||
// 驱动级错误
|
||||
var (
|
||||
DSN_INVALID_SCHEMA = newDmError(9001, "error.dsn.invalidSchema")
|
||||
UNSUPPORTED_SCAN = newDmError(9002, "error.unsupported.scan")
|
||||
INVALID_PARAMETER_NUMBER = newDmError(9003, "error.invalidParameterNumber")
|
||||
THIRD_PART_CIPHER_INIT_FAILED = newDmError(9004, "error.initThirdPartCipherFailed")
|
||||
ECGO_NOT_QUERY_SQL = newDmError(9005, "error.notQuerySQL")
|
||||
ECGO_NOT_EXEC_SQL = newDmError(9006, "error.notExecSQL")
|
||||
ECGO_UNKOWN_NETWORK = newDmError(9007, "error.unkownNetWork")
|
||||
ECGO_INVALID_CONN = newDmError(9008, "error.invalidConn")
|
||||
ECGO_UNSUPPORTED_INPARAM_TYPE = newDmError(9009, "error.unsupportedInparamType")
|
||||
ECGO_UNSUPPORTED_OUTPARAM_TYPE = newDmError(9010, "error.unsupportedOutparamType")
|
||||
ECGO_STORE_IN_NIL_POINTER = newDmError(9011, "error.storeInNilPointer")
|
||||
ECGO_IS_NULL = newDmError(9012, "error.isNull")
|
||||
DSN_INVALID_FORMAT = newDmError(9001, "error.dsn.invalidFormat")
|
||||
)
|
||||
|
||||
var (
|
||||
ECGO_CONNECTION_SWITCH_FAILED = newDmError(20001, "error.connectionSwitchFailed")
|
||||
ECGO_CONNECTION_SWITCHED = newDmError(20000, "error.connectionSwitched")
|
||||
ECGO_COMMUNITION_ERROR = newDmError(6001, "error.communicationError")
|
||||
ECGO_MSG_CHECK_ERROR = newDmError(6002, "error.msgCheckError")
|
||||
ECGO_INVALID_TIME_INTERVAL = newDmError(6005, "error.invalidTimeInterval")
|
||||
ECGO_UNSUPPORTED_TYPE = newDmError(6006, "error.unsupportedType")
|
||||
ECGO_DATA_CONVERTION_ERROR = newDmError(6007, "error.dataConvertionError")
|
||||
ECGO_INVALID_SQL_TYPE = newDmError(6009, "error.invalidSqlType")
|
||||
ECGO_INVALID_DATETIME_FORMAT = newDmError(6015, "error.invalidDateTimeFormat")
|
||||
ECGO_INVALID_COLUMN_TYPE = newDmError(6016, "error.invalidColumnType")
|
||||
ECGO_RESULTSET_IS_READ_ONLY = newDmError(6029, "error.resultsetInReadOnlyStatus")
|
||||
ECGO_INVALID_SEQUENCE_NUMBER = newDmError(6032, "error.invalidSequenceNumber")
|
||||
ECGO_RESULTSET_CLOSED = newDmError(6034, "errorResultSetColsed")
|
||||
ECGO_STATEMENT_HANDLE_CLOSED = newDmError(6035, "errorStatementHandleClosed")
|
||||
ECGO_INVALID_PARAMETER_VALUE = newDmError(6036, "error.invalidParamterValue")
|
||||
ECGO_INVALID_TRAN_ISOLATION = newDmError(6038, "error.invalidTranIsolation")
|
||||
ECGO_COMMIT_IN_AUTOCOMMIT_MODE = newDmError(6039, "errorCommitInAutoCommitMode")
|
||||
ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE = newDmError(6040, "errorRollbackInAutoCommitMode")
|
||||
ECGO_UNBINDED_PARAMETER = newDmError(6054, "error.unbindedParameter")
|
||||
ECGO_PARAM_COUNT_LIMIT = newDmError(6056, "error.ParamCountLimit")
|
||||
ECGO_INVALID_LENGTH_OR_OFFSET = newDmError(6057, "error.invalidLenOrOffset")
|
||||
ECGO_CONNECTION_CLOSED = newDmError(6060, "error.error.connectionClosedOrNotBuild")
|
||||
ECGO_INTERVAL_OVERFLOW = newDmError(6066, "error.intervalValueOverflow")
|
||||
ECGO_STRING_CUT = newDmError(6067, "error.stringCut")
|
||||
ECGO_INVALID_HEX = newDmError(6068, "error.invalidHex")
|
||||
ECGO_INVALID_CIPHER = newDmError(6069, "error.invalidCipher")
|
||||
ECGO_INVALID_BFILE_STR = newDmError(6070, "error.invalidBFile")
|
||||
ECGO_OSAUTH_ERROR = newDmError(6073, "error.osauthError")
|
||||
ECGO_ERROR_SERVER_VERSION = newDmError(6074, "error.serverVersion")
|
||||
ECGO_USERNAME_TOO_LONG = newDmError(6075, "error.usernameTooLong")
|
||||
ECGO_PASSWORD_TOO_LONG = newDmError(6076, "error.passwordTooLong")
|
||||
ECGO_INVALID_COMPLEX_TYPE_NAME = newDmError(6079, "error.invalidComplexTypeName")
|
||||
ECGO_STRUCT_MEM_NOT_MATCH = newDmError(6080, "error.structMemNotMatch")
|
||||
ECGO_INVALID_OBJ_BLOB = newDmError(6081, "error.invalidObjBlob")
|
||||
ECGO_INVALID_ARRAY_LEN = newDmError(6082, "error.invalidArrayLen")
|
||||
ECGO_INVALID_SERVER_MODE = newDmError(6091, "error.invalidServerMode")
|
||||
ECGO_DATA_TOO_LONG = newDmError(6092, "error.dataTooLong")
|
||||
ECGO_BATCH_ERROR = newDmError(6093, "error.batchError")
|
||||
ECGO_MSG_TOO_LONG = newDmError(6101, "error.msgTooLong")
|
||||
ECGO_INVALID_DATETIME_VALUE = newDmError(6103, "error.invalidDateTimeValue")
|
||||
|
||||
ECGO_INIT_SSL_FAILED = newDmError(20002, "error.SSLInitFailed")
|
||||
ECGO_LOB_FREED = newDmError(20003, "error.LobDataHasFreed")
|
||||
ECGO_FATAL_ERROR = newDmError(20004, "error.fatalError")
|
||||
)
|
||||
|
||||
// Svr Msg Err
|
||||
var (
|
||||
ECGO_DATA_OVERFLOW = newDmError(-6102, "error.dataOverflow")
|
||||
ECGO_DATETIME_OVERFLOW = newDmError(-6112, "error.datetimeOverflow")
|
||||
EC_RN_EXCEED_ROWSET_SIZE = newDmError(-7036, "")
|
||||
EC_BP_WITH_ERROR = newDmError(121, "warning.bpWithErr")
|
||||
)
|
||||
|
||||
type DmError struct {
|
||||
ErrCode int32
|
||||
ErrText string
|
||||
stack []uintptr
|
||||
detail string
|
||||
}
|
||||
|
||||
func newDmError(errCode int32, errText string) *DmError {
|
||||
de := new(DmError)
|
||||
de.ErrCode = errCode
|
||||
de.ErrText = errText
|
||||
de.stack = nil
|
||||
de.detail = ""
|
||||
return de
|
||||
}
|
||||
|
||||
func (dmError *DmError) throw() *DmError {
|
||||
var pcs [32]uintptr
|
||||
n := runtime.Callers(2, pcs[:])
|
||||
dmError.stack = pcs[0:n]
|
||||
return dmError
|
||||
}
|
||||
|
||||
func (dmError *DmError) Stack() string {
|
||||
if dmError == nil || dmError.stack == nil {
|
||||
return ""
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
index := 1
|
||||
space := " "
|
||||
for _, p := range dmError.stack {
|
||||
if fn := runtime.FuncForPC(p - 1); fn != nil {
|
||||
file, line := fn.FileLine(p - 1)
|
||||
buffer.WriteString(fmt.Sprintf(" %d).%s%s\n \t%s:%d\n", index, space, fn.Name(), file, line))
|
||||
index++
|
||||
}
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (dmError *DmError) getErrText() string {
|
||||
return i18n.Get(dmError.ErrText, Locale)
|
||||
}
|
||||
|
||||
func (dmError *DmError) Error() string {
|
||||
return fmt.Sprintf("Error %d: %s", dmError.ErrCode, dmError.getErrText()) + dmError.detail // + "\n" + "stack info:\n" + dmError.Stack()
|
||||
}
|
||||
|
||||
// 扩充ErrText
|
||||
func (dmError *DmError) addDetail(detail string) *DmError {
|
||||
dmError.detail = detail
|
||||
return dmError
|
||||
}
|
||||
func (dmError *DmError) addDetailln(detail string) *DmError {
|
||||
return dmError.addDetail("\n" + detail)
|
||||
}
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
const (
|
||||
PARAM_COUNT_LIMIT int32 = 65536
|
||||
|
||||
IGNORE_TARGET_LENGTH int32 = -1
|
||||
|
||||
IGNORE_TARGET_SCALE int32 = -1
|
||||
|
||||
IGNORE_TARGET_TYPE = INT32_MIN
|
||||
|
||||
TYPE_FLAG_UNKNOWN byte = 0 // 未知类型
|
||||
|
||||
TYPE_FLAG_EXACT byte = 1 // 精确类型
|
||||
|
||||
TYPE_FLAG_RECOMMEND byte = 2 // 推荐类型
|
||||
|
||||
IO_TYPE_UNKNOWN int8 = -1
|
||||
|
||||
IO_TYPE_IN int8 = 0
|
||||
|
||||
IO_TYPE_OUT int8 = 1
|
||||
|
||||
IO_TYPE_INOUT int8 = 2
|
||||
|
||||
MASK_ORACLE_DATE int32 = 1
|
||||
|
||||
MASK_ORACLE_FLOAT int32 = 2
|
||||
|
||||
MASK_BFILE int32 = 3
|
||||
|
||||
MASK_LOCAL_DATETIME int32 = 4
|
||||
)
|
||||
|
||||
type execRetInfo struct {
|
||||
// param
|
||||
outParamDatas [][]byte
|
||||
|
||||
// rs
|
||||
hasResultSet bool
|
||||
|
||||
rsDatas [][][]byte
|
||||
|
||||
rsSizeof int // 结果集数据占用多少空间,(消息中结果集起始位置到 rsCacheOffset
|
||||
// 的空间大小,这和实际的rsDatas占用空间大小有一定出入,这里粗略估算,用于结果集缓存时的空间管理)
|
||||
|
||||
rsCacheOffset int32 // 缓存信息,在响应消息体中的偏移,0表示不存在,仅结果集缓存中可以用
|
||||
|
||||
rsBdta bool
|
||||
|
||||
rsUpdatable bool
|
||||
|
||||
rsRowIds []int64
|
||||
|
||||
// rs cache
|
||||
tbIds []int32
|
||||
|
||||
tbTss []int64
|
||||
|
||||
// print
|
||||
printLen int32
|
||||
|
||||
printMsg string
|
||||
|
||||
// explain
|
||||
explain string
|
||||
|
||||
// 影响行数
|
||||
updateCount int64 // Insert/Update/Delet影响行数, select结果集的总行数
|
||||
|
||||
updateCounts []int64 // 批量影响行数
|
||||
|
||||
// 键
|
||||
rowid int64
|
||||
|
||||
lastInsertId int64
|
||||
|
||||
// other
|
||||
retSqlType int16 // 执行返回的语句类型
|
||||
|
||||
execId int32
|
||||
|
||||
serverParams []parameter
|
||||
|
||||
nativeSQL string
|
||||
}
|
||||
|
||||
type column struct {
|
||||
typeName string
|
||||
|
||||
colType int32
|
||||
|
||||
prec int32
|
||||
|
||||
scale int32
|
||||
|
||||
name string
|
||||
|
||||
tableName string
|
||||
|
||||
schemaName string
|
||||
|
||||
nullable bool
|
||||
|
||||
identity bool
|
||||
|
||||
readonly bool // 是否只读
|
||||
|
||||
baseName string
|
||||
|
||||
// lob info
|
||||
lob bool
|
||||
|
||||
lobTabId int32
|
||||
|
||||
lobColId int16
|
||||
|
||||
// 用于描述ARRAY、STRUCT类型的特有描述信息
|
||||
typeDescriptor *TypeDescriptor
|
||||
|
||||
isBdta bool
|
||||
|
||||
mask int32
|
||||
}
|
||||
|
||||
type parameter struct {
|
||||
column
|
||||
|
||||
typeFlag byte
|
||||
|
||||
ioType int8
|
||||
|
||||
outJType int32
|
||||
|
||||
outScale int32
|
||||
|
||||
outObjectName string
|
||||
|
||||
cursorStmt *DmStatement
|
||||
|
||||
hasDefault bool
|
||||
}
|
||||
|
||||
func (column *column) InitColumn() *column {
|
||||
column.typeName = ""
|
||||
|
||||
column.colType = 0
|
||||
|
||||
column.prec = 0
|
||||
|
||||
column.scale = 0
|
||||
|
||||
column.name = ""
|
||||
|
||||
column.tableName = ""
|
||||
|
||||
column.schemaName = ""
|
||||
|
||||
column.nullable = false
|
||||
|
||||
column.identity = false
|
||||
|
||||
column.readonly = false
|
||||
|
||||
column.baseName = ""
|
||||
|
||||
// lob info
|
||||
column.lob = false
|
||||
|
||||
column.lobTabId = 0
|
||||
|
||||
column.lobColId = 0
|
||||
|
||||
// 用于描述ARRAY、STRUCT类型的特有描述信息
|
||||
column.typeDescriptor = nil
|
||||
|
||||
column.isBdta = false
|
||||
|
||||
return column
|
||||
}
|
||||
|
||||
func (parameter *parameter) InitParameter() *parameter {
|
||||
parameter.InitColumn()
|
||||
|
||||
parameter.typeFlag = TYPE_FLAG_UNKNOWN
|
||||
|
||||
parameter.ioType = IO_TYPE_UNKNOWN
|
||||
|
||||
parameter.outJType = IGNORE_TARGET_TYPE
|
||||
|
||||
parameter.outScale = IGNORE_TARGET_SCALE
|
||||
|
||||
parameter.outObjectName = ""
|
||||
|
||||
parameter.cursorStmt = nil
|
||||
|
||||
return parameter
|
||||
}
|
||||
|
||||
func (parameter *parameter) resetType(colType int32) {
|
||||
parameter.colType = colType
|
||||
parameter.scale = 0
|
||||
switch colType {
|
||||
case BIT, BOOLEAN:
|
||||
parameter.prec = BIT_PREC
|
||||
case TINYINT:
|
||||
parameter.prec = TINYINT_PREC
|
||||
case SMALLINT:
|
||||
parameter.prec = SMALLINT_PREC
|
||||
case INT:
|
||||
parameter.prec = INT_PREC
|
||||
case BIGINT:
|
||||
parameter.prec = BIGINT_PREC
|
||||
case CHAR, VARCHAR, VARCHAR2:
|
||||
parameter.prec = VARCHAR_PREC
|
||||
case CLOB:
|
||||
parameter.prec = CLOB_PREC
|
||||
case BINARY, VARBINARY:
|
||||
parameter.prec = VARBINARY_PREC
|
||||
case BLOB:
|
||||
parameter.prec = BLOB_PREC
|
||||
case DATE:
|
||||
parameter.prec = DATE_PREC
|
||||
case TIME:
|
||||
parameter.prec = TIME_PREC
|
||||
parameter.scale = 6
|
||||
case TIME_TZ:
|
||||
parameter.prec = TIME_TZ_PREC
|
||||
parameter.scale = 6
|
||||
case DATETIME:
|
||||
parameter.prec = DATETIME_PREC
|
||||
parameter.scale = 6
|
||||
case DATETIME_TZ:
|
||||
parameter.prec = DATETIME_TZ_PREC
|
||||
parameter.scale = 6
|
||||
case DATETIME2:
|
||||
parameter.prec = DATETIME2_PREC
|
||||
parameter.scale = 9
|
||||
case DATETIME2_TZ:
|
||||
parameter.prec = DATETIME2_TZ_PREC
|
||||
parameter.scale = 9
|
||||
case REAL,DOUBLE,DECIMAL,INTERVAL_YM,INTERVAL_DT,ARRAY,CLASS,PLTYPE_RECORD,SARRAY:
|
||||
parameter.prec = 0
|
||||
case UNKNOWN, NULL:
|
||||
// UNKNOWN 导致服务器断言 // setNull导致服务器报错“字符转换失败”
|
||||
parameter.colType = VARCHAR
|
||||
parameter.prec = VARCHAR_PREC
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (execInfo *execRetInfo) union(other *execRetInfo, startRow int, count int) {
|
||||
if count == 1 {
|
||||
execInfo.updateCounts[startRow] = other.updateCount
|
||||
} else if execInfo.updateCounts != nil && other.updateCounts != nil{
|
||||
copy(execInfo.updateCounts[startRow:startRow+count], other.updateCounts[0:count])
|
||||
}
|
||||
if execInfo.outParamDatas != nil {
|
||||
execInfo.outParamDatas = append(execInfo.outParamDatas, other.outParamDatas...)
|
||||
}
|
||||
}
|
||||
|
||||
func NewExceInfo() *execRetInfo {
|
||||
|
||||
execInfo := execRetInfo{}
|
||||
|
||||
execInfo.outParamDatas = nil
|
||||
|
||||
execInfo.hasResultSet = false
|
||||
|
||||
execInfo.rsDatas = nil
|
||||
|
||||
execInfo.rsSizeof = 0
|
||||
|
||||
execInfo.rsCacheOffset = 0
|
||||
|
||||
execInfo.rsBdta = false
|
||||
|
||||
execInfo.rsUpdatable = false
|
||||
|
||||
execInfo.rsRowIds = nil
|
||||
|
||||
execInfo.tbIds = nil
|
||||
|
||||
execInfo.tbTss = nil
|
||||
|
||||
execInfo.printLen = 0
|
||||
|
||||
execInfo.printMsg = ""
|
||||
|
||||
execInfo.explain = ""
|
||||
|
||||
execInfo.updateCount = 0
|
||||
|
||||
execInfo.updateCounts = nil
|
||||
|
||||
execInfo.rowid = -1
|
||||
|
||||
execInfo.lastInsertId = 0
|
||||
// other
|
||||
execInfo.retSqlType = -1 // 执行返回的语句类型
|
||||
|
||||
execInfo.execId = 0
|
||||
|
||||
return &execInfo
|
||||
}
|
||||
+444
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"reflect"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type filter interface {
|
||||
DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error)
|
||||
DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error)
|
||||
|
||||
DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error)
|
||||
DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver
|
||||
|
||||
DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error)
|
||||
DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error)
|
||||
DmConnectionCommit(filterChain *filterChain, c *DmConnection) error
|
||||
DmConnectionRollback(filterChain *filterChain, c *DmConnection) error
|
||||
DmConnectionClose(filterChain *filterChain, c *DmConnection) error
|
||||
DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error
|
||||
DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error)
|
||||
DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error)
|
||||
DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error)
|
||||
DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error)
|
||||
DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error)
|
||||
DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error)
|
||||
DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error
|
||||
DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error
|
||||
|
||||
DmStatementClose(filterChain *filterChain, s *DmStatement) error
|
||||
DmStatementNumInput(filterChain *filterChain, s *DmStatement) int
|
||||
DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error)
|
||||
DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error)
|
||||
DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error)
|
||||
DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error)
|
||||
DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error
|
||||
|
||||
DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error)
|
||||
DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error)
|
||||
|
||||
DmRowsColumns(filterChain *filterChain, r *DmRows) []string
|
||||
DmRowsClose(filterChain *filterChain, r *DmRows) error
|
||||
DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error
|
||||
DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool
|
||||
DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error
|
||||
DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type
|
||||
DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string
|
||||
DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool)
|
||||
DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool)
|
||||
DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool)
|
||||
}
|
||||
|
||||
type IDGenerator int64
|
||||
|
||||
var dmDriverIDGenerator = new(IDGenerator)
|
||||
var dmConntorIDGenerator = new(IDGenerator)
|
||||
var dmConnIDGenerator = new(IDGenerator)
|
||||
var dmStmtIDGenerator = new(IDGenerator)
|
||||
var dmResultIDGenerator = new(IDGenerator)
|
||||
var dmRowsIDGenerator = new(IDGenerator)
|
||||
|
||||
func (g *IDGenerator) incrementAndGet() int64 {
|
||||
return atomic.AddInt64((*int64)(g), 1)
|
||||
}
|
||||
|
||||
type RWSiteEnum int
|
||||
|
||||
const (
|
||||
PRIMARY RWSiteEnum = iota
|
||||
STANDBY
|
||||
ANYSITE
|
||||
)
|
||||
|
||||
var (
|
||||
goMapMu sync.RWMutex
|
||||
goMap = make(map[string]goRun, 2)
|
||||
)
|
||||
|
||||
type filterable struct {
|
||||
filterChain *filterChain
|
||||
rwInfo *rwInfo
|
||||
logInfo *logInfo
|
||||
recoverInfo *recoverInfo
|
||||
statInfo *statInfo
|
||||
objId int64
|
||||
idGenerator *IDGenerator
|
||||
}
|
||||
|
||||
func runLog() {
|
||||
goMapMu.Lock()
|
||||
_, ok := goMap["log"]
|
||||
if !ok {
|
||||
goMap["log"] = &logWriter{
|
||||
flushQueue: make(chan []byte, LogFlushQueueSize),
|
||||
date: time.Now().Format("2006-01-02"),
|
||||
logFile: nil,
|
||||
flushFreq: LogFlushFreq,
|
||||
filePath: LogDir,
|
||||
filePrefix: "dm_go",
|
||||
buffer: Dm_build_4(),
|
||||
}
|
||||
go goMap["log"].doRun()
|
||||
}
|
||||
goMapMu.Unlock()
|
||||
}
|
||||
|
||||
func runStat() {
|
||||
goMapMu.Lock()
|
||||
_, ok := goMap["stat"]
|
||||
if !ok {
|
||||
goMap["stat"] = newStatFlusher()
|
||||
go goMap["stat"].doRun()
|
||||
}
|
||||
goMapMu.Unlock()
|
||||
}
|
||||
|
||||
func (f *filterable) createFilterChain(bc *DmConnector, props *Properties) {
|
||||
var filters = make([]filter, 0, 5)
|
||||
|
||||
if bc != nil {
|
||||
if LogLevel != LOG_OFF {
|
||||
filters = append(filters, &logFilter{})
|
||||
f.logInfo = &logInfo{logRecord: new(LogRecord)}
|
||||
runLog()
|
||||
}
|
||||
|
||||
if StatEnable {
|
||||
filters = append(filters, &statFilter{})
|
||||
f.statInfo = newStatInfo()
|
||||
goStatMu.Lock()
|
||||
if goStat == nil {
|
||||
goStat = newGoStat(1000)
|
||||
}
|
||||
goStatMu.Unlock()
|
||||
runStat()
|
||||
}
|
||||
|
||||
if bc.doSwitch != DO_SWITCH_OFF {
|
||||
filters = append(filters, &reconnectFilter{})
|
||||
f.recoverInfo = newRecoverInfo()
|
||||
}
|
||||
|
||||
if bc.rwSeparate > RW_SEPARATE_OFF {
|
||||
filters = append(filters, &rwFilter{})
|
||||
f.rwInfo = newRwInfo()
|
||||
}
|
||||
} else if props != nil {
|
||||
if ParseLogLevel(props) != LOG_OFF {
|
||||
filters = append(filters, &logFilter{})
|
||||
f.logInfo = &logInfo{logRecord: new(LogRecord)}
|
||||
runLog()
|
||||
}
|
||||
|
||||
if props.GetBool("statEnable", StatEnable) {
|
||||
filters = append(filters, &statFilter{})
|
||||
f.statInfo = newStatInfo()
|
||||
goStatMu.Lock()
|
||||
if goStat == nil {
|
||||
goStat = newGoStat(1000)
|
||||
}
|
||||
goStatMu.Unlock()
|
||||
runStat()
|
||||
}
|
||||
|
||||
if props.GetInt(DoSwitchKey, int(DO_SWITCH_OFF), 0, 2) != int(DO_SWITCH_OFF) {
|
||||
filters = append(filters, &reconnectFilter{})
|
||||
f.recoverInfo = newRecoverInfo()
|
||||
}
|
||||
|
||||
if props.GetBool("rwSeparate", false) {
|
||||
filters = append(filters, &rwFilter{})
|
||||
f.rwInfo = newRwInfo()
|
||||
}
|
||||
}
|
||||
|
||||
f.filterChain = newFilterChain(filters)
|
||||
}
|
||||
|
||||
func (f *filterable) resetFilterable(src *filterable) {
|
||||
f.filterChain = src.filterChain
|
||||
f.logInfo = src.logInfo
|
||||
f.rwInfo = src.rwInfo
|
||||
f.statInfo = src.statInfo
|
||||
}
|
||||
|
||||
func (f *filterable) getID() int64 {
|
||||
if f.objId < 0 {
|
||||
f.objId = f.idGenerator.incrementAndGet()
|
||||
}
|
||||
return f.objId
|
||||
}
|
||||
|
||||
type logInfo struct {
|
||||
logRecord *LogRecord
|
||||
lastExecuteStartNano time.Time
|
||||
}
|
||||
|
||||
type rwInfo struct {
|
||||
distribute RWSiteEnum
|
||||
|
||||
rwCounter *rwCounter
|
||||
|
||||
connStandby *DmConnection
|
||||
|
||||
connCurrent *DmConnection
|
||||
|
||||
tryRecoverTs int64
|
||||
|
||||
stmtStandby *DmStatement
|
||||
|
||||
stmtCurrent *DmStatement
|
||||
|
||||
readOnly bool
|
||||
}
|
||||
|
||||
func newRwInfo() *rwInfo {
|
||||
rwInfo := new(rwInfo)
|
||||
rwInfo.distribute = PRIMARY
|
||||
rwInfo.readOnly = true
|
||||
return rwInfo
|
||||
}
|
||||
|
||||
func (rwi *rwInfo) cleanup() {
|
||||
rwi.distribute = PRIMARY
|
||||
rwi.rwCounter = nil
|
||||
rwi.connStandby = nil
|
||||
rwi.connCurrent = nil
|
||||
rwi.stmtStandby = nil
|
||||
rwi.stmtCurrent = nil
|
||||
}
|
||||
|
||||
func (rwi *rwInfo) toPrimary() RWSiteEnum {
|
||||
if rwi.distribute != PRIMARY {
|
||||
|
||||
rwi.rwCounter.countPrimary()
|
||||
}
|
||||
rwi.distribute = PRIMARY
|
||||
return rwi.distribute
|
||||
}
|
||||
|
||||
func (rwi *rwInfo) toAny() RWSiteEnum {
|
||||
|
||||
rwi.distribute = rwi.rwCounter.count(ANYSITE, rwi.connStandby)
|
||||
return rwi.distribute
|
||||
}
|
||||
|
||||
type recoverInfo struct {
|
||||
checkEpRecoverTs int64
|
||||
}
|
||||
|
||||
func newRecoverInfo() *recoverInfo {
|
||||
recoverInfo := new(recoverInfo)
|
||||
recoverInfo.checkEpRecoverTs = 0
|
||||
return recoverInfo
|
||||
}
|
||||
|
||||
type statInfo struct {
|
||||
constructNano int64
|
||||
|
||||
connStat *connectionStat
|
||||
|
||||
lastExecuteStartNano int64
|
||||
|
||||
lastExecuteTimeNano int64
|
||||
|
||||
lastExecuteType ExecuteTypeEnum
|
||||
|
||||
firstResultSet bool
|
||||
|
||||
lastExecuteSql string
|
||||
|
||||
sqlStat *sqlStat
|
||||
|
||||
sql string
|
||||
|
||||
cursorIndex int
|
||||
|
||||
closeCount int
|
||||
|
||||
readStringLength int64
|
||||
|
||||
readBytesLength int64
|
||||
|
||||
openInputStreamCount int
|
||||
|
||||
openReaderCount int
|
||||
}
|
||||
|
||||
var (
|
||||
goStatMu sync.RWMutex
|
||||
goStat *GoStat
|
||||
)
|
||||
|
||||
func newStatInfo() *statInfo {
|
||||
si := new(statInfo)
|
||||
return si
|
||||
}
|
||||
func (si *statInfo) init(conn *DmConnection) {
|
||||
si.connStat = goStat.createConnStat(conn)
|
||||
}
|
||||
|
||||
func (si *statInfo) setConstructNano() {
|
||||
si.constructNano = time.Now().UnixNano()
|
||||
}
|
||||
|
||||
func (si *statInfo) getConstructNano() int64 {
|
||||
return si.constructNano
|
||||
}
|
||||
|
||||
func (si *statInfo) getConnStat() *connectionStat {
|
||||
return si.connStat
|
||||
}
|
||||
|
||||
func (si *statInfo) getLastExecuteStartNano() int64 {
|
||||
return si.lastExecuteStartNano
|
||||
}
|
||||
|
||||
func (si *statInfo) setLastExecuteStartNano(lastExecuteStartNano int64) {
|
||||
si.lastExecuteStartNano = lastExecuteStartNano
|
||||
}
|
||||
|
||||
func (si *statInfo) getLastExecuteTimeNano() int64 {
|
||||
return si.lastExecuteTimeNano
|
||||
}
|
||||
|
||||
func (si *statInfo) setLastExecuteTimeNano(lastExecuteTimeNano int64) {
|
||||
si.lastExecuteTimeNano = lastExecuteTimeNano
|
||||
}
|
||||
|
||||
func (si *statInfo) getLastExecuteType() ExecuteTypeEnum {
|
||||
return si.lastExecuteType
|
||||
}
|
||||
|
||||
func (si *statInfo) setLastExecuteType(lastExecuteType ExecuteTypeEnum) {
|
||||
si.lastExecuteType = lastExecuteType
|
||||
}
|
||||
|
||||
func (si *statInfo) isFirstResultSet() bool {
|
||||
return si.firstResultSet
|
||||
}
|
||||
|
||||
func (si *statInfo) setFirstResultSet(firstResultSet bool) {
|
||||
si.firstResultSet = firstResultSet
|
||||
}
|
||||
|
||||
func (si *statInfo) getLastExecuteSql() string {
|
||||
return si.lastExecuteSql
|
||||
}
|
||||
|
||||
func (si *statInfo) setLastExecuteSql(lastExecuteSql string) {
|
||||
si.lastExecuteSql = lastExecuteSql
|
||||
}
|
||||
|
||||
func (si *statInfo) getSqlStat() *sqlStat {
|
||||
return si.sqlStat
|
||||
}
|
||||
|
||||
func (si *statInfo) setSqlStat(sqlStat *sqlStat) {
|
||||
si.sqlStat = sqlStat
|
||||
}
|
||||
|
||||
func (si *statInfo) setConnStat(connStat *connectionStat) {
|
||||
si.connStat = connStat
|
||||
}
|
||||
|
||||
func (si *statInfo) setConstructNanoWithConstructNano(constructNano int64) {
|
||||
si.constructNano = constructNano
|
||||
}
|
||||
|
||||
func (si *statInfo) afterExecute(nanoSpan int64) {
|
||||
si.lastExecuteTimeNano = nanoSpan
|
||||
}
|
||||
|
||||
func (si *statInfo) beforeExecute() {
|
||||
si.lastExecuteStartNano = time.Now().UnixNano()
|
||||
}
|
||||
|
||||
func (si *statInfo) getSql() string {
|
||||
return si.sql
|
||||
}
|
||||
|
||||
func (si *statInfo) setSql(sql string) {
|
||||
si.sql = sql
|
||||
}
|
||||
|
||||
func (si *statInfo) getCursorIndex() int {
|
||||
return si.cursorIndex
|
||||
}
|
||||
|
||||
func (si *statInfo) setCursorIndex(cursorIndex int) {
|
||||
si.cursorIndex = cursorIndex
|
||||
}
|
||||
|
||||
func (si *statInfo) getCloseCount() int {
|
||||
return si.closeCount
|
||||
}
|
||||
|
||||
func (si *statInfo) setCloseCount(closeCount int) {
|
||||
si.closeCount = closeCount
|
||||
}
|
||||
|
||||
func (si *statInfo) getReadStringLength() int64 {
|
||||
return si.readStringLength
|
||||
}
|
||||
|
||||
func (si *statInfo) setReadStringLength(readStringLength int64) {
|
||||
si.readStringLength = readStringLength
|
||||
}
|
||||
|
||||
func (si *statInfo) getReadBytesLength() int64 {
|
||||
return si.readBytesLength
|
||||
}
|
||||
|
||||
func (si *statInfo) setReadBytesLength(readBytesLength int64) {
|
||||
si.readBytesLength = readBytesLength
|
||||
}
|
||||
|
||||
func (si *statInfo) getOpenInputStreamCount() int {
|
||||
return si.openInputStreamCount
|
||||
}
|
||||
|
||||
func (si *statInfo) setOpenInputStreamCount(openInputStreamCount int) {
|
||||
si.openInputStreamCount = openInputStreamCount
|
||||
}
|
||||
|
||||
func (si *statInfo) getOpenReaderCount() int {
|
||||
return si.openReaderCount
|
||||
}
|
||||
|
||||
func (si *statInfo) setOpenReaderCount(openReaderCount int) {
|
||||
si.openReaderCount = openReaderCount
|
||||
}
|
||||
|
||||
func (si *statInfo) incrementCloseCount() {
|
||||
si.closeCount++
|
||||
}
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type filterChain struct {
|
||||
filters []filter
|
||||
fpos int
|
||||
}
|
||||
|
||||
func newFilterChain(filters []filter) *filterChain {
|
||||
fc := new(filterChain)
|
||||
fc.filters = filters
|
||||
fc.fpos = 0
|
||||
return fc
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) reset() *filterChain {
|
||||
filterChain.fpos = 0
|
||||
return filterChain
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmDriverOpen(d *DmDriver, dsn string) (*DmConnection, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmDriverOpen(filterChain, d, dsn)
|
||||
}
|
||||
|
||||
return d.open(dsn)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmDriverOpenConnector(d *DmDriver, dsn string) (*DmConnector, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmDriverOpenConnector(filterChain, d, dsn)
|
||||
}
|
||||
|
||||
return d.openConnector(dsn)
|
||||
}
|
||||
|
||||
//DmConnector
|
||||
func (filterChain *filterChain) DmConnectorConnect(c *DmConnector, ctx context.Context) (*DmConnection, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectorConnect(filterChain, c, ctx)
|
||||
}
|
||||
|
||||
return c.connect(ctx)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectorDriver(c *DmConnector) *DmDriver {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectorDriver(filterChain, c)
|
||||
}
|
||||
|
||||
return c.driver()
|
||||
}
|
||||
|
||||
//DmConnection
|
||||
func (filterChain *filterChain) DmConnectionBegin(c *DmConnection) (*DmConnection, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionBegin(filterChain, c)
|
||||
}
|
||||
|
||||
return c.begin()
|
||||
}
|
||||
func (filterChain *filterChain) DmConnectionBeginTx(c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionBeginTx(filterChain, c, ctx, opts)
|
||||
}
|
||||
|
||||
return c.beginTx(ctx, opts)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionCommit(c *DmConnection) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionCommit(filterChain, c)
|
||||
}
|
||||
|
||||
return c.commit()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionRollback(c *DmConnection) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionRollback(filterChain, c)
|
||||
}
|
||||
|
||||
return c.rollback()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionClose(c *DmConnection) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionClose(filterChain, c)
|
||||
}
|
||||
|
||||
return c.close()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionPing(c *DmConnection, ctx context.Context) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionPing(filterChain, c, ctx)
|
||||
}
|
||||
|
||||
return c.ping(ctx)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionExec(c *DmConnection, query string, args []driver.Value) (*DmResult, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionExec(filterChain, c, query, args)
|
||||
}
|
||||
|
||||
return c.exec(query, args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionExecContext(c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionExecContext(filterChain, c, ctx, query, args)
|
||||
}
|
||||
|
||||
return c.execContext(ctx, query, args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionQuery(c *DmConnection, query string, args []driver.Value) (*DmRows, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionQuery(filterChain, c, query, args)
|
||||
}
|
||||
|
||||
return c.query(query, args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionQueryContext(c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionQueryContext(filterChain, c, ctx, query, args)
|
||||
}
|
||||
|
||||
return c.queryContext(ctx, query, args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionPrepare(c *DmConnection, query string) (*DmStatement, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionPrepare(filterChain, c, query)
|
||||
}
|
||||
|
||||
return c.prepare(query)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionPrepareContext(c *DmConnection, ctx context.Context, query string) (*DmStatement, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionPrepareContext(filterChain, c, ctx, query)
|
||||
}
|
||||
|
||||
return c.prepareContext(ctx, query)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionResetSession(c *DmConnection, ctx context.Context) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionResetSession(filterChain, c, ctx)
|
||||
}
|
||||
|
||||
return c.resetSession(ctx)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmConnectionCheckNamedValue(c *DmConnection, nv *driver.NamedValue) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmConnectionCheckNamedValue(filterChain, c, nv)
|
||||
}
|
||||
|
||||
return c.checkNamedValue(nv)
|
||||
}
|
||||
|
||||
//DmStatement
|
||||
func (filterChain *filterChain) DmStatementClose(s *DmStatement) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmStatementClose(filterChain, s)
|
||||
}
|
||||
|
||||
return s.close()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmStatementNumInput(s *DmStatement) int {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmStatementNumInput(filterChain, s)
|
||||
}
|
||||
|
||||
return s.numInput()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmStatementExec(s *DmStatement, args []driver.Value) (*DmResult, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmStatementExec(filterChain, s, args)
|
||||
}
|
||||
|
||||
return s.exec(args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmStatementExecContext(s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmStatementExecContext(filterChain, s, ctx, args)
|
||||
}
|
||||
|
||||
return s.execContext(ctx, args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmStatementQuery(s *DmStatement, args []driver.Value) (*DmRows, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmStatementQuery(filterChain, s, args)
|
||||
}
|
||||
|
||||
return s.query(args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmStatementQueryContext(s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmStatementQueryContext(filterChain, s, ctx, args)
|
||||
}
|
||||
|
||||
return s.queryContext(ctx, args)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmStatementCheckNamedValue(s *DmStatement, nv *driver.NamedValue) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmStatementCheckNamedValue(filterChain, s, nv)
|
||||
}
|
||||
|
||||
return s.checkNamedValue(nv)
|
||||
}
|
||||
|
||||
//DmResult
|
||||
func (filterChain *filterChain) DmResultLastInsertId(r *DmResult) (int64, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmResultLastInsertId(filterChain, r)
|
||||
}
|
||||
|
||||
return r.lastInsertId()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmResultRowsAffected(r *DmResult) (int64, error) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmResultRowsAffected(filterChain, r)
|
||||
}
|
||||
|
||||
return r.rowsAffected()
|
||||
}
|
||||
|
||||
//DmRows
|
||||
func (filterChain *filterChain) DmRowsColumns(r *DmRows) []string {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsColumns(filterChain, r)
|
||||
}
|
||||
|
||||
return r.columns()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsClose(r *DmRows) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsClose(filterChain, r)
|
||||
}
|
||||
|
||||
return r.close()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsNext(r *DmRows, dest []driver.Value) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsNext(filterChain, r, dest)
|
||||
}
|
||||
|
||||
return r.next(dest)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsHasNextResultSet(r *DmRows) bool {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsHasNextResultSet(filterChain, r)
|
||||
}
|
||||
|
||||
return r.hasNextResultSet()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsNextResultSet(r *DmRows) error {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsNextResultSet(filterChain, r)
|
||||
}
|
||||
|
||||
return r.nextResultSet()
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsColumnTypeScanType(r *DmRows, index int) reflect.Type {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsColumnTypeScanType(filterChain, r, index)
|
||||
}
|
||||
|
||||
return r.columnTypeScanType(index)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsColumnTypeDatabaseTypeName(r *DmRows, index int) string {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsColumnTypeDatabaseTypeName(filterChain, r, index)
|
||||
}
|
||||
|
||||
return r.columnTypeDatabaseTypeName(index)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsColumnTypeLength(r *DmRows, index int) (length int64, ok bool) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsColumnTypeLength(filterChain, r, index)
|
||||
}
|
||||
|
||||
return r.columnTypeLength(index)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsColumnTypeNullable(r *DmRows, index int) (nullable, ok bool) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsColumnTypeNullable(filterChain, r, index)
|
||||
}
|
||||
|
||||
return r.columnTypeNullable(index)
|
||||
}
|
||||
|
||||
func (filterChain *filterChain) DmRowsColumnTypePrecisionScale(r *DmRows, index int) (precision, scale int64, ok bool) {
|
||||
if filterChain.fpos < len(filterChain.filters) {
|
||||
f := filterChain.filters[filterChain.fpos]
|
||||
filterChain.fpos++
|
||||
return f.DmRowsColumnTypePrecisionScale(filterChain, r, index)
|
||||
}
|
||||
|
||||
return r.columnTypePrecisionScale(index)
|
||||
}
|
||||
+907
@@ -0,0 +1,907 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
type logFilter struct{}
|
||||
|
||||
func (filter *logFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (ret *DmConnection, err error) {
|
||||
var logRecord = d.logInfo.logRecord.Reset()
|
||||
logRecord.Set(d, "open", dsn)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret, err = filterChain.DmDriverOpen(d, dsn)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (ret *DmConnector, err error) {
|
||||
var logRecord = d.logInfo.logRecord.Reset()
|
||||
logRecord.Set(d, "openConnector", dsn)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret, err = filterChain.DmDriverOpenConnector(d, dsn)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (ret *DmConnection, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "connect")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret, err = filterChain.DmConnectorConnect(c, ctx)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) (ret *DmDriver) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "driver")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret = filterChain.DmConnectorDriver(c)
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (ret *DmConnection, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "begin")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret, err = filterChain.DmConnectionBegin(c)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (ret *DmConnection, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "beginTx", opts)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret, err = filterChain.DmConnectionBeginTx(c, ctx, opts)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) (err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "commit")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmConnectionCommit(c)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) (err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "rollback")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmConnectionRollback(c)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) (err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "close")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmConnectionClose(c)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) (err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "ping")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmConnectionPing(c, ctx)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (ret *DmResult, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "exec", convertParams2(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(c.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(query, true)
|
||||
filter.executeBefore(c.logInfo)
|
||||
ret, err = filterChain.DmConnectionExec(c, query, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (ret *DmResult, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "execCtx", convertParams1(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(c.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(query, true)
|
||||
filter.executeBefore(c.logInfo)
|
||||
ret, err = filterChain.DmConnectionExecContext(c, ctx, query, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (ret *DmRows, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "query", convertParams2(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(c.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(query, true)
|
||||
filter.executeBefore(c.logInfo)
|
||||
ret, err = filterChain.DmConnectionQuery(c, query, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (ret *DmRows, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "queryCtx", convertParams1(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(c.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(query, true)
|
||||
filter.executeBefore(c.logInfo)
|
||||
ret, err = filterChain.DmConnectionQueryContext(c, ctx, query, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (ret *DmStatement, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "prepare", query)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(query, false)
|
||||
ret, err = filterChain.DmConnectionPrepare(c, query)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (ret *DmStatement, err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "prepareCtx", query)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(query, false)
|
||||
ret, err = filterChain.DmConnectionPrepareContext(c, ctx, query)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) (err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "resetSession")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmConnectionResetSession(c, ctx)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) (err error) {
|
||||
var logRecord = c.logInfo.logRecord.Reset()
|
||||
logRecord.Set(c, "checkNamedValue", nv.Value)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmConnectionCheckNamedValue(c, nv)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) (err error) {
|
||||
var logRecord = s.logInfo.logRecord.Reset()
|
||||
logRecord.Set(s, "close")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmStatementClose(s)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) (ret int) {
|
||||
var logRecord = s.logInfo.logRecord.Reset()
|
||||
logRecord.Set(s, "numInput")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret = filterChain.DmStatementNumInput(s)
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (ret *DmResult, err error) {
|
||||
var logRecord = s.logInfo.logRecord.Reset()
|
||||
logRecord.Set(s, "exec", convertParams2(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(s.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(s.nativeSql, true)
|
||||
filter.executeBefore(s.logInfo)
|
||||
ret, err = filterChain.DmStatementExec(s, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (ret *DmResult, err error) {
|
||||
var logRecord = s.logInfo.logRecord.Reset()
|
||||
logRecord.Set(s, "execCtx", convertParams1(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(s.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(s.nativeSql, true)
|
||||
filter.executeBefore(s.logInfo)
|
||||
ret, err = filterChain.DmStatementExecContext(s, ctx, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (ret *DmRows, err error) {
|
||||
var logRecord = s.logInfo.logRecord.Reset()
|
||||
logRecord.Set(s, "query", convertParams2(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(s.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(s.nativeSql, true)
|
||||
filter.executeBefore(s.logInfo)
|
||||
ret, err = filterChain.DmStatementQuery(s, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (ret *DmRows, err error) {
|
||||
var logRecord = s.logInfo.logRecord.Reset()
|
||||
logRecord.Set(s, "queryCtx", convertParams1(args)...)
|
||||
defer func() {
|
||||
filter.executeAfter(s.logInfo, logRecord)
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
logRecord.SetSql(s.nativeSql, true)
|
||||
filter.executeBefore(s.logInfo)
|
||||
ret, err = filterChain.DmStatementQueryContext(s, ctx, args)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) (err error) {
|
||||
var logRecord = s.logInfo.logRecord.Reset()
|
||||
logRecord.Set(s, "checkNamedValue", nv.Value)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmStatementCheckNamedValue(s, nv)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (ret int64, err error) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "lastInsertId")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret, err = filterChain.DmResultLastInsertId(r)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (ret int64, err error) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "rowsAffected")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret, err = filterChain.DmResultRowsAffected(r)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) (ret []string) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "columns")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret = filterChain.DmRowsColumns(r)
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsClose(filterChain *filterChain, r *DmRows) (err error) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "close")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmRowsClose(r)
|
||||
if err != nil {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) (err error) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "next", convertParams2(dest)...)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmRowsNext(r, dest)
|
||||
if err != nil && err != io.EOF {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) (ret bool) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "hasNextResultSet")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret = filterChain.DmRowsHasNextResultSet(r)
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) (err error) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "nextResultSet")
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
err = filterChain.DmRowsNextResultSet(r)
|
||||
if err != nil && err != io.EOF {
|
||||
logRecord.SetError(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) (ret reflect.Type) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "columnTypeScanType", index)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret = filterChain.DmRowsColumnTypeScanType(r, index)
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) (ret string) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "columnTypeDatabaseTypeName", index)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
ret = filterChain.DmRowsColumnTypeDatabaseTypeName(r, index)
|
||||
logRecord.SetReturnValue(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "columnTypeLength", index)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
length, ok = filterChain.DmRowsColumnTypeLength(r, index)
|
||||
if ok {
|
||||
logRecord.SetReturnValue(length)
|
||||
} else {
|
||||
logRecord.SetReturnValue(-1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "columnTypeNullable", index)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
nullable, ok = filterChain.DmRowsColumnTypeNullable(r, index)
|
||||
if ok {
|
||||
logRecord.SetReturnValue(nullable)
|
||||
} else {
|
||||
logRecord.SetReturnValue(false)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) {
|
||||
var logRecord = r.logInfo.logRecord.Reset()
|
||||
logRecord.Set(r, "columnTypePrecisionScale", index)
|
||||
defer func() {
|
||||
filter.doLog(logRecord)
|
||||
}()
|
||||
precision, scale, ok = filterChain.DmRowsColumnTypePrecisionScale(r, index)
|
||||
if ok {
|
||||
logRecord.SetReturnValue(strconv.FormatInt(precision, 10) + "&" + strconv.FormatInt(scale, 10))
|
||||
} else {
|
||||
logRecord.SetReturnValue("-1&-1")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (filter *logFilter) executeBefore(logInfo *logInfo) {
|
||||
if LogFilterLogger.IsSqlEnabled() {
|
||||
logInfo.lastExecuteStartNano = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func (filter *logFilter) executeAfter(logInfo *logInfo, record *LogRecord) {
|
||||
if LogFilterLogger.IsSqlEnabled() {
|
||||
record.SetUsedTime(time.Since(logInfo.lastExecuteStartNano))
|
||||
}
|
||||
}
|
||||
|
||||
func (filter *logFilter) doLog(record *LogRecord) {
|
||||
|
||||
if record == nil {
|
||||
return
|
||||
}
|
||||
if record.GetError() != nil {
|
||||
LogFilterLogger.ErrorWithErr(record.ToString(), record.GetError())
|
||||
} else if record.GetSql() != "" && LogFilterLogger.IsSqlEnabled() {
|
||||
LogFilterLogger.Sql(record.ToString())
|
||||
} else {
|
||||
LogFilterLogger.Info(record.ToString())
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************************/
|
||||
type Logger struct {
|
||||
}
|
||||
|
||||
var LogFilterLogger = &Logger{}
|
||||
var ConnLogger = &Logger{}
|
||||
var AccessLogger = &Logger{}
|
||||
|
||||
func (logger Logger) IsDebugEnabled() bool {
|
||||
return LogLevel >= LOG_DEBUG
|
||||
}
|
||||
func (logger Logger) IsErrorEnabled() bool {
|
||||
return LogLevel >= LOG_ERROR
|
||||
}
|
||||
func (logger Logger) IsInfoEnabled() bool {
|
||||
return LogLevel >= LOG_INFO
|
||||
}
|
||||
func (logger Logger) IsWarnEnabled() bool {
|
||||
return LogLevel >= LOG_WARN
|
||||
}
|
||||
func (logger Logger) IsSqlEnabled() bool {
|
||||
return LogLevel >= LOG_SQL
|
||||
}
|
||||
func (logger Logger) Debug(msg string) {
|
||||
if logger.IsDebugEnabled() {
|
||||
logger.println(logger.formatHead("DEBUG") + msg)
|
||||
}
|
||||
}
|
||||
func (logger Logger) DebugWithErr(msg string, err error) {
|
||||
if logger.IsDebugEnabled() {
|
||||
if e, ok := err.(*DmError); ok {
|
||||
logger.println(logger.formatHead("DEBUG") + msg + util.LINE_SEPARATOR + e.Stack())
|
||||
} else {
|
||||
logger.println(logger.formatHead("DEBUG") + msg + util.LINE_SEPARATOR + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
func (logger Logger) Info(msg string) {
|
||||
if logger.IsInfoEnabled() {
|
||||
logger.println(logger.formatHead("INFO ") + msg)
|
||||
}
|
||||
}
|
||||
func (logger Logger) Sql(msg string) {
|
||||
if logger.IsSqlEnabled() {
|
||||
logger.println(logger.formatHead("SQL ") + msg)
|
||||
}
|
||||
}
|
||||
func (logger Logger) Warn(msg string) {
|
||||
if logger.IsWarnEnabled() {
|
||||
logger.println(logger.formatHead("WARN ") + msg)
|
||||
}
|
||||
}
|
||||
func (logger Logger) ErrorWithErr(msg string, err error) {
|
||||
//if e, ok := err.(*DmError); ok {
|
||||
// logger.println(logger.formatHead("ERROR") + msg + util.LINE_SEPARATOR + e.Stack())
|
||||
//} else {
|
||||
logger.println(logger.formatHead("ERROR") + msg + util.LINE_SEPARATOR + err.Error())
|
||||
//}
|
||||
}
|
||||
|
||||
// TODO: 获取goroutine objId
|
||||
func (logger Logger) formatHead(head string) string {
|
||||
// return "[" + head + " - " + StringUtil.formatTime() + "] tid:" + Thread.currentThread().getId();
|
||||
return "[" + head + " - " + util.StringUtil.FormatTime() + "]"
|
||||
}
|
||||
func (logger Logger) println(msg string) {
|
||||
goMap["log"].(*logWriter).WriteLine(msg)
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
func formatSource(source interface{}) string {
|
||||
if source == nil {
|
||||
return ""
|
||||
}
|
||||
var str string
|
||||
switch src := source.(type) {
|
||||
case string:
|
||||
str += src
|
||||
case *DmDriver:
|
||||
str += formatDriver(src)
|
||||
case *DmConnector:
|
||||
str += formatContor(src)
|
||||
case *DmConnection:
|
||||
str += formatConn(src)
|
||||
case *DmStatement:
|
||||
str += formatConn(src.dmConn) + ", "
|
||||
str += formatStmt(src)
|
||||
case *DmResult:
|
||||
str += formatConn(src.dmStmt.dmConn) + ", "
|
||||
str += formatStmt(src.dmStmt) + ", "
|
||||
str += formatRs(src)
|
||||
case *DmRows:
|
||||
str += formatConn(src.CurrentRows.dmStmt.dmConn) + ", "
|
||||
str += formatStmt(src.CurrentRows.dmStmt) + ", "
|
||||
str += formatRows(src)
|
||||
default:
|
||||
str += reflect.TypeOf(src).String() + "@" + reflect.ValueOf(src).Addr().String()
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func formatDriver(driver *DmDriver) string {
|
||||
if driver != nil && driver.logInfo != nil {
|
||||
return "driver-" + strconv.FormatInt(driver.getID(), 10)
|
||||
}
|
||||
return "driver-nil"
|
||||
}
|
||||
|
||||
func formatContor(contor *DmConnector) string {
|
||||
if contor != nil && contor.logInfo != nil {
|
||||
return "contor-" + strconv.FormatInt(contor.getID(), 10)
|
||||
}
|
||||
return "contor-nil"
|
||||
}
|
||||
|
||||
func formatConn(conn *DmConnection) string {
|
||||
if conn != nil && conn.logInfo != nil {
|
||||
return "conn-0x" + strconv.FormatInt(conn.SessionID, 16)
|
||||
}
|
||||
return "conn-nil"
|
||||
}
|
||||
|
||||
func formatStmt(stmt *DmStatement) string {
|
||||
if stmt != nil && stmt.logInfo != nil {
|
||||
return "stmt-" + strconv.Itoa(int(stmt.id))
|
||||
}
|
||||
return "stmt-nil"
|
||||
}
|
||||
|
||||
func formatRs(result *DmResult) string {
|
||||
if result != nil && result.logInfo != nil {
|
||||
return "rs-" + strconv.FormatInt(result.getID(), 10)
|
||||
}
|
||||
return "rs-nil"
|
||||
}
|
||||
|
||||
func formatRows(rows *DmRows) string {
|
||||
if rows != nil && rows.logInfo != nil {
|
||||
return "rows-" + strconv.FormatInt(rows.getID(), 10)
|
||||
}
|
||||
return "rows-nil"
|
||||
}
|
||||
|
||||
func formatTrace(source string, sql string, method string, returnValue interface{}, params ...interface{}) string {
|
||||
var str string
|
||||
if source != "" {
|
||||
str += "{ " + source + " } "
|
||||
}
|
||||
str += method + "("
|
||||
var paramStartIndex = 0
|
||||
if params != nil && len(params) > paramStartIndex {
|
||||
for i := paramStartIndex; i < len(params); i++ {
|
||||
if i != paramStartIndex {
|
||||
str += ", "
|
||||
}
|
||||
if params[i] != nil {
|
||||
str += reflect.TypeOf(params[i]).String()
|
||||
} else {
|
||||
str += "nil"
|
||||
}
|
||||
}
|
||||
}
|
||||
str += ")"
|
||||
if returnValue != nil {
|
||||
str += ": " + formatReturn(returnValue)
|
||||
}
|
||||
str += "; "
|
||||
if params != nil && len(params) > paramStartIndex {
|
||||
str += "[PARAMS]: "
|
||||
for i := paramStartIndex; i < len(params); i++ {
|
||||
if i != 0 {
|
||||
str += ", "
|
||||
}
|
||||
//if s, ok := params[i].(driver.NamedValue); ok {
|
||||
// str += fmt.Sprintf("%v", s.Value)
|
||||
//} else {
|
||||
str += fmt.Sprintf("%v", params[i])
|
||||
//}
|
||||
}
|
||||
str += "; "
|
||||
}
|
||||
|
||||
if sql != "" {
|
||||
str += "[SQL]: " + sql + "; "
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func formatReturn(returnObj interface{}) string {
|
||||
var str string
|
||||
switch o := returnObj.(type) {
|
||||
case *DmConnection:
|
||||
str = formatConn(o)
|
||||
case *DmStatement:
|
||||
str = formatStmt(o)
|
||||
case *DmResult:
|
||||
str = formatRs(o)
|
||||
case *DmRows:
|
||||
str = formatRows(o)
|
||||
case string:
|
||||
str = `"` + o + `"`
|
||||
case nullData:
|
||||
str = "nil"
|
||||
default:
|
||||
str = "unknown"
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func formatUsedTime(duration time.Duration) string {
|
||||
return "[USED TIME]: " + duration.String()
|
||||
}
|
||||
|
||||
/************************************************************************************************************/
|
||||
|
||||
type nullData struct{}
|
||||
|
||||
var null = nullData{}
|
||||
|
||||
type LogRecord struct {
|
||||
source string
|
||||
method string
|
||||
params []interface{}
|
||||
returnValue interface{}
|
||||
e error
|
||||
usedTime time.Duration
|
||||
sql string
|
||||
logSql bool // 是否需要记录sql(exec,query等需要在日志中记录sql语句)
|
||||
}
|
||||
|
||||
func (record *LogRecord) Reset() *LogRecord {
|
||||
record.source = ""
|
||||
record.method = ""
|
||||
record.params = nil
|
||||
record.returnValue = nil
|
||||
record.e = nil
|
||||
record.usedTime = 0
|
||||
record.sql = ""
|
||||
record.logSql = false
|
||||
return record
|
||||
}
|
||||
|
||||
func (record *LogRecord) Set(source interface{}, method string, params ...interface{}) {
|
||||
record.source = formatSource(source)
|
||||
record.method = method
|
||||
record.params = params
|
||||
}
|
||||
|
||||
func (record *LogRecord) SetReturnValue(retValue interface{}) {
|
||||
if retValue == nil {
|
||||
record.returnValue = null
|
||||
} else {
|
||||
record.returnValue = retValue
|
||||
}
|
||||
}
|
||||
|
||||
func (record *LogRecord) GetReturnValue() interface{} {
|
||||
return record.returnValue
|
||||
}
|
||||
|
||||
func (record *LogRecord) SetSql(sql string, logSql bool) {
|
||||
record.sql = sql
|
||||
record.logSql = logSql
|
||||
}
|
||||
|
||||
func (record *LogRecord) GetSql() string {
|
||||
return record.sql
|
||||
}
|
||||
|
||||
func (record *LogRecord) SetUsedTime(usedTime time.Duration) {
|
||||
record.usedTime = usedTime
|
||||
}
|
||||
|
||||
func (record *LogRecord) GetUsedTime() time.Duration {
|
||||
return record.usedTime
|
||||
}
|
||||
|
||||
func (record *LogRecord) SetError(err error) {
|
||||
record.e = err
|
||||
}
|
||||
|
||||
func (record *LogRecord) GetError() error {
|
||||
return record.e
|
||||
}
|
||||
|
||||
func (record *LogRecord) ToString() string {
|
||||
var sql string
|
||||
if record.logSql && record.sql != "" {
|
||||
sql = record.sql
|
||||
}
|
||||
var str string
|
||||
str += formatTrace(record.source, sql, record.method, record.returnValue, record.params...)
|
||||
if record.usedTime > 0 {
|
||||
str += formatUsedTime(record.usedTime)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func convertParams1(args []driver.NamedValue) []interface{} {
|
||||
tmp := make([]interface{}, len(args))
|
||||
for i := 0; i < len(tmp); i++ {
|
||||
tmp[i] = args[i].Value
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
func convertParams2(args []driver.Value) []interface{} {
|
||||
tmp := make([]interface{}, len(args))
|
||||
for i := 0; i < len(tmp); i++ {
|
||||
tmp[i] = args[i]
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
+516
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
const SQL_GET_DSC_EP_SITE = "SELECT " +
|
||||
"dsc.ep_seqno, " +
|
||||
"(CASE mal.MAL_INST_HOST WHEN '' THEN mal.MAL_HOST ELSE mal.MAL_INST_HOST END) as ep_host, " +
|
||||
"dcr.EP_PORT, " +
|
||||
"dsc.EP_STATUS " +
|
||||
"FROM V$DSC_EP_INFO dsc " +
|
||||
"LEFT join V$DM_MAL_INI mal " +
|
||||
"on dsc.EP_NAME = mal.MAL_INST_NAME " +
|
||||
"LEFT join (SELECT grp.GROUP_TYPE GROUP_TYPE, ep.* FROM SYS.\"V$DCR_GROUP\" grp, SYS.\"V$DCR_EP\" ep where grp.GROUP_NAME = ep.GROUP_NAME) dcr " +
|
||||
"on dsc.EP_NAME = dcr.EP_NAME and GROUP_TYPE = 'DB' order by dsc.ep_seqno asc;"
|
||||
|
||||
type reconnectFilter struct {
|
||||
}
|
||||
|
||||
// 一定抛错
|
||||
func (rf *reconnectFilter) autoReconnect(connection *DmConnection, err error) error {
|
||||
if dmErr, ok := err.(*DmError); ok {
|
||||
if dmErr.ErrCode == ECGO_COMMUNITION_ERROR.ErrCode || dmErr.ErrCode == ECGO_CONNECTION_CLOSED.ErrCode {
|
||||
|
||||
if connection.dmConnector.driverReconnect {
|
||||
return rf.reconnect(connection, dmErr.getErrText())
|
||||
} else {
|
||||
connection.Access.Close()
|
||||
connection.closed.Set(true)
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 一定抛错
|
||||
func (rf *reconnectFilter) reconnect(connection *DmConnection, reason string) error {
|
||||
// 读写分离,重连需要处理备机
|
||||
var err error
|
||||
if connection.dmConnector.rwSeparate > RW_SEPARATE_OFF {
|
||||
err = RWUtil.reconnect(connection)
|
||||
} else {
|
||||
err = connection.reconnect()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
connection.closed.Set(true)
|
||||
return ECGO_CONNECTION_SWITCH_FAILED.addDetailln(reason).throw()
|
||||
}
|
||||
|
||||
// 重连成功
|
||||
connection.closed.Set(false)
|
||||
return ECGO_CONNECTION_SWITCHED.addDetailln(reason).throw()
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) loadDscEpSites(conn *DmConnection) []*ep {
|
||||
stmt, rs, err := conn.driverQuery(SQL_GET_DSC_EP_SITE)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer func() {
|
||||
rs.close()
|
||||
stmt.close()
|
||||
}()
|
||||
epList := make([]*ep, 0)
|
||||
dest := make([]driver.Value, 4)
|
||||
for err = rs.next(dest); err != io.EOF; err = rs.next(dest) {
|
||||
ep := newEP(dest[1].(string), dest[2].(int32))
|
||||
ep.epSeqno = dest[0].(int32)
|
||||
if util.StringUtil.EqualsIgnoreCase(dest[3].(string), "OK") {
|
||||
ep.epStatus = EP_STATUS_OK
|
||||
} else {
|
||||
ep.epStatus = EP_STATUS_ERROR
|
||||
}
|
||||
epList = append(epList, ep)
|
||||
}
|
||||
return epList
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) checkAndRecover(conn *DmConnection) error {
|
||||
if conn.dmConnector.doSwitch != DO_SWITCH_WHEN_EP_RECOVER {
|
||||
return nil
|
||||
}
|
||||
// check trx finish
|
||||
if !conn.trxFinish {
|
||||
return nil
|
||||
}
|
||||
var curIndex = conn.getIndexOnEPGroup()
|
||||
if curIndex == 0 || (time.Now().UnixNano()/1000000-conn.recoverInfo.checkEpRecoverTs) < int64(conn.dmConnector.switchInterval) {
|
||||
return nil
|
||||
}
|
||||
// check db recover
|
||||
var dscEps []*ep
|
||||
if conn.dmConnector.cluster == CLUSTER_TYPE_DSC {
|
||||
dscEps = rf.loadDscEpSites(conn)
|
||||
}
|
||||
if dscEps == nil || len(dscEps) == 0 {
|
||||
return nil
|
||||
}
|
||||
var recover = false
|
||||
for _, okEp := range dscEps {
|
||||
if okEp.epStatus != EP_STATUS_OK {
|
||||
continue
|
||||
}
|
||||
for i := int32(0); i < curIndex; i++ {
|
||||
ep := conn.dmConnector.group.epList[i]
|
||||
if okEp.host == ep.host && okEp.port == ep.port {
|
||||
recover = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if recover {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
conn.recoverInfo.checkEpRecoverTs = time.Now().UnixNano() / 1000000
|
||||
if !recover {
|
||||
return nil
|
||||
}
|
||||
|
||||
if conn.dmConnector.driverReconnect {
|
||||
return conn.reconnect()
|
||||
} else {
|
||||
conn.Access.Close()
|
||||
conn.closed.Set(false)
|
||||
return ECGO_CONNECTION_CLOSED.throw()
|
||||
}
|
||||
|
||||
//return driver.ErrBadConn
|
||||
// do reconnect
|
||||
//return conn.reconnect()
|
||||
}
|
||||
|
||||
// DmDriver
|
||||
func (rf *reconnectFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) {
|
||||
return filterChain.DmDriverOpen(d, dsn)
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) {
|
||||
return filterChain.DmDriverOpenConnector(d, dsn)
|
||||
}
|
||||
|
||||
// DmConnector
|
||||
func (rf *reconnectFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) {
|
||||
return filterChain.DmConnectorConnect(c, ctx)
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver {
|
||||
return filterChain.DmConnectorDriver(c)
|
||||
}
|
||||
|
||||
// DmConnection
|
||||
func (rf *reconnectFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) {
|
||||
dc, err := filterChain.DmConnectionBegin(c)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
return dc, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) {
|
||||
dc, err := filterChain.DmConnectionBeginTx(c, ctx, opts)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
return dc, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error {
|
||||
if err := filterChain.DmConnectionCommit(c); err != nil {
|
||||
return rf.autoReconnect(c, err)
|
||||
}
|
||||
if err := rf.checkAndRecover(c); err != nil {
|
||||
return rf.autoReconnect(c, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error {
|
||||
err := filterChain.DmConnectionRollback(c)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error {
|
||||
err := filterChain.DmConnectionClose(c)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error {
|
||||
err := filterChain.DmConnectionPing(c, ctx)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) {
|
||||
if err := rf.checkAndRecover(c); err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
dr, err := filterChain.DmConnectionExec(c, query, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) {
|
||||
if err := rf.checkAndRecover(c); err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
dr, err := filterChain.DmConnectionExecContext(c, ctx, query, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) {
|
||||
if err := rf.checkAndRecover(c); err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
dr, err := filterChain.DmConnectionQuery(c, query, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) {
|
||||
if err := rf.checkAndRecover(c); err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
dr, err := filterChain.DmConnectionQueryContext(c, ctx, query, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) {
|
||||
ds, err := filterChain.DmConnectionPrepare(c, query)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return ds, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) {
|
||||
ds, err := filterChain.DmConnectionPrepareContext(c, ctx, query)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return ds, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error {
|
||||
err := filterChain.DmConnectionResetSession(c, ctx)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error {
|
||||
err := filterChain.DmConnectionCheckNamedValue(c, nv)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(c, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DmStatement
|
||||
func (rf *reconnectFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error {
|
||||
err := filterChain.DmStatementClose(s)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int {
|
||||
var ret int
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(s.dmConn, err.(error))
|
||||
ret = 0
|
||||
}
|
||||
}()
|
||||
ret = filterChain.DmStatementNumInput(s)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) {
|
||||
if err := rf.checkAndRecover(s.dmConn); err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
dr, err := filterChain.DmStatementExec(s, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) {
|
||||
if err := rf.checkAndRecover(s.dmConn); err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
dr, err := filterChain.DmStatementExecContext(s, ctx, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) {
|
||||
if err := rf.checkAndRecover(s.dmConn); err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
dr, err := filterChain.DmStatementQuery(s, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) {
|
||||
if err := rf.checkAndRecover(s.dmConn); err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
dr, err := filterChain.DmStatementQueryContext(s, ctx, args)
|
||||
if err != nil {
|
||||
return nil, rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
|
||||
return dr, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error {
|
||||
err := filterChain.DmStatementCheckNamedValue(s, nv)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(s.dmConn, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DmResult
|
||||
func (rf *reconnectFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) {
|
||||
i, err := filterChain.DmResultLastInsertId(r)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(r.dmStmt.dmConn, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return i, err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) {
|
||||
i, err := filterChain.DmResultRowsAffected(r)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(r.dmStmt.dmConn, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return i, err
|
||||
}
|
||||
|
||||
// DmRows
|
||||
func (rf *reconnectFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string {
|
||||
var ret []string
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error))
|
||||
ret = nil
|
||||
}
|
||||
}()
|
||||
ret = filterChain.DmRowsColumns(r)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error {
|
||||
err := filterChain.DmRowsClose(r)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error {
|
||||
err := filterChain.DmRowsNext(r, dest)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool {
|
||||
var ret bool
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error))
|
||||
ret = false
|
||||
}
|
||||
}()
|
||||
ret = filterChain.DmRowsHasNextResultSet(r)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error {
|
||||
err := filterChain.DmRowsNextResultSet(r)
|
||||
if err != nil {
|
||||
err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type {
|
||||
var ret reflect.Type
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error))
|
||||
ret = scanTypeUnknown
|
||||
}
|
||||
}()
|
||||
ret = filterChain.DmRowsColumnTypeScanType(r, index)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string {
|
||||
var ret string
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error))
|
||||
ret = ""
|
||||
}
|
||||
}()
|
||||
ret = filterChain.DmRowsColumnTypeDatabaseTypeName(r, index)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error))
|
||||
length, ok = 0, false
|
||||
}
|
||||
}()
|
||||
return filterChain.DmRowsColumnTypeLength(r, index)
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error))
|
||||
nullable, ok = false, false
|
||||
}
|
||||
}()
|
||||
return filterChain.DmRowsColumnTypeNullable(r, index)
|
||||
}
|
||||
|
||||
func (rf *reconnectFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error))
|
||||
precision, scale, ok = 0, 0, false
|
||||
}
|
||||
}()
|
||||
return filterChain.DmRowsColumnTypePrecisionScale(r, index)
|
||||
}
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type rwFilter struct {
|
||||
}
|
||||
|
||||
//DmDriver
|
||||
func (rwf *rwFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) {
|
||||
return filterChain.DmDriverOpen(d, dsn)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) {
|
||||
return filterChain.DmDriverOpenConnector(d, dsn)
|
||||
}
|
||||
|
||||
//DmConnector
|
||||
func (rwf *rwFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) {
|
||||
return RWUtil.connect(c, ctx)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver {
|
||||
return filterChain.DmConnectorDriver(c)
|
||||
}
|
||||
|
||||
//DmConnection
|
||||
func (rwf *rwFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) {
|
||||
if RWUtil.isStandbyAlive(c) {
|
||||
_, err := c.rwInfo.connStandby.begin()
|
||||
if err != nil {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
return filterChain.DmConnectionBegin(c)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) {
|
||||
if RWUtil.isStandbyAlive(c) {
|
||||
_, err := c.rwInfo.connStandby.beginTx(ctx, opts)
|
||||
if err != nil {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
return filterChain.DmConnectionBeginTx(c, ctx, opts)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error {
|
||||
if RWUtil.isStandbyAlive(c) {
|
||||
err := c.rwInfo.connStandby.commit()
|
||||
if err != nil {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
return filterChain.DmConnectionCommit(c)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error {
|
||||
if RWUtil.isStandbyAlive(c) {
|
||||
err := c.rwInfo.connStandby.rollback()
|
||||
if err != nil {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
return filterChain.DmConnectionRollback(c)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error {
|
||||
if RWUtil.isStandbyAlive(c) {
|
||||
err := c.rwInfo.connStandby.close()
|
||||
if err != nil {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
return filterChain.DmConnectionClose(c)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error {
|
||||
return filterChain.DmConnectionPing(c, ctx)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) {
|
||||
ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) {
|
||||
return c.rwInfo.connCurrent.exec(query, args)
|
||||
}, func(otherConn *DmConnection) (interface{}, error) {
|
||||
return otherConn.exec(query, args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmResult), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) {
|
||||
ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) {
|
||||
return c.rwInfo.connCurrent.execContext(ctx, query, args)
|
||||
}, func(otherConn *DmConnection) (interface{}, error) {
|
||||
return otherConn.execContext(ctx, query, args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmResult), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) {
|
||||
ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) {
|
||||
return c.rwInfo.connCurrent.query(query, args)
|
||||
}, func(otherConn *DmConnection) (interface{}, error) {
|
||||
return otherConn.query(query, args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmRows), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) {
|
||||
ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) {
|
||||
return c.rwInfo.connCurrent.queryContext(ctx, query, args)
|
||||
}, func(otherConn *DmConnection) (interface{}, error) {
|
||||
return otherConn.queryContext(ctx, query, args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmRows), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) {
|
||||
stmt, err := c.prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.rwInfo.stmtCurrent = stmt
|
||||
stmt.rwInfo.readOnly = RWUtil.checkReadonlyByStmt(stmt)
|
||||
if RWUtil.isCreateStandbyStmt(stmt) {
|
||||
stmt.rwInfo.stmtStandby, err = c.rwInfo.connStandby.prepare(query)
|
||||
if err == nil {
|
||||
stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby
|
||||
} else {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) {
|
||||
stmt, err := c.prepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.rwInfo.stmtCurrent = stmt
|
||||
stmt.rwInfo.readOnly = RWUtil.checkReadonlyByStmt(stmt)
|
||||
if RWUtil.isCreateStandbyStmt(stmt) {
|
||||
stmt.rwInfo.stmtStandby, err = c.rwInfo.connStandby.prepareContext(ctx, query)
|
||||
if err == nil {
|
||||
stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby
|
||||
} else {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error {
|
||||
if RWUtil.isStandbyAlive(c) {
|
||||
err := c.rwInfo.connStandby.resetSession(ctx)
|
||||
if err != nil {
|
||||
RWUtil.afterExceptionOnStandby(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
return filterChain.DmConnectionResetSession(c, ctx)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error {
|
||||
return filterChain.DmConnectionCheckNamedValue(c, nv)
|
||||
}
|
||||
|
||||
//DmStatement
|
||||
func (rwf *rwFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error {
|
||||
if RWUtil.isStandbyStatementValid(s) {
|
||||
err := s.rwInfo.stmtStandby.close()
|
||||
if err != nil {
|
||||
RWUtil.afterExceptionOnStandby(s.dmConn, err)
|
||||
}
|
||||
}
|
||||
|
||||
return filterChain.DmStatementClose(s)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int {
|
||||
return filterChain.DmStatementNumInput(s)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) {
|
||||
ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) {
|
||||
return s.rwInfo.stmtCurrent.exec(args)
|
||||
}, func(otherStmt *DmStatement) (interface{}, error) {
|
||||
return otherStmt.exec(args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmResult), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) {
|
||||
ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) {
|
||||
return s.rwInfo.stmtCurrent.execContext(ctx, args)
|
||||
}, func(otherStmt *DmStatement) (interface{}, error) {
|
||||
return otherStmt.execContext(ctx, args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmResult), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) {
|
||||
ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) {
|
||||
return s.rwInfo.stmtCurrent.query(args)
|
||||
}, func(otherStmt *DmStatement) (interface{}, error) {
|
||||
return otherStmt.query(args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmRows), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) {
|
||||
ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) {
|
||||
return s.rwInfo.stmtCurrent.queryContext(ctx, args)
|
||||
}, func(otherStmt *DmStatement) (interface{}, error) {
|
||||
return otherStmt.queryContext(ctx, args)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret.(*DmRows), nil
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error {
|
||||
return filterChain.DmStatementCheckNamedValue(s, nv)
|
||||
}
|
||||
|
||||
//DmResult
|
||||
func (rwf *rwFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) {
|
||||
return filterChain.DmResultLastInsertId(r)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) {
|
||||
return filterChain.DmResultRowsAffected(r)
|
||||
}
|
||||
|
||||
//DmRows
|
||||
func (rwf *rwFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string {
|
||||
return filterChain.DmRowsColumns(r)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error {
|
||||
return filterChain.DmRowsClose(r)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error {
|
||||
return filterChain.DmRowsNext(r, dest)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool {
|
||||
return filterChain.DmRowsHasNextResultSet(r)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error {
|
||||
return filterChain.DmRowsNextResultSet(r)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type {
|
||||
return filterChain.DmRowsColumnTypeScanType(r, index)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string {
|
||||
return filterChain.DmRowsColumnTypeDatabaseTypeName(r, index)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) {
|
||||
return filterChain.DmRowsColumnTypeLength(r, index)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) {
|
||||
return filterChain.DmRowsColumnTypeNullable(r, index)
|
||||
}
|
||||
|
||||
func (rwf *rwFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) {
|
||||
return filterChain.DmRowsColumnTypePrecisionScale(r, index)
|
||||
}
|
||||
+607
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type statFilter struct {
|
||||
}
|
||||
|
||||
//DmDriver
|
||||
func (sf *statFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) {
|
||||
conn, err := filterChain.DmDriverOpen(d, dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.statInfo.init(conn)
|
||||
conn.statInfo.setConstructNano()
|
||||
conn.statInfo.getConnStat().incrementConn()
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) {
|
||||
return filterChain.DmDriverOpenConnector(d, dsn)
|
||||
}
|
||||
|
||||
//DmConnector
|
||||
func (sf *statFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) {
|
||||
conn, err := filterChain.DmConnectorConnect(c, ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.statInfo.init(conn)
|
||||
conn.statInfo.setConstructNano()
|
||||
conn.statInfo.getConnStat().incrementConn()
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver {
|
||||
return filterChain.DmConnectorDriver(c)
|
||||
}
|
||||
|
||||
//DmConnection
|
||||
func (sf *statFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) {
|
||||
return filterChain.DmConnectionBegin(c)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) {
|
||||
return filterChain.DmConnectionBeginTx(c, ctx, opts)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error {
|
||||
err := filterChain.DmConnectionCommit(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.statInfo.getConnStat().incrementCommitCount()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error {
|
||||
err := filterChain.DmConnectionRollback(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.statInfo.getConnStat().incrementRollbackCount()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error {
|
||||
if !c.closed.IsSet() {
|
||||
c.statInfo.getConnStat().decrementStmtByActiveStmtCount(int64(getActiveStmtCount(c)))
|
||||
c.statInfo.getConnStat().decrementConn()
|
||||
}
|
||||
|
||||
return filterChain.DmConnectionClose(c)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error {
|
||||
return c.ping(ctx)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) {
|
||||
connExecBefore(c, query)
|
||||
dr, err := filterChain.DmConnectionExec(c, query, args)
|
||||
if err != nil {
|
||||
connExecuteErrorAfter(c, args, err)
|
||||
return nil, err
|
||||
}
|
||||
connExecAfter(c, query, args, int(dr.affectedRows))
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) {
|
||||
connExecBefore(c, query)
|
||||
dr, err := filterChain.DmConnectionExecContext(c, ctx, query, args)
|
||||
if err != nil {
|
||||
connExecuteErrorAfter(c, args, err)
|
||||
return nil, err
|
||||
}
|
||||
connExecAfter(c, query, args, int(dr.affectedRows))
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) {
|
||||
connQueryBefore(c, query)
|
||||
dr, err := filterChain.DmConnectionQuery(c, query, args)
|
||||
if err != nil {
|
||||
connExecuteErrorAfter(c, args, err)
|
||||
return nil, err
|
||||
}
|
||||
connQueryAfter(c, query, args, dr)
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) {
|
||||
connQueryBefore(c, query)
|
||||
dr, err := filterChain.DmConnectionQueryContext(c, ctx, query, args)
|
||||
if err != nil {
|
||||
connExecuteErrorAfter(c, args, err)
|
||||
return nil, err
|
||||
}
|
||||
connQueryAfter(c, query, args, dr)
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) {
|
||||
stmt, err := filterChain.DmConnectionPrepare(c, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
statementCreateAfter(c, stmt)
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) {
|
||||
stmt, err := filterChain.DmConnectionPrepareContext(c, ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
statementCreateAfter(c, stmt)
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error {
|
||||
return filterChain.DmConnectionResetSession(c, ctx)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error {
|
||||
return filterChain.DmConnectionCheckNamedValue(c, nv)
|
||||
}
|
||||
|
||||
//DmStatement
|
||||
func (sf *statFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error {
|
||||
if !s.closed {
|
||||
statementCloseBefore(s)
|
||||
}
|
||||
return filterChain.DmStatementClose(s)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int {
|
||||
return filterChain.DmStatementNumInput(s)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) {
|
||||
stmtExecBefore(s)
|
||||
dr, err := filterChain.DmStatementExec(s, args)
|
||||
if err != nil {
|
||||
statementExecuteErrorAfter(s, args, err)
|
||||
return nil, err
|
||||
}
|
||||
stmtExecAfter(s, args, int(dr.affectedRows))
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) {
|
||||
stmtExecBefore(s)
|
||||
dr, err := filterChain.DmStatementExecContext(s, ctx, args)
|
||||
if err != nil {
|
||||
statementExecuteErrorAfter(s, args, err)
|
||||
return nil, err
|
||||
}
|
||||
stmtExecAfter(s, args, int(dr.affectedRows))
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) {
|
||||
stmtQueryBefore(s)
|
||||
dr, err := filterChain.DmStatementQuery(s, args)
|
||||
if err != nil {
|
||||
statementExecuteErrorAfter(s, args, err)
|
||||
return nil, err
|
||||
}
|
||||
stmtQueryAfter(s, args, dr)
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) {
|
||||
stmtQueryBefore(s)
|
||||
dr, err := filterChain.DmStatementQueryContext(s, ctx, args)
|
||||
if err != nil {
|
||||
statementExecuteErrorAfter(s, args, err)
|
||||
return nil, err
|
||||
}
|
||||
stmtQueryAfter(s, args, dr)
|
||||
return dr, nil
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error {
|
||||
return filterChain.DmStatementCheckNamedValue(s, nv)
|
||||
}
|
||||
|
||||
//DmResult
|
||||
func (sf *statFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) {
|
||||
return filterChain.DmResultLastInsertId(r)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) {
|
||||
return filterChain.DmResultRowsAffected(r)
|
||||
}
|
||||
|
||||
//DmRows
|
||||
func (sf *statFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string {
|
||||
return filterChain.DmRowsColumns(r)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error {
|
||||
if !r.CurrentRows.closed {
|
||||
resultSetCloseBefore(r)
|
||||
}
|
||||
return filterChain.DmRowsClose(r)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error {
|
||||
return filterChain.DmRowsNext(r, dest)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool {
|
||||
return filterChain.DmRowsHasNextResultSet(r)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error {
|
||||
return filterChain.DmRowsNextResultSet(r)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type {
|
||||
return filterChain.DmRowsColumnTypeScanType(r, index)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string {
|
||||
return filterChain.DmRowsColumnTypeDatabaseTypeName(r, index)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) {
|
||||
return filterChain.DmRowsColumnTypeLength(r, index)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) {
|
||||
return filterChain.DmRowsColumnTypeNullable(r, index)
|
||||
}
|
||||
|
||||
func (sf *statFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) {
|
||||
return filterChain.DmRowsColumnTypePrecisionScale(r, index)
|
||||
}
|
||||
|
||||
func getActiveStmtCount(conn *DmConnection) int {
|
||||
if conn.stmtMap == nil {
|
||||
return 0
|
||||
} else {
|
||||
return len(conn.stmtMap)
|
||||
}
|
||||
}
|
||||
|
||||
func statementCreateAfter(conn *DmConnection, stmt *DmStatement) {
|
||||
stmt.statInfo.setConstructNano()
|
||||
conn.statInfo.getConnStat().incrementStmt()
|
||||
}
|
||||
|
||||
func connExecBefore(conn *DmConnection, sql string) {
|
||||
conn.statInfo.setLastExecuteSql(sql)
|
||||
conn.statInfo.setFirstResultSet(false)
|
||||
conn.statInfo.setLastExecuteType(ExecuteUpdate)
|
||||
internalBeforeConnExecute(conn, sql)
|
||||
}
|
||||
|
||||
func connExecAfter(conn *DmConnection, sql string, args interface{}, updateCount int) {
|
||||
internalAfterConnExecute(conn, args, updateCount)
|
||||
}
|
||||
|
||||
func connQueryBefore(conn *DmConnection, sql string) {
|
||||
conn.statInfo.setLastExecuteSql(sql)
|
||||
conn.statInfo.setFirstResultSet(true)
|
||||
conn.statInfo.setLastExecuteType(ExecuteQuery)
|
||||
internalBeforeConnExecute(conn, sql)
|
||||
}
|
||||
|
||||
func connQueryAfter(conn *DmConnection, sql string, args interface{}, resultSet *DmRows) {
|
||||
if resultSet != nil {
|
||||
connResultSetCreateAfter(resultSet, conn)
|
||||
}
|
||||
internalAfterConnExecute(conn, args, 0)
|
||||
}
|
||||
|
||||
func stmtExecBefore(stmt *DmStatement) {
|
||||
stmt.statInfo.setLastExecuteSql(stmt.nativeSql)
|
||||
stmt.statInfo.setFirstResultSet(false)
|
||||
stmt.statInfo.setLastExecuteType(ExecuteUpdate)
|
||||
internalBeforeStatementExecute(stmt, stmt.nativeSql)
|
||||
}
|
||||
|
||||
func stmtExecAfter(stmt *DmStatement, args interface{}, updateCount int) {
|
||||
internalAfterStatementExecute(stmt, args, updateCount)
|
||||
}
|
||||
|
||||
func stmtQueryBefore(stmt *DmStatement) {
|
||||
stmt.statInfo.setLastExecuteSql(stmt.nativeSql)
|
||||
stmt.statInfo.setFirstResultSet(true)
|
||||
stmt.statInfo.setLastExecuteType(ExecuteQuery)
|
||||
internalBeforeStatementExecute(stmt, stmt.nativeSql)
|
||||
}
|
||||
|
||||
func stmtQueryAfter(stmt *DmStatement, args interface{}, resultSet *DmRows) {
|
||||
if resultSet != nil {
|
||||
stmtResultSetCreateAfter(resultSet, stmt)
|
||||
}
|
||||
internalAfterStatementExecute(stmt, args, 0)
|
||||
}
|
||||
|
||||
func internalBeforeConnExecute(conn *DmConnection, sql string) {
|
||||
connStat := conn.statInfo.getConnStat()
|
||||
connStat.incrementExecuteCount()
|
||||
conn.statInfo.beforeExecute()
|
||||
|
||||
sqlStat := conn.statInfo.getSqlStat()
|
||||
if sqlStat == nil || sqlStat.Removed == 1 || !(sqlStat.Sql == sql) {
|
||||
sqlStat = connStat.createSqlStat(sql)
|
||||
conn.statInfo.setSqlStat(sqlStat)
|
||||
}
|
||||
|
||||
inTransaction := false
|
||||
inTransaction = !conn.autoCommit
|
||||
|
||||
if sqlStat != nil {
|
||||
sqlStat.ExecuteLastStartTime = time.Now().UnixNano()
|
||||
sqlStat.incrementRunningCount()
|
||||
|
||||
if inTransaction {
|
||||
sqlStat.incrementInTransactionCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func internalAfterConnExecute(conn *DmConnection, args interface{}, updateCount int) {
|
||||
nowNano := time.Now().UnixNano()
|
||||
nanos := nowNano - conn.statInfo.getLastExecuteStartNano()
|
||||
|
||||
conn.statInfo.afterExecute(nanos)
|
||||
|
||||
sqlStat := conn.statInfo.getSqlStat()
|
||||
|
||||
if sqlStat != nil {
|
||||
sqlStat.incrementExecuteSuccessCount()
|
||||
|
||||
sqlStat.decrementRunningCount()
|
||||
|
||||
parameters := buildSlowParameters(args)
|
||||
|
||||
sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(conn.statInfo.getLastExecuteType(), conn.statInfo.isFirstResultSet(),
|
||||
nanos, parameters)
|
||||
|
||||
if !conn.statInfo.isFirstResultSet() &&
|
||||
conn.statInfo.getLastExecuteType() == ExecuteUpdate {
|
||||
if updateCount < 0 {
|
||||
updateCount = 0
|
||||
}
|
||||
sqlStat.addUpdateCount(int64(updateCount))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func internalBeforeStatementExecute(stmt *DmStatement, sql string) {
|
||||
connStat := stmt.dmConn.statInfo.getConnStat()
|
||||
connStat.incrementExecuteCount()
|
||||
stmt.statInfo.beforeExecute()
|
||||
|
||||
sqlStat := stmt.statInfo.getSqlStat()
|
||||
if sqlStat == nil || sqlStat.Removed == 1 || !(sqlStat.Sql == sql) {
|
||||
sqlStat = connStat.createSqlStat(sql)
|
||||
stmt.statInfo.setSqlStat(sqlStat)
|
||||
}
|
||||
|
||||
inTransaction := false
|
||||
inTransaction = !stmt.dmConn.autoCommit
|
||||
|
||||
if sqlStat != nil {
|
||||
sqlStat.ExecuteLastStartTime = time.Now().UnixNano()
|
||||
sqlStat.incrementRunningCount()
|
||||
|
||||
if inTransaction {
|
||||
sqlStat.incrementInTransactionCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func internalAfterStatementExecute(stmt *DmStatement, args interface{}, updateCount int) {
|
||||
nowNano := time.Now().UnixNano()
|
||||
nanos := nowNano - stmt.statInfo.getLastExecuteStartNano()
|
||||
|
||||
stmt.statInfo.afterExecute(nanos)
|
||||
|
||||
sqlStat := stmt.statInfo.getSqlStat()
|
||||
|
||||
if sqlStat != nil {
|
||||
sqlStat.incrementExecuteSuccessCount()
|
||||
|
||||
sqlStat.decrementRunningCount()
|
||||
|
||||
parameters := ""
|
||||
if stmt.paramCount > 0 {
|
||||
parameters = buildStmtSlowParameters(stmt, args)
|
||||
}
|
||||
sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(stmt.statInfo.getLastExecuteType(), stmt.statInfo.isFirstResultSet(),
|
||||
nanos, parameters)
|
||||
|
||||
if (!stmt.statInfo.isFirstResultSet()) &&
|
||||
stmt.statInfo.getLastExecuteType() == ExecuteUpdate {
|
||||
updateCount := stmt.execInfo.updateCount
|
||||
if updateCount < 0 {
|
||||
updateCount = 0
|
||||
}
|
||||
sqlStat.addUpdateCount(updateCount)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func buildSlowParameters(args interface{}) string {
|
||||
switch v := args.(type) {
|
||||
case []driver.Value:
|
||||
sb := bytes.NewBufferString("")
|
||||
for i := 0; i < len(v); i++ {
|
||||
if i != 0 {
|
||||
sb.WriteString(",")
|
||||
} else {
|
||||
sb.WriteString("[")
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprint(v[i]))
|
||||
}
|
||||
|
||||
if len(v) > 0 {
|
||||
sb.WriteString("]")
|
||||
}
|
||||
return sb.String()
|
||||
case []driver.NamedValue:
|
||||
sb := bytes.NewBufferString("")
|
||||
for i := 0; i < len(v); i++ {
|
||||
if i != 0 {
|
||||
sb.WriteString(",")
|
||||
} else {
|
||||
sb.WriteString("[")
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprint(v[i]))
|
||||
}
|
||||
if len(v) > 0 {
|
||||
sb.WriteString("]")
|
||||
}
|
||||
return sb.String()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func buildStmtSlowParameters(stmt *DmStatement, args interface{}) string {
|
||||
switch v := args.(type) {
|
||||
case []driver.Value:
|
||||
sb := bytes.NewBufferString("")
|
||||
for i := 0; i < int(stmt.paramCount); i++ {
|
||||
if i != 0 {
|
||||
sb.WriteString(",")
|
||||
} else {
|
||||
sb.WriteString("[")
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprint(v[i]))
|
||||
}
|
||||
if len(v) > 0 {
|
||||
sb.WriteString("]")
|
||||
}
|
||||
return sb.String()
|
||||
case []driver.NamedValue:
|
||||
sb := bytes.NewBufferString("")
|
||||
for i := 0; i < int(stmt.paramCount); i++ {
|
||||
if i != 0 {
|
||||
sb.WriteString(",")
|
||||
} else {
|
||||
sb.WriteString("[")
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprint(v[i]))
|
||||
}
|
||||
if len(v) > 0 {
|
||||
sb.WriteString("]")
|
||||
}
|
||||
return sb.String()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func connExecuteErrorAfter(conn *DmConnection, args interface{}, err error) {
|
||||
nanos := time.Now().UnixNano() - conn.statInfo.getLastExecuteStartNano()
|
||||
conn.statInfo.getConnStat().incrementErrorCount()
|
||||
conn.statInfo.afterExecute(nanos)
|
||||
|
||||
// SQL
|
||||
sqlStat := conn.statInfo.getSqlStat()
|
||||
if sqlStat != nil {
|
||||
sqlStat.decrementRunningCount()
|
||||
sqlStat.error(err)
|
||||
parameters := buildSlowParameters(args)
|
||||
sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(conn.statInfo.getLastExecuteType(), conn.statInfo.isFirstResultSet(),
|
||||
nanos, parameters)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func statementExecuteErrorAfter(stmt *DmStatement, args interface{}, err error) {
|
||||
nanos := time.Now().UnixNano() - stmt.statInfo.getLastExecuteStartNano()
|
||||
stmt.dmConn.statInfo.getConnStat().incrementErrorCount()
|
||||
stmt.statInfo.afterExecute(nanos)
|
||||
|
||||
// SQL
|
||||
sqlStat := stmt.statInfo.getSqlStat()
|
||||
if sqlStat != nil {
|
||||
sqlStat.decrementRunningCount()
|
||||
sqlStat.error(err)
|
||||
parameters := ""
|
||||
if stmt.paramCount > 0 {
|
||||
parameters = buildStmtSlowParameters(stmt, args)
|
||||
}
|
||||
sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(stmt.statInfo.getLastExecuteType(), stmt.statInfo.isFirstResultSet(),
|
||||
nanos, parameters)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func statementCloseBefore(stmt *DmStatement) {
|
||||
stmt.dmConn.statInfo.getConnStat().decrementStmt()
|
||||
}
|
||||
|
||||
func connResultSetCreateAfter(dmdbResultSet *DmRows, conn *DmConnection) {
|
||||
dmdbResultSet.statInfo.setSql(conn.statInfo.getLastExecuteSql())
|
||||
dmdbResultSet.statInfo.setSqlStat(conn.statInfo.getSqlStat())
|
||||
dmdbResultSet.statInfo.setConstructNano()
|
||||
}
|
||||
|
||||
func stmtResultSetCreateAfter(dmdbResultSet *DmRows, stmt *DmStatement) {
|
||||
dmdbResultSet.statInfo.setSql(stmt.statInfo.getLastExecuteSql())
|
||||
dmdbResultSet.statInfo.setSqlStat(stmt.statInfo.getSqlStat())
|
||||
dmdbResultSet.statInfo.setConstructNano()
|
||||
}
|
||||
|
||||
func resultSetCloseBefore(resultSet *DmRows) {
|
||||
nanos := time.Now().UnixNano() - resultSet.statInfo.getConstructNano()
|
||||
fetchRowCount := getFetchedRows(resultSet)
|
||||
sqlStat := resultSet.statInfo.getSqlStat()
|
||||
if sqlStat != nil && resultSet.statInfo.getCloseCount() == 0 {
|
||||
sqlStat.addFetchRowCount(fetchRowCount)
|
||||
stmtExecuteNano := resultSet.statInfo.getLastExecuteTimeNano()
|
||||
sqlStat.addResultSetHoldTimeNano2(stmtExecuteNano, nanos)
|
||||
if resultSet.statInfo.getReadStringLength() > 0 {
|
||||
sqlStat.addStringReadLength(resultSet.statInfo.getReadStringLength())
|
||||
}
|
||||
if resultSet.statInfo.getReadBytesLength() > 0 {
|
||||
sqlStat.addReadBytesLength(resultSet.statInfo.getReadBytesLength())
|
||||
}
|
||||
if resultSet.statInfo.getOpenInputStreamCount() > 0 {
|
||||
sqlStat.addInputStreamOpenCount(int64(resultSet.statInfo.getOpenInputStreamCount()))
|
||||
}
|
||||
if resultSet.statInfo.getOpenReaderCount() > 0 {
|
||||
sqlStat.addReaderOpenCount(int64(resultSet.statInfo.getOpenReaderCount()))
|
||||
}
|
||||
}
|
||||
|
||||
resultSet.statInfo.incrementCloseCount()
|
||||
}
|
||||
|
||||
func getFetchedRows(rs *DmRows) int64 {
|
||||
if rs.CurrentRows.currentPos >= rs.CurrentRows.totalRowCount {
|
||||
return rs.CurrentRows.totalRowCount
|
||||
} else {
|
||||
return rs.CurrentRows.currentPos + 1
|
||||
}
|
||||
}
|
||||
+1017
File diff suppressed because it is too large
Load Diff
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
const (
|
||||
LOB_FLAG_BYTE = 0
|
||||
LOB_FLAG_CHAR = 1
|
||||
|
||||
LOB_IN_ROW = 0x1
|
||||
LOB_OFF_ROW = 0x2
|
||||
|
||||
NBLOB_HEAD_IN_ROW_FLAG = 0
|
||||
NBLOB_HEAD_BLOBID = NBLOB_HEAD_IN_ROW_FLAG + BYTE_SIZE
|
||||
NBLOB_HEAD_BLOB_LEN = NBLOB_HEAD_BLOBID + DDWORD_SIZE
|
||||
|
||||
NBLOB_HEAD_OUTROW_GROUPID = NBLOB_HEAD_BLOB_LEN + ULINT_SIZE
|
||||
NBLOB_HEAD_OUTROW_FILEID = NBLOB_HEAD_OUTROW_GROUPID + USINT_SIZE
|
||||
NBLOB_HEAD_OUTROW_PAGENO = NBLOB_HEAD_OUTROW_FILEID + USINT_SIZE
|
||||
|
||||
NBLOB_EX_HEAD_TABLE_ID = NBLOB_HEAD_OUTROW_PAGENO + ULINT_SIZE
|
||||
NBLOB_EX_HEAD_COL_ID = NBLOB_EX_HEAD_TABLE_ID + ULINT_SIZE
|
||||
NBLOB_EX_HEAD_ROW_ID = NBLOB_EX_HEAD_COL_ID + USINT_SIZE
|
||||
NBLOB_EX_HEAD_FPA_GRPID = NBLOB_EX_HEAD_ROW_ID + LINT64_SIZE
|
||||
NBLOB_EX_HEAD_FPA_FILEID = NBLOB_EX_HEAD_FPA_GRPID + USINT_SIZE
|
||||
NBLOB_EX_HEAD_FPA_PAGENO = NBLOB_EX_HEAD_FPA_FILEID + USINT_SIZE
|
||||
NBLOB_EX_HEAD_SIZE = NBLOB_EX_HEAD_FPA_PAGENO + ULINT_SIZE
|
||||
|
||||
NBLOB_OUTROW_HEAD_SIZE = NBLOB_HEAD_OUTROW_PAGENO + ULINT_SIZE
|
||||
|
||||
NBLOB_INROW_HEAD_SIZE = NBLOB_HEAD_BLOB_LEN + ULINT_SIZE
|
||||
)
|
||||
|
||||
type lob struct {
|
||||
blobId int64
|
||||
inRow bool
|
||||
|
||||
groupId int16
|
||||
fileId int16
|
||||
pageNo int32
|
||||
tabId int32
|
||||
colId int16
|
||||
rowId int64
|
||||
exGroupId int16
|
||||
exFileId int16
|
||||
exPageNo int32
|
||||
|
||||
curFileId int16
|
||||
curPageNo int32
|
||||
curPageOffset int16
|
||||
totalOffset int32
|
||||
readOver bool
|
||||
|
||||
connection *DmConnection
|
||||
local bool
|
||||
updateable bool
|
||||
lobFlag int8
|
||||
length int64
|
||||
compatibleOracle bool
|
||||
fetchAll bool
|
||||
freed bool
|
||||
modify bool
|
||||
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (lob *lob) GetLength() (int64, error) {
|
||||
var err error
|
||||
if err = lob.checkValid(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if err = lob.checkFreed(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if lob.length == -1 {
|
||||
|
||||
if lob.length, err = lob.connection.Access.dm_build_585(lob); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
return lob.length, nil
|
||||
}
|
||||
|
||||
func (lob *lob) resetCurrentInfo() {
|
||||
lob.curFileId = lob.fileId
|
||||
lob.curPageNo = lob.pageNo
|
||||
lob.totalOffset = 0
|
||||
lob.curPageOffset = 0
|
||||
}
|
||||
|
||||
func (lob *lob) getLengthFromHead(head []byte) int64 {
|
||||
return int64(Dm_build_1346.Dm_build_1448(head, NBLOB_HEAD_BLOB_LEN))
|
||||
}
|
||||
|
||||
func (lob *lob) canOptimized(connection *DmConnection) bool {
|
||||
return !(lob.inRow || lob.fetchAll || lob.local || connection != lob.connection)
|
||||
}
|
||||
|
||||
func (lob *lob) buildCtlData() (bytes []byte) {
|
||||
if lob.connection.NewLobFlag {
|
||||
bytes = make([]byte, NBLOB_EX_HEAD_SIZE, NBLOB_EX_HEAD_SIZE)
|
||||
} else {
|
||||
bytes = make([]byte, NBLOB_OUTROW_HEAD_SIZE, NBLOB_OUTROW_HEAD_SIZE)
|
||||
}
|
||||
Dm_build_1346.Dm_build_1347(bytes, NBLOB_HEAD_IN_ROW_FLAG, LOB_OFF_ROW)
|
||||
Dm_build_1346.Dm_build_1367(bytes, NBLOB_HEAD_BLOBID, lob.blobId)
|
||||
Dm_build_1346.Dm_build_1362(bytes, NBLOB_HEAD_BLOB_LEN, -1)
|
||||
|
||||
Dm_build_1346.Dm_build_1357(bytes, NBLOB_HEAD_OUTROW_GROUPID, lob.groupId)
|
||||
Dm_build_1346.Dm_build_1357(bytes, NBLOB_HEAD_OUTROW_FILEID, lob.fileId)
|
||||
Dm_build_1346.Dm_build_1362(bytes, NBLOB_HEAD_OUTROW_PAGENO, lob.pageNo)
|
||||
|
||||
if lob.connection.NewLobFlag {
|
||||
Dm_build_1346.Dm_build_1362(bytes, NBLOB_EX_HEAD_TABLE_ID, lob.tabId)
|
||||
Dm_build_1346.Dm_build_1357(bytes, NBLOB_EX_HEAD_COL_ID, lob.colId)
|
||||
Dm_build_1346.Dm_build_1367(bytes, NBLOB_EX_HEAD_ROW_ID, lob.rowId)
|
||||
Dm_build_1346.Dm_build_1357(bytes, NBLOB_EX_HEAD_FPA_GRPID, lob.exGroupId)
|
||||
Dm_build_1346.Dm_build_1357(bytes, NBLOB_EX_HEAD_FPA_FILEID, lob.exFileId)
|
||||
Dm_build_1346.Dm_build_1362(bytes, NBLOB_EX_HEAD_FPA_PAGENO, lob.exPageNo)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (lob *lob) checkFreed() (err error) {
|
||||
if lob.freed {
|
||||
err = ECGO_LOB_FREED.throw()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (lob *lob) checkValid() error {
|
||||
if !lob.Valid {
|
||||
return ECGO_IS_NULL.throw()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
const (
|
||||
ParamDataEnum_Null = 0
|
||||
/**
|
||||
* 只有大字段才有行内数据、行外数据的概念
|
||||
*/
|
||||
ParamDataEnum_OFF_ROW = 1
|
||||
)
|
||||
|
||||
// JDBC中的Data
|
||||
type lobCtl struct {
|
||||
value []byte
|
||||
}
|
||||
|
||||
// lob数据返回信息,自bug610335后,服务器不光返回字节数组,还返回字符数
|
||||
type lobRetInfo struct {
|
||||
charLen int64 // 字符长度
|
||||
data []byte //lob数据
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
const (
|
||||
MAX_FILE_SIZE = 100 * 1024 * 1024
|
||||
FLUSH_SIZE = 32 * 1024
|
||||
)
|
||||
|
||||
type goRun interface {
|
||||
doRun()
|
||||
}
|
||||
|
||||
type logWriter struct {
|
||||
flushQueue chan []byte
|
||||
date string
|
||||
logFile *os.File
|
||||
flushFreq int
|
||||
filePath string
|
||||
filePrefix string
|
||||
buffer *Dm_build_0
|
||||
}
|
||||
|
||||
func (lw *logWriter) doRun() {
|
||||
defer func() {
|
||||
lw.beforeExit()
|
||||
lw.closeCurrentFile()
|
||||
}()
|
||||
|
||||
i := 0
|
||||
for {
|
||||
var ibytes []byte
|
||||
|
||||
select {
|
||||
case ibytes = <-lw.flushQueue:
|
||||
if LogLevel != LOG_OFF {
|
||||
if i == LogFlushQueueSize {
|
||||
lw.doFlush(lw.buffer)
|
||||
i = 0
|
||||
} else {
|
||||
lw.buffer.Dm_build_26(ibytes, 0, len(ibytes))
|
||||
i++
|
||||
}
|
||||
}
|
||||
case <-time.After(time.Duration(LogFlushFreq) * time.Millisecond):
|
||||
if LogLevel != LOG_OFF && lw.buffer.Dm_build_5() > 0 {
|
||||
lw.doFlush(lw.buffer)
|
||||
i = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (lw *logWriter) doFlush(buffer *Dm_build_0) {
|
||||
if lw.needCreateNewFile() {
|
||||
lw.closeCurrentFile()
|
||||
lw.logFile = lw.createNewFile()
|
||||
}
|
||||
if lw.logFile != nil {
|
||||
buffer.Dm_build_20(lw.logFile, buffer.Dm_build_5())
|
||||
}
|
||||
}
|
||||
func (lw *logWriter) closeCurrentFile() {
|
||||
if lw.logFile != nil {
|
||||
lw.logFile.Close()
|
||||
lw.logFile = nil
|
||||
}
|
||||
}
|
||||
func (lw *logWriter) createNewFile() *os.File {
|
||||
lw.date = time.Now().Format("2006-01-02")
|
||||
fileName := lw.filePrefix + "_" + lw.date + "_" + strconv.Itoa(time.Now().Nanosecond()) + ".log"
|
||||
lw.filePath = LogDir
|
||||
if len(lw.filePath) > 0 {
|
||||
if _, err := os.Stat(lw.filePath); err != nil {
|
||||
os.MkdirAll(lw.filePath, 0755)
|
||||
}
|
||||
if _, err := os.Stat(lw.filePath + fileName); err != nil {
|
||||
logFile, err := os.Create(lw.filePath + fileName)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
return logFile
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (lw *logWriter) needCreateNewFile() bool {
|
||||
now := time.Now().Format("2006-01-02")
|
||||
fileInfo, err := lw.logFile.Stat()
|
||||
return now != lw.date || err != nil || lw.logFile == nil || fileInfo.Size() > int64(MAX_FILE_SIZE)
|
||||
}
|
||||
func (lw *logWriter) beforeExit() {
|
||||
close(lw.flushQueue)
|
||||
var ibytes []byte
|
||||
for ibytes = <-lw.flushQueue; ibytes != nil; ibytes = <-lw.flushQueue {
|
||||
lw.buffer.Dm_build_26(ibytes, 0, len(ibytes))
|
||||
if lw.buffer.Dm_build_5() >= LogBufferSize {
|
||||
lw.doFlush(lw.buffer)
|
||||
}
|
||||
}
|
||||
if lw.buffer.Dm_build_5() > 0 {
|
||||
lw.doFlush(lw.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func (lw *logWriter) WriteLine(msg string) {
|
||||
var b = []byte(strings.TrimSpace(msg) + util.LINE_SEPARATOR)
|
||||
lw.flushQueue <- b
|
||||
}
|
||||
+2944
File diff suppressed because it is too large
Load Diff
+205
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
READ_LEN = Dm_build_820
|
||||
)
|
||||
|
||||
type iOffRowBinder interface {
|
||||
read(buf *Dm_build_0)
|
||||
isReadOver() bool
|
||||
getObj() interface{}
|
||||
}
|
||||
|
||||
type offRowBinder struct {
|
||||
obj interface{}
|
||||
encoding string
|
||||
readOver bool
|
||||
buffer *Dm_build_0
|
||||
position int32
|
||||
offRow bool
|
||||
targetLength int64
|
||||
}
|
||||
|
||||
func newOffRowBinder(obj interface{}, encoding string, targetLength int64) *offRowBinder {
|
||||
return &offRowBinder{
|
||||
obj: obj,
|
||||
encoding: encoding,
|
||||
targetLength: targetLength,
|
||||
readOver: false,
|
||||
buffer: Dm_build_4(),
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
type offRowBytesBinder struct {
|
||||
*offRowBinder
|
||||
}
|
||||
|
||||
func newOffRowBytesBinder(obj []byte, encoding string) *offRowBytesBinder {
|
||||
var binder = &offRowBytesBinder{
|
||||
newOffRowBinder(obj, encoding, int64(IGNORE_TARGET_LENGTH)),
|
||||
}
|
||||
binder.read(binder.buffer)
|
||||
binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817
|
||||
return binder
|
||||
}
|
||||
|
||||
func (b *offRowBytesBinder) read(buf *Dm_build_0) {
|
||||
if b.buffer.Dm_build_5() > 0 {
|
||||
buf.Dm_build_37(b.buffer)
|
||||
} else if !b.readOver {
|
||||
var obj = b.obj.([]byte)
|
||||
buf.Dm_build_26(obj, 0, len(obj))
|
||||
b.readOver = true
|
||||
}
|
||||
}
|
||||
|
||||
func (b *offRowBytesBinder) isReadOver() bool {
|
||||
return b.readOver
|
||||
}
|
||||
|
||||
func (b *offRowBytesBinder) getObj() interface{} {
|
||||
return b.obj
|
||||
}
|
||||
|
||||
type offRowBlobBinder struct {
|
||||
*offRowBinder
|
||||
}
|
||||
|
||||
func newOffRowBlobBinder(blob DmBlob, encoding string) *offRowBlobBinder {
|
||||
var binder = &offRowBlobBinder{
|
||||
newOffRowBinder(blob, encoding, int64(IGNORE_TARGET_LENGTH)),
|
||||
}
|
||||
binder.read(binder.buffer)
|
||||
binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817
|
||||
return binder
|
||||
}
|
||||
|
||||
func (b *offRowBlobBinder) read(buf *Dm_build_0) {
|
||||
if b.buffer.Dm_build_5() > 0 {
|
||||
buf.Dm_build_37(b.buffer)
|
||||
} else if !b.readOver {
|
||||
var obj = b.obj.(DmBlob)
|
||||
var totalLen, _ = obj.GetLength()
|
||||
var leaveLen = totalLen - int64(b.position)
|
||||
var readLen = int32(leaveLen)
|
||||
if leaveLen > READ_LEN {
|
||||
readLen = READ_LEN
|
||||
}
|
||||
var bytes, _ = obj.getBytes(int64(b.position)+1, readLen)
|
||||
b.position += readLen
|
||||
if b.position == int32(totalLen) {
|
||||
b.readOver = true
|
||||
}
|
||||
buf.Dm_build_26(bytes, 0, len(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *offRowBlobBinder) isReadOver() bool {
|
||||
return b.readOver
|
||||
}
|
||||
|
||||
func (b *offRowBlobBinder) getObj() interface{} {
|
||||
return b.obj
|
||||
}
|
||||
|
||||
type offRowClobBinder struct {
|
||||
*offRowBinder
|
||||
}
|
||||
|
||||
func newOffRowClobBinder(clob DmClob, encoding string) *offRowClobBinder {
|
||||
var binder = &offRowClobBinder{
|
||||
newOffRowBinder(clob, encoding, int64(IGNORE_TARGET_LENGTH)),
|
||||
}
|
||||
binder.read(binder.buffer)
|
||||
binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817
|
||||
return binder
|
||||
}
|
||||
|
||||
func (b *offRowClobBinder) read(buf *Dm_build_0) {
|
||||
if b.buffer.Dm_build_5() > 0 {
|
||||
buf.Dm_build_37(b.buffer)
|
||||
} else if !b.readOver {
|
||||
var obj = b.obj.(DmClob)
|
||||
var totalLen, _ = obj.GetLength()
|
||||
var leaveLen = totalLen - int64(b.position)
|
||||
var readLen = int32(leaveLen)
|
||||
if leaveLen > READ_LEN {
|
||||
readLen = READ_LEN
|
||||
}
|
||||
var str, _ = obj.getSubString(int64(b.position)+1, readLen)
|
||||
var bytes = Dm_build_1346.Dm_build_1562(str, b.encoding, nil)
|
||||
b.position += readLen
|
||||
if b.position == int32(totalLen) {
|
||||
b.readOver = true
|
||||
}
|
||||
buf.Dm_build_26(bytes, 0, len(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *offRowClobBinder) isReadOver() bool {
|
||||
return b.readOver
|
||||
}
|
||||
|
||||
func (b *offRowClobBinder) getObj() interface{} {
|
||||
return b.obj
|
||||
}
|
||||
|
||||
type offRowReaderBinder struct {
|
||||
*offRowBinder
|
||||
}
|
||||
|
||||
func newOffRowReaderBinder(reader io.Reader, encoding string) *offRowReaderBinder {
|
||||
var binder = &offRowReaderBinder{
|
||||
newOffRowBinder(reader, encoding, int64(IGNORE_TARGET_LENGTH)),
|
||||
}
|
||||
binder.read(binder.buffer)
|
||||
binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817
|
||||
return binder
|
||||
}
|
||||
|
||||
func (b *offRowReaderBinder) read(buf *Dm_build_0) {
|
||||
if b.buffer.Dm_build_5() > 0 {
|
||||
buf.Dm_build_37(b.buffer)
|
||||
} else if !b.readOver {
|
||||
var err error
|
||||
var readLen = READ_LEN
|
||||
var reader = b.obj.(io.Reader)
|
||||
var bytes = make([]byte, readLen)
|
||||
readLen, err = reader.Read(bytes)
|
||||
if err == io.EOF {
|
||||
b.readOver = true
|
||||
return
|
||||
}
|
||||
b.position += int32(readLen)
|
||||
if readLen < len(bytes) || b.targetLength != int64(IGNORE_TARGET_LENGTH) && int64(b.position) == b.targetLength {
|
||||
b.readOver = true
|
||||
}
|
||||
buf.Dm_build_26(bytes[0:readLen], 0, readLen)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *offRowReaderBinder) readAll() []byte {
|
||||
var byteArray = Dm_build_4()
|
||||
b.read(byteArray)
|
||||
for !b.readOver {
|
||||
b.read(byteArray)
|
||||
}
|
||||
return byteArray.Dm_build_47()
|
||||
}
|
||||
|
||||
func (b *offRowReaderBinder) isReadOver() bool {
|
||||
return b.readOver
|
||||
}
|
||||
|
||||
func (b *offRowReaderBinder) getObj() interface{} {
|
||||
return b.obj
|
||||
}
|
||||
+882
@@ -0,0 +1,882 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
type oracleDateFormat struct {
|
||||
PM bool
|
||||
TZNegative bool
|
||||
pattern string
|
||||
language int
|
||||
scale int32
|
||||
FormatElementList []interface{}
|
||||
YearElement yearElement
|
||||
MonthElement monthElement
|
||||
MonElement monElement
|
||||
MMElement mmElement
|
||||
DDElement ddElement
|
||||
HH24Element hh24Element
|
||||
HH12Element hh12Element
|
||||
MIElement miElement
|
||||
SSElement ssElement
|
||||
FElement fElement
|
||||
TZHElement tzhElement
|
||||
TZMElement tzmElement
|
||||
AMElement amElement
|
||||
}
|
||||
|
||||
type element interface {
|
||||
/**
|
||||
* 从字符串中解析出对应的值,
|
||||
* @param str 完整的字符串
|
||||
* @param offset 当前偏移
|
||||
* @return 解析后的offset
|
||||
*/
|
||||
parse(str string, offset int, dt []int) (int, error)
|
||||
|
||||
/**
|
||||
* 将时间值value格式化成字符串
|
||||
*/
|
||||
format(dt []int) string
|
||||
}
|
||||
|
||||
type yearElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
len int
|
||||
}
|
||||
|
||||
func (YearElement yearElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
for i := offset; i < offset+YearElement.len && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
if YearElement.len < 4 {
|
||||
today := strconv.FormatInt(int64(dt[OFFSET_YEAR]), 10)
|
||||
i, err := strconv.ParseInt(today[:4-YearElement.len]+str, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dt[OFFSET_YEAR] = int(i)
|
||||
} else {
|
||||
i, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dt[OFFSET_YEAR] = int(i)
|
||||
}
|
||||
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (YearElement yearElement) format(dt []int) string {
|
||||
return YearElement.OracleDateFormat.formatInt(dt[OFFSET_YEAR], YearElement.len)
|
||||
}
|
||||
|
||||
type monthElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
upperCase bool
|
||||
lowerCase bool
|
||||
}
|
||||
|
||||
var monthNameList = []string{"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
|
||||
|
||||
func (MonthElement monthElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
|
||||
if MonthElement.OracleDateFormat.language == LANGUAGE_CN {
|
||||
index := strings.IndexRune(str[offset:], '月')
|
||||
if index == -1 {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
index += offset
|
||||
|
||||
mon, err := strconv.ParseInt(str[offset:index], 10, 32)
|
||||
if err != nil {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
|
||||
if mon > 12 || mon < 1 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_MONTH] = int(mon)
|
||||
return index + utf8.RuneLen('月'), nil
|
||||
} else {
|
||||
str = str[offset:]
|
||||
mon := 0
|
||||
for i := 1; i < len(monthNameList); i++ {
|
||||
if util.StringUtil.StartWithIgnoreCase(str, monthNameList[i]) {
|
||||
mon = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if mon == 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
dt[OFFSET_MONTH] = mon
|
||||
return offset + len(monthNameList[mon]), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (MonthElement monthElement) format(dt []int) string {
|
||||
value := dt[OFFSET_MONTH]
|
||||
|
||||
if MonthElement.OracleDateFormat.language == LANGUAGE_CN {
|
||||
return strconv.FormatInt(int64(value), 10) + "月"
|
||||
}
|
||||
|
||||
if MonthElement.upperCase {
|
||||
return strings.ToUpper(monthNameList[value])
|
||||
} else if MonthElement.lowerCase {
|
||||
return strings.ToLower(monthNameList[value])
|
||||
} else {
|
||||
return monthNameList[value]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type monElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
upperCase bool
|
||||
lowerCase bool
|
||||
}
|
||||
|
||||
var monNameList []string = []string{"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
|
||||
|
||||
func (MonElement monElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
|
||||
if MonElement.OracleDateFormat.language == LANGUAGE_CN {
|
||||
index := strings.IndexRune(str[offset:], '月') + offset
|
||||
if index == -1+offset {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
|
||||
mon, err := strconv.ParseInt(str[offset:index], 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if mon > 12 || mon < 1 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_MONTH] = int(mon)
|
||||
return index + utf8.RuneLen('月'), nil
|
||||
} else {
|
||||
str = str[offset : offset+3]
|
||||
mon := 0
|
||||
for i := 1; i < len(monNameList); i++ {
|
||||
if util.StringUtil.EqualsIgnoreCase(str, monNameList[i]) {
|
||||
mon = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if mon == 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
dt[OFFSET_MONTH] = mon
|
||||
return offset + 3, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (MonElement monElement) format(dt []int) string {
|
||||
value := dt[OFFSET_MONTH]
|
||||
language := int(0)
|
||||
if language == LANGUAGE_CN {
|
||||
return strconv.FormatInt(int64(value), 10) + "月"
|
||||
}
|
||||
|
||||
if MonElement.upperCase {
|
||||
return strings.ToUpper(monNameList[value])
|
||||
} else if MonElement.lowerCase {
|
||||
return strings.ToLower(monNameList[value])
|
||||
} else {
|
||||
return monNameList[value]
|
||||
}
|
||||
}
|
||||
|
||||
type mmElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (MMElement mmElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
month, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
|
||||
if month > 12 || month < 1 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_MONTH] = int(month)
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (MMElement mmElement) format(dt []int) string {
|
||||
return MMElement.OracleDateFormat.formatInt(dt[OFFSET_MONTH], 2)
|
||||
}
|
||||
|
||||
type ddElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (DDElement ddElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
day, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if day > 31 || day < 1 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_DAY] = int(day)
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (DDElement ddElement) format(dt []int) string {
|
||||
return DDElement.OracleDateFormat.formatInt(dt[OFFSET_DAY], 2)
|
||||
}
|
||||
|
||||
type hh24Element struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (HH24Element hh24Element) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
hour, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if hour > 23 || hour < 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_HOUR] = int(hour) // 0-23
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (HH24Element hh24Element) format(dt []int) string {
|
||||
return HH24Element.OracleDateFormat.formatInt(dt[OFFSET_HOUR], 2) // 0-23
|
||||
}
|
||||
|
||||
type hh12Element struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (HH12Element hh12Element) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
hour, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if hour > 12 || hour < 1 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_HOUR] = int(hour)
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (HH12Element hh12Element) format(dt []int) string {
|
||||
var ret string
|
||||
value := dt[OFFSET_HOUR]
|
||||
if value > 12 || value == 0 {
|
||||
ret = HH12Element.OracleDateFormat.formatInt(int(math.Abs(float64(value-12))), 2) // 1-12
|
||||
} else {
|
||||
ret = HH12Element.OracleDateFormat.formatInt(value, 2)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type miElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (MIElement miElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
minute, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if minute > 59 || minute < 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_MINUTE] = int(minute) // 0-59
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (MIElement miElement) format(dt []int) string {
|
||||
return MIElement.OracleDateFormat.formatInt(dt[OFFSET_MINUTE], 2) // 0-59
|
||||
}
|
||||
|
||||
type ssElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (SSElement ssElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
second, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if second > 59 || second < 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
dt[OFFSET_SECOND] = int(second) // 0-59
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (SSElement ssElement) format(dt []int) string {
|
||||
return SSElement.OracleDateFormat.formatInt(dt[OFFSET_SECOND], 2) // 0-59
|
||||
}
|
||||
|
||||
type fElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
len int
|
||||
}
|
||||
|
||||
func (FElement fElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
strLen := 0
|
||||
maxLen := 0
|
||||
if FElement.len > 0 {
|
||||
maxLen = FElement.len
|
||||
} else {
|
||||
maxLen = NANOSECOND_DIGITS
|
||||
}
|
||||
for i := offset; i < offset+maxLen && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
ms, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if strLen < NANOSECOND_DIGITS {
|
||||
ms *= int64(math.Pow10(NANOSECOND_DIGITS - strLen))
|
||||
} else {
|
||||
ms /= int64(math.Pow10(strLen - NANOSECOND_DIGITS))
|
||||
}
|
||||
|
||||
dt[OFFSET_NANOSECOND] = int(ms)
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (FElement fElement) format(dt []int) string {
|
||||
msgLen := 0
|
||||
if FElement.len > 0 {
|
||||
msgLen = FElement.len
|
||||
} else {
|
||||
msgLen = int(FElement.OracleDateFormat.scale)
|
||||
}
|
||||
return FElement.OracleDateFormat.formatMilliSecond(dt[OFFSET_NANOSECOND], msgLen)
|
||||
}
|
||||
|
||||
type tzhElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (TZHElement tzhElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
if str[offset] == '+' {
|
||||
offset += 1
|
||||
} else if str[offset] == '-' {
|
||||
offset += 1
|
||||
TZHElement.OracleDateFormat.TZNegative = true
|
||||
}
|
||||
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
|
||||
tzh, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if tzh > 23 || tzh < 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
|
||||
tzh *= 60
|
||||
if dt[OFFSET_TIMEZONE] == int(INVALID_VALUE) {
|
||||
dt[OFFSET_TIMEZONE] = int(tzh)
|
||||
} else {
|
||||
dt[OFFSET_TIMEZONE] += int(tzh)
|
||||
}
|
||||
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (TZHElement tzhElement) format(dt []int) string {
|
||||
var value int
|
||||
if dt[OFFSET_TIMEZONE] != int(INVALID_VALUE) {
|
||||
value = int(math.Abs(float64(dt[OFFSET_TIMEZONE]))) / 60
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
|
||||
return TZHElement.OracleDateFormat.formatInt(value, 2)
|
||||
}
|
||||
|
||||
type tzmElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (TZMElement tzmElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
if str[offset] == '+' {
|
||||
offset += 1
|
||||
} else if str[offset] == '-' {
|
||||
offset += 1
|
||||
TZMElement.OracleDateFormat.TZNegative = true
|
||||
}
|
||||
|
||||
strLen := 0
|
||||
for i := offset; i < offset+2 && i < len(str); i++ {
|
||||
if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) {
|
||||
break
|
||||
}
|
||||
strLen++
|
||||
}
|
||||
str = str[offset : offset+strLen]
|
||||
|
||||
tzm, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if tzm > 59 || tzm < 0 {
|
||||
return -1, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
|
||||
if dt[OFFSET_TIMEZONE] == INVALID_VALUE {
|
||||
dt[OFFSET_TIMEZONE] = int(tzm)
|
||||
} else {
|
||||
dt[OFFSET_TIMEZONE] += int(tzm)
|
||||
}
|
||||
return offset + strLen, nil
|
||||
}
|
||||
|
||||
func (TZMElement tzmElement) format(dt []int) string {
|
||||
var value int
|
||||
if dt[OFFSET_TIMEZONE] != int(INVALID_VALUE) {
|
||||
value = int(math.Abs(float64(dt[OFFSET_TIMEZONE]))) % 60
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
|
||||
return TZMElement.OracleDateFormat.formatInt(value, 2)
|
||||
}
|
||||
|
||||
type amElement struct {
|
||||
OracleDateFormat *oracleDateFormat
|
||||
}
|
||||
|
||||
func (AMElement amElement) parse(str string, offset int, dt []int) (int, error) {
|
||||
runeStr := ([]rune(str))[offset : offset+2]
|
||||
|
||||
if AMElement.OracleDateFormat.language == LANGUAGE_CN {
|
||||
if util.StringUtil.EqualsIgnoreCase("下午", string(runeStr)) {
|
||||
AMElement.OracleDateFormat.PM = true
|
||||
return offset + utf8.RuneLen('下') + utf8.RuneLen('午'), nil
|
||||
} else {
|
||||
AMElement.OracleDateFormat.PM = false
|
||||
return offset + utf8.RuneLen('上') + utf8.RuneLen('午'), nil
|
||||
}
|
||||
|
||||
} else if util.StringUtil.EqualsIgnoreCase("PM", string(runeStr)) {
|
||||
AMElement.OracleDateFormat.PM = true
|
||||
} else {
|
||||
AMElement.OracleDateFormat.PM = false
|
||||
}
|
||||
|
||||
return offset + 2, nil
|
||||
}
|
||||
|
||||
func (AMElement amElement) format(dt []int) string {
|
||||
hour := dt[OFFSET_HOUR]
|
||||
language := int(0)
|
||||
if language == LANGUAGE_CN {
|
||||
if hour > 12 {
|
||||
return "下午"
|
||||
} else {
|
||||
return "上午"
|
||||
}
|
||||
}
|
||||
|
||||
if hour > 12 {
|
||||
return "PM"
|
||||
} else {
|
||||
return "AM"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将int值格式化成指定长度,长度不足前面补0,长度超过的取末尾指定长度
|
||||
*/
|
||||
func (OracleDateFormat *oracleDateFormat) formatInt(value int, len int) string {
|
||||
pow := int(math.Pow10(len))
|
||||
if value >= pow {
|
||||
value %= pow
|
||||
}
|
||||
value += pow
|
||||
return strconv.FormatInt(int64(value), 10)[1:]
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化毫秒值
|
||||
* @param ms
|
||||
* @param len <= 6
|
||||
*/
|
||||
func (OracleDateFormat *oracleDateFormat) formatMilliSecond(ms int, len int) string {
|
||||
var ret string
|
||||
if ms < 10 {
|
||||
ret = "00000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 100 {
|
||||
ret = "0000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 1000 {
|
||||
ret = "000" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 10000 {
|
||||
ret = "00" + strconv.FormatInt(int64(ms), 10)
|
||||
} else if ms < 100000 {
|
||||
ret = "0" + strconv.FormatInt(int64(ms), 10)
|
||||
} else {
|
||||
ret = strconv.FormatInt(int64(ms), 10)
|
||||
}
|
||||
|
||||
if len < 6 {
|
||||
ret = ret[:len]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getFormat() *oracleDateFormat {
|
||||
format := new(oracleDateFormat)
|
||||
format.PM = false
|
||||
format.TZNegative = false
|
||||
format.YearElement = yearElement{format, 4}
|
||||
format.MonthElement = monthElement{format, false, false}
|
||||
format.MonElement = monElement{format, false, false}
|
||||
format.MMElement = mmElement{format}
|
||||
format.DDElement = ddElement{format}
|
||||
format.HH24Element = hh24Element{format}
|
||||
format.HH12Element = hh12Element{format}
|
||||
format.MIElement = miElement{format}
|
||||
format.SSElement = ssElement{format}
|
||||
format.FElement = fElement{format, -1}
|
||||
format.TZHElement = tzhElement{format}
|
||||
format.TZMElement = tzmElement{format}
|
||||
format.AMElement = amElement{format}
|
||||
|
||||
return format
|
||||
}
|
||||
|
||||
func (OracleDateFormat *oracleDateFormat) parse(str string) (ret []int, err error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
err = ECGO_INVALID_DATETIME_FORMAT.throw()
|
||||
}
|
||||
}()
|
||||
OracleDateFormat.TZNegative = false
|
||||
OracleDateFormat.PM = false
|
||||
dt := make([]int, DT_LEN)
|
||||
// oracle默认年月日为 当前时间
|
||||
today := time.Now()
|
||||
dt[OFFSET_YEAR] = today.Year()
|
||||
dt[OFFSET_MONTH] = int(today.Month())
|
||||
dt[OFFSET_DAY] = today.Day()
|
||||
dt[OFFSET_TIMEZONE] = INVALID_VALUE
|
||||
offset := 0
|
||||
str = strings.TrimSpace(str)
|
||||
for _, obj := range OracleDateFormat.FormatElementList {
|
||||
// 跳过空格
|
||||
for str[offset] == ' ' && fmt.Sprintf("%+v", obj) != " " {
|
||||
offset++
|
||||
}
|
||||
if e, ok := obj.(element); ok {
|
||||
offset, err = e.parse(str, offset, dt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
offset += len(obj.(string))
|
||||
}
|
||||
}
|
||||
if offset < len(str) {
|
||||
//[6103]:文字与格式字符串不匹配.
|
||||
return nil, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
|
||||
// 12小时制时间转换
|
||||
if OracleDateFormat.PM {
|
||||
dt[OFFSET_HOUR] = (dt[OFFSET_HOUR] + 12) % 24
|
||||
}
|
||||
|
||||
// 时区符号保留
|
||||
if OracleDateFormat.TZNegative {
|
||||
dt[OFFSET_TIMEZONE] = -dt[OFFSET_TIMEZONE]
|
||||
}
|
||||
|
||||
// check day
|
||||
if dt[OFFSET_DAY] > getDaysOfMonth(dt[OFFSET_YEAR], dt[OFFSET_MONTH]) || dt[OFFSET_DAY] < 1 {
|
||||
return nil, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
// check timezone 兼容oracle
|
||||
if dt[OFFSET_TIMEZONE] != INVALID_VALUE && (dt[OFFSET_TIMEZONE] > 14*60 || dt[OFFSET_TIMEZONE] <= -13*60) {
|
||||
return nil, ECGO_INVALID_DATETIME_VALUE.throw()
|
||||
}
|
||||
return dt, nil
|
||||
}
|
||||
|
||||
func parse(str string, pattern string, language int) ([]int, error) {
|
||||
f := getFormat()
|
||||
f.setPattern(pattern)
|
||||
f.language = language
|
||||
return f.parse(str)
|
||||
}
|
||||
|
||||
func (OracleDateFormat *oracleDateFormat) setPattern(pattern string) {
|
||||
if pattern != OracleDateFormat.pattern {
|
||||
OracleDateFormat.pattern = pattern
|
||||
OracleDateFormat.FormatElementList = OracleDateFormat.FormatElementList[:0]
|
||||
OracleDateFormat.analysePattern(pattern)
|
||||
}
|
||||
}
|
||||
|
||||
func format(dt []int, pattern string, scale int32, language int) string {
|
||||
f := getFormat()
|
||||
f.setPattern(pattern)
|
||||
f.language = language
|
||||
f.scale = scale
|
||||
ret := f.format(dt)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (OracleDateFormat *oracleDateFormat) format(dt []int) string {
|
||||
sf := strings.Builder{}
|
||||
tzStart := false
|
||||
for _, obj := range OracleDateFormat.FormatElementList {
|
||||
_, ok1 := obj.(tzhElement)
|
||||
_, ok2 := obj.(tzmElement)
|
||||
if !tzStart && (ok1 || ok2) {
|
||||
tzStart = true
|
||||
if dt[OFFSET_TIMEZONE] < 0 {
|
||||
sf.WriteString("-")
|
||||
} else {
|
||||
sf.WriteString("+")
|
||||
}
|
||||
}
|
||||
|
||||
if e, ok := obj.(element); ok {
|
||||
sf.WriteString(e.format(dt))
|
||||
} else {
|
||||
sf.WriteString(obj.(string))
|
||||
}
|
||||
}
|
||||
return sf.String()
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析格式串
|
||||
*/
|
||||
func (OracleDateFormat *oracleDateFormat) analysePattern(pattern string) ([]interface{}, error) {
|
||||
|
||||
// 按分隔符split
|
||||
pattern = strings.TrimSpace(pattern)
|
||||
l := len(pattern)
|
||||
var splitPatterns []string
|
||||
starti := 0
|
||||
var curChar rune
|
||||
for i := 0; i < l; i++ {
|
||||
curChar = rune(pattern[i])
|
||||
if !unicode.IsDigit(curChar) && !unicode.IsLetter(curChar) {
|
||||
if i > starti {
|
||||
splitPatterns = append(splitPatterns, pattern[starti:i])
|
||||
}
|
||||
|
||||
splitPatterns = append(splitPatterns, string(curChar))
|
||||
starti = i + 1
|
||||
} else if i == l-1 {
|
||||
splitPatterns = append(splitPatterns, pattern[starti:i+1])
|
||||
}
|
||||
}
|
||||
|
||||
// 每个串按照从完整串,然后依次去掉一个末尾字符 来进行尝试规约
|
||||
for _, subPattern := range splitPatterns {
|
||||
if len(subPattern) != 1 || unicode.IsDigit(rune(subPattern[0])) || unicode.IsLetter(rune(subPattern[0])) {
|
||||
fmtWord := subPattern
|
||||
for subPattern != "" {
|
||||
i := len(subPattern)
|
||||
for ; i > 0; i-- {
|
||||
fmtWord = subPattern[0:i]
|
||||
element, err := OracleDateFormat.getFormatElement(fmtWord)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if element != nil {
|
||||
// 忽略时区前面的+-号
|
||||
if element == OracleDateFormat.TZHElement || element == OracleDateFormat.TZMElement {
|
||||
var lastFormatElement string = OracleDateFormat.FormatElementList[len(OracleDateFormat.FormatElementList)-1].(string)
|
||||
if util.StringUtil.Equals("+", lastFormatElement) || util.StringUtil.Equals("-", lastFormatElement) {
|
||||
OracleDateFormat.FormatElementList = OracleDateFormat.FormatElementList[:len(OracleDateFormat.FormatElementList)-2]
|
||||
}
|
||||
}
|
||||
OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, element)
|
||||
if i == len(subPattern) {
|
||||
subPattern = ""
|
||||
} else {
|
||||
subPattern = subPattern[i:len(subPattern)]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
// 非标识符串
|
||||
OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, subPattern)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, subPattern)
|
||||
}
|
||||
}
|
||||
return OracleDateFormat.FormatElementList, nil
|
||||
}
|
||||
|
||||
func (OracleDateFormat *oracleDateFormat) getFormatElement(word string) (element, error) {
|
||||
if util.StringUtil.EqualsIgnoreCase("HH", word) || util.StringUtil.EqualsIgnoreCase("HH12", word) {
|
||||
return OracleDateFormat.HH12Element, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("HH24", word) {
|
||||
return OracleDateFormat.HH24Element, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("MI", word) {
|
||||
return OracleDateFormat.MIElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("SS", word) {
|
||||
return OracleDateFormat.SSElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("AM", word) || util.StringUtil.EqualsIgnoreCase("A.M.", word) || util.StringUtil.EqualsIgnoreCase("PM", word) || util.StringUtil.EqualsIgnoreCase("P.M.", word) {
|
||||
return OracleDateFormat.AMElement, nil
|
||||
} else if util.StringUtil.Equals("MONTH", word) {
|
||||
OracleDateFormat.MonthElement.upperCase = true
|
||||
OracleDateFormat.MonthElement.lowerCase = false
|
||||
return OracleDateFormat.MonthElement, nil
|
||||
} else if util.StringUtil.Equals("month", word) {
|
||||
OracleDateFormat.MonthElement.upperCase = false
|
||||
OracleDateFormat.MonthElement.lowerCase = true
|
||||
return OracleDateFormat.MonthElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("Month", word) {
|
||||
OracleDateFormat.MonthElement.upperCase = false
|
||||
OracleDateFormat.MonthElement.lowerCase = false
|
||||
return OracleDateFormat.MonthElement, nil
|
||||
} else if util.StringUtil.Equals("MON", word) {
|
||||
OracleDateFormat.MonElement.upperCase = true
|
||||
OracleDateFormat.MonElement.lowerCase = false
|
||||
return OracleDateFormat.MonElement, nil
|
||||
} else if util.StringUtil.Equals("mon", word) {
|
||||
OracleDateFormat.MonElement.upperCase = false
|
||||
OracleDateFormat.MonElement.lowerCase = true
|
||||
return OracleDateFormat.MonElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("Mon", word) {
|
||||
OracleDateFormat.MonElement.upperCase = false
|
||||
OracleDateFormat.MonElement.lowerCase = false
|
||||
return OracleDateFormat.MonElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("MM", word) {
|
||||
return OracleDateFormat.MMElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("DD", word) {
|
||||
return OracleDateFormat.DDElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("TZH", word) {
|
||||
return OracleDateFormat.TZHElement, nil
|
||||
} else if util.StringUtil.EqualsIgnoreCase("TZM", word) {
|
||||
return OracleDateFormat.TZMElement, nil
|
||||
} else if strings.Index(word, "Y") == 0 || strings.Index(word, "y") == 0 {
|
||||
OracleDateFormat.YearElement.len = len(word)
|
||||
return OracleDateFormat.YearElement, nil
|
||||
} else if strings.Index(word, "F") == 0 || strings.Index(word, "f") == 0 {
|
||||
|
||||
word = strings.ToUpper(word)
|
||||
numIndex := strings.LastIndex(word, "F") + 1
|
||||
var count int64
|
||||
var err error
|
||||
if numIndex < len(word) {
|
||||
count, err = strconv.ParseInt(word[numIndex:len(word)], 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
count = -1
|
||||
}
|
||||
|
||||
OracleDateFormat.FElement.len = int(count)
|
||||
return OracleDateFormat.FElement, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Properties struct {
|
||||
innerProps map[string]string
|
||||
}
|
||||
|
||||
func NewProperties() *Properties {
|
||||
p := Properties{
|
||||
innerProps: make(map[string]string, 50),
|
||||
}
|
||||
return &p
|
||||
}
|
||||
|
||||
func (g *Properties) SetProperties(p *Properties) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
for k, v := range p.innerProps {
|
||||
g.Set(strings.ToLower(k), v)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Properties) Len() int {
|
||||
return len(g.innerProps)
|
||||
}
|
||||
|
||||
func (g *Properties) IsNil() bool {
|
||||
return g == nil || g.innerProps == nil
|
||||
}
|
||||
|
||||
func (g *Properties) GetString(key, def string) string {
|
||||
v, ok := g.innerProps[strings.ToLower(key)]
|
||||
|
||||
if !ok || v == "" {
|
||||
return def
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (g *Properties) GetInt(key string, def int, min int, max int) int {
|
||||
value, ok := g.innerProps[strings.ToLower(key)]
|
||||
if !ok || value == "" {
|
||||
return def
|
||||
}
|
||||
|
||||
i, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
|
||||
if i > max || i < min {
|
||||
return def
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (g *Properties) GetBool(key string, def bool) bool {
|
||||
value, ok := g.innerProps[strings.ToLower(key)]
|
||||
if !ok || value == "" {
|
||||
return def
|
||||
}
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return def
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (g *Properties) GetTrimString(key string, def string) string {
|
||||
value, ok := g.innerProps[strings.ToLower(key)]
|
||||
if !ok || value == "" {
|
||||
return def
|
||||
} else {
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Properties) GetStringArray(key string, def []string) []string {
|
||||
value, ok := g.innerProps[strings.ToLower(key)]
|
||||
if ok || value != "" {
|
||||
array := strings.Split(value, ",")
|
||||
if len(array) > 0 {
|
||||
return array
|
||||
}
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
//func (g *Properties) GetBool(key string) bool {
|
||||
// i, _ := strconv.ParseBool(g.innerProps[key])
|
||||
// return i
|
||||
//}
|
||||
|
||||
func (g *Properties) Set(key, value string) {
|
||||
g.innerProps[strings.ToLower(key)] = value
|
||||
}
|
||||
|
||||
func (g *Properties) SetIfNotExist(key, value string) {
|
||||
if _, ok := g.innerProps[strings.ToLower(key)]; !ok {
|
||||
g.Set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果p有g没有的键值对,添加进g中
|
||||
func (g *Properties) SetDiffProperties(p *Properties) {
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
for k, v := range p.innerProps {
|
||||
if _, ok := g.innerProps[strings.ToLower(k)]; !ok {
|
||||
g.innerProps[strings.ToLower(k)] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
var rwMap sync.Map
|
||||
|
||||
type rwCounter struct {
|
||||
ntrx_primary int64
|
||||
|
||||
ntrx_total int64
|
||||
|
||||
primaryPercent float64
|
||||
|
||||
standbyPercent float64
|
||||
|
||||
standbyNTrxMapMu sync.RWMutex
|
||||
|
||||
standbyNTrxMap map[string]int64
|
||||
|
||||
standbyIdMapMu sync.RWMutex
|
||||
|
||||
standbyIdMap map[string]int32
|
||||
|
||||
standbyCount int32
|
||||
|
||||
flag []int32
|
||||
|
||||
increments []int32
|
||||
|
||||
//用来计数,选择存活的standby节点
|
||||
indexCount int64
|
||||
}
|
||||
|
||||
func newRWCounter(primaryPercent int32, standbyCount int32) *rwCounter {
|
||||
rwc := new(rwCounter)
|
||||
rwc.standbyNTrxMap = make(map[string]int64)
|
||||
rwc.standbyIdMap = make(map[string]int32)
|
||||
rwc.reset(primaryPercent, standbyCount)
|
||||
return rwc
|
||||
}
|
||||
|
||||
func (rwc *rwCounter) reset(primaryPercent int32, standbyCount int32) {
|
||||
rwc.ntrx_primary = 0
|
||||
rwc.ntrx_total = 0
|
||||
rwc.standbyCount = standbyCount
|
||||
rwc.increments = make([]int32, standbyCount+1)
|
||||
rwc.flag = make([]int32, standbyCount+1)
|
||||
var gcd = util.GCD(primaryPercent*standbyCount, 100-primaryPercent)
|
||||
rwc.increments[0] = primaryPercent * standbyCount / gcd
|
||||
for i, tmp := 1, (100-primaryPercent)/gcd; i < len(rwc.increments); i++ {
|
||||
rwc.increments[i] = tmp
|
||||
}
|
||||
copy(rwc.flag, rwc.increments)
|
||||
|
||||
if standbyCount > 0 {
|
||||
rwc.primaryPercent = float64(primaryPercent) / 100.0
|
||||
rwc.standbyPercent = float64(100-primaryPercent) / 100.0 / float64(standbyCount)
|
||||
} else {
|
||||
rwc.primaryPercent = 1
|
||||
rwc.standbyPercent = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 连接创建成功后调用,需要服务器返回standbyCount
|
||||
func getRwCounterInstance(conn *DmConnection, standbyCount int32) *rwCounter {
|
||||
key := conn.dmConnector.host + "_" + strconv.Itoa(int(conn.dmConnector.port)) + "_" + strconv.Itoa(int(conn.dmConnector.rwPercent))
|
||||
|
||||
val, ok := rwMap.Load(key)
|
||||
if !ok {
|
||||
rwc := newRWCounter(conn.dmConnector.rwPercent, standbyCount)
|
||||
rwMap.Store(key, rwc)
|
||||
return rwc
|
||||
} else {
|
||||
rwc := val.(*rwCounter)
|
||||
if rwc.standbyCount != standbyCount {
|
||||
rwc.reset(conn.dmConnector.rwPercent, standbyCount)
|
||||
}
|
||||
return rwc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 主机;
|
||||
*/
|
||||
func (rwc *rwCounter) countPrimary() RWSiteEnum {
|
||||
rwc.adjustNtrx()
|
||||
rwc.increasePrimaryNtrx()
|
||||
return PRIMARY
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dest 主机; 备机; any;
|
||||
* @return 主机; 备机
|
||||
*/
|
||||
func (rwc *rwCounter) count(dest RWSiteEnum, standby *DmConnection) RWSiteEnum {
|
||||
rwc.adjustNtrx()
|
||||
switch dest {
|
||||
case ANYSITE:
|
||||
{
|
||||
if rwc.primaryPercent == 1 || (rwc.flag[0] > rwc.getStandbyFlag(standby) && rwc.flag[0] > util.Sum(rwc.flag[1:])) {
|
||||
rwc.increasePrimaryNtrx()
|
||||
dest = PRIMARY
|
||||
} else {
|
||||
rwc.increaseStandbyNtrx(standby)
|
||||
dest = STANDBY
|
||||
}
|
||||
}
|
||||
case STANDBY:
|
||||
{
|
||||
rwc.increaseStandbyNtrx(standby)
|
||||
}
|
||||
case PRIMARY:
|
||||
{
|
||||
rwc.increasePrimaryNtrx()
|
||||
}
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
/**
|
||||
* 防止ntrx超出有效范围,等比调整
|
||||
*/
|
||||
func (rwc *rwCounter) adjustNtrx() {
|
||||
if rwc.ntrx_total >= INT64_MAX {
|
||||
var min int64
|
||||
var i = 0
|
||||
func() {
|
||||
rwc.standbyNTrxMapMu.Lock()
|
||||
defer rwc.standbyNTrxMapMu.Unlock()
|
||||
for _, num := range rwc.standbyNTrxMap {
|
||||
if i == 0 || num < min {
|
||||
min = num
|
||||
}
|
||||
i++
|
||||
}
|
||||
if rwc.ntrx_primary < min {
|
||||
min = rwc.ntrx_primary
|
||||
}
|
||||
rwc.ntrx_primary /= min
|
||||
rwc.ntrx_total /= min
|
||||
for k, v := range rwc.standbyNTrxMap {
|
||||
rwc.standbyNTrxMap[k] = v / min
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if rwc.flag[0] <= 0 && util.Sum(rwc.flag[1:]) <= 0 {
|
||||
// 如果主库事务数以及所有备库事务数的总和 都 <= 0, 重置事务计数,给每个库的事务计数加上初始计数值
|
||||
for i := 0; i < len(rwc.flag); i++ {
|
||||
rwc.flag[i] += rwc.increments[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rwc *rwCounter) increasePrimaryNtrx() {
|
||||
rwc.ntrx_primary++
|
||||
rwc.flag[0]--
|
||||
rwc.ntrx_total++
|
||||
}
|
||||
|
||||
//func (rwc *rwCounter) getStandbyNtrx(standby *DmConnection) int64 {
|
||||
// key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port))
|
||||
// ret, ok := rwc.standbyNTrxMap[key]
|
||||
// if !ok {
|
||||
// ret = 0
|
||||
// }
|
||||
//
|
||||
// return ret
|
||||
//}
|
||||
|
||||
func (rwc *rwCounter) getStandbyId(standby *DmConnection) int32 {
|
||||
key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port))
|
||||
rwc.standbyIdMapMu.Lock()
|
||||
defer rwc.standbyIdMapMu.Unlock()
|
||||
sid, ok := rwc.standbyIdMap[key]
|
||||
if !ok {
|
||||
sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary
|
||||
if sid > rwc.standbyCount {
|
||||
// 不在有效备库中
|
||||
return -1
|
||||
}
|
||||
rwc.standbyIdMap[key] = sid
|
||||
}
|
||||
return sid
|
||||
}
|
||||
|
||||
func (rwc *rwCounter) getStandbyFlag(standby *DmConnection) int32 {
|
||||
sid := rwc.getStandbyId(standby)
|
||||
if sid > 0 && sid < int32(len(rwc.flag)) {
|
||||
// 保证备库有效
|
||||
return rwc.flag[sid]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rwc *rwCounter) increaseStandbyNtrx(standby *DmConnection) {
|
||||
key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port))
|
||||
func() {
|
||||
rwc.standbyNTrxMapMu.Lock()
|
||||
defer rwc.standbyNTrxMapMu.Unlock()
|
||||
ret, ok := rwc.standbyNTrxMap[key]
|
||||
if ok {
|
||||
ret += 1
|
||||
} else {
|
||||
ret = 1
|
||||
}
|
||||
rwc.standbyNTrxMap[key] = ret
|
||||
}()
|
||||
func() {
|
||||
rwc.standbyIdMapMu.Lock()
|
||||
defer rwc.standbyIdMapMu.Unlock()
|
||||
sid, ok := rwc.standbyIdMap[key]
|
||||
if !ok {
|
||||
sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary
|
||||
rwc.standbyIdMap[key] = sid
|
||||
}
|
||||
rwc.flag[sid]--
|
||||
}()
|
||||
rwc.ntrx_total++
|
||||
}
|
||||
|
||||
func (rwc *rwCounter) random(rowCount int32) int32 {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
if rowCount > rwc.standbyCount {
|
||||
return rand.Int31n(rwc.standbyCount)
|
||||
} else {
|
||||
return rand.Int31n(rowCount)
|
||||
}
|
||||
}
|
||||
|
||||
func (rwc *rwCounter) String() string {
|
||||
return "PERCENT(P/S) : " + strconv.FormatFloat(rwc.primaryPercent, 'f', -1, 64) + "/" + strconv.FormatFloat(rwc.standbyPercent, 'f', -1, 64) + "\nNTRX_PRIMARY : " +
|
||||
strconv.FormatInt(rwc.ntrx_primary, 10) + "\nNTRX_TOTAL : " + strconv.FormatInt(rwc.ntrx_total, 10) + "\nNTRX_STANDBY : "
|
||||
}
|
||||
+554
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
const (
|
||||
SQL_SELECT_STANDBY = "select distinct mailIni.inst_name, mailIni.INST_IP, mailIni.INST_PORT, archIni.arch_status " +
|
||||
"from v$arch_status archIni " +
|
||||
"left join (select * from V$DM_MAL_INI) mailIni on archIni.arch_dest = mailIni.inst_name " +
|
||||
"left join V$MAL_LINK_STATUS on CTL_LINK_STATUS = 'CONNECTED' AND DATA_LINK_STATUS = 'CONNECTED' " +
|
||||
"where archIni.arch_type in ('TIMELY', 'REALTIME') AND archIni.arch_status = 'VALID'"
|
||||
|
||||
SQL_SELECT_STANDBY2 = "select distinct " +
|
||||
"mailIni.mal_inst_name, mailIni.mal_INST_HOST, mailIni.mal_INST_PORT, archIni.arch_status " +
|
||||
"from v$arch_status archIni " + "left join (select * from V$DM_MAL_INI) mailIni " +
|
||||
"on archIni.arch_dest = mailIni.mal_inst_name " + "left join V$MAL_LINK_STATUS " +
|
||||
"on CTL_LINK_STATUS = 'CONNECTED' AND DATA_LINK_STATUS = 'CONNECTED' " +
|
||||
"where archIni.arch_type in ('TIMELY', 'REALTIME') AND archIni.arch_status = 'VALID'"
|
||||
)
|
||||
|
||||
type rwUtil struct {
|
||||
}
|
||||
|
||||
var RWUtil = rwUtil{}
|
||||
|
||||
func (RWUtil rwUtil) connect(c *DmConnector, ctx context.Context) (*DmConnection, error) {
|
||||
c.loginMode = LOGIN_MODE_PRIMARY_ONLY
|
||||
connection, err := c.connect(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
connection.rwInfo.rwCounter = getRwCounterInstance(connection, connection.StandbyCount)
|
||||
err = RWUtil.connectStandby(connection)
|
||||
|
||||
return connection, err
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) reconnect(connection *DmConnection) error {
|
||||
if connection.rwInfo == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
RWUtil.removeStandby(connection)
|
||||
|
||||
err := connection.reconnect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
connection.rwInfo.cleanup()
|
||||
connection.rwInfo.rwCounter = getRwCounterInstance(connection, connection.StandbyCount)
|
||||
|
||||
err = RWUtil.connectStandby(connection)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) recoverStandby(connection *DmConnection) error {
|
||||
if connection.closed.IsSet() || RWUtil.isStandbyAlive(connection) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ts := time.Now().UnixNano() / 1000000
|
||||
|
||||
freq := int64(connection.dmConnector.rwStandbyRecoverTime)
|
||||
if freq <= 0 || ts-connection.rwInfo.tryRecoverTs < freq {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := RWUtil.connectStandby(connection)
|
||||
|
||||
if err == nil && !RWUtil.checkStatusValid(connection) {
|
||||
RWUtil.removeStandby(connection)
|
||||
}
|
||||
|
||||
connection.rwInfo.tryRecoverTs = ts
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) checkStatusValid(connection *DmConnection) bool {
|
||||
standbyConn := connection.rwInfo.connStandby
|
||||
if standbyConn == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var id int32 = -1
|
||||
stmt, rs, err := connection.driverQuery("select oguid from v$instance")
|
||||
defer stmt.close()
|
||||
defer rs.close()
|
||||
if err == nil {
|
||||
dest := make([]driver.Value, 1)
|
||||
err := rs.next(dest)
|
||||
if err == nil {
|
||||
id = dest[0].(int32)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
stmt2, rs2, err2 := standbyConn.driverQuery("select oguid from v$instance")
|
||||
defer stmt2.close()
|
||||
defer rs2.close()
|
||||
if err2 == nil {
|
||||
dest2 := make([]driver.Value, 1)
|
||||
err2 := rs.next(dest2)
|
||||
if err2 == nil {
|
||||
if dest2[0].(int32) == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) connectStandby(connection *DmConnection) error {
|
||||
var err error
|
||||
db, err := RWUtil.chooseValidStandby(connection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if db == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
standbyConnectorValue := *connection.dmConnector
|
||||
standbyConnector := &standbyConnectorValue
|
||||
standbyConnector.host = db.host
|
||||
standbyConnector.port = db.port
|
||||
standbyConnector.rwStandby = true
|
||||
standbyConnector.group = nil
|
||||
standbyConnector.loginMode = LOGIN_MODE_STANDBY_ONLY
|
||||
standbyConnector.switchTimes = 0
|
||||
connection.rwInfo.connStandby, err = standbyConnector.connectSingle(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if connection.rwInfo.connStandby.SvrMode != SERVER_MODE_STANDBY || connection.rwInfo.connStandby.SvrStat != SERVER_STATUS_OPEN {
|
||||
RWUtil.removeStandby(connection)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) chooseValidStandby(connection *DmConnection) (*ep, error) {
|
||||
var filter, filter2 string
|
||||
var stmt *DmStatement
|
||||
var rs *DmRows
|
||||
var err error
|
||||
if connection.dmConnector.rwSeparate == RW_SEPARATE_USER_DEFINED {
|
||||
return RWUtil.chooseStandbyUserDefined(connection), nil
|
||||
} else if connection.dmConnector.rwSeparate == RW_SEPARATE_DB_APPLY_WAIT {
|
||||
return newEP(connection.StandbyHost, connection.StandbyPort), nil
|
||||
} else if connection.dmConnector.rwSeparate == RW_SEPARATE_EP_GROUP {
|
||||
epStr := ""
|
||||
if connection.dmConnector.group != nil {
|
||||
for i := 0; i < len(connection.dmConnector.group.epList); i++ {
|
||||
if i != 0 {
|
||||
epStr += ","
|
||||
}
|
||||
epStr += "'" + connection.dmConnector.group.epList[i].host + ":" + string(connection.dmConnector.group.epList[i].port) + "'"
|
||||
}
|
||||
}
|
||||
if len(epStr) > 0 {
|
||||
filter = " and (mailIni.INST_IP || ':'|| mailIni.INST_PORT) in (" + epStr + ")"
|
||||
filter2 = " and (mailIni.mal_INST_HOST || ':'|| mailIni.mal_INST_PORT) in (" + epStr + ")"
|
||||
}
|
||||
}
|
||||
|
||||
if connection.Malini2 {
|
||||
stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY2 + filter2)
|
||||
} else {
|
||||
stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY + filter)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if rs != nil {
|
||||
rs.close()
|
||||
}
|
||||
if stmt != nil {
|
||||
stmt.close()
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
rs.close()
|
||||
stmt.close()
|
||||
|
||||
if connection.Malini2 {
|
||||
stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY2 + filter)
|
||||
} else {
|
||||
stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY + filter2)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
count := int32(rs.CurrentRows.getRowCount())
|
||||
if count > 0 {
|
||||
connection.rwInfo.rwCounter = getRwCounterInstance(connection, count)
|
||||
i := int32(0)
|
||||
rowIndex := connection.rwInfo.rwCounter.random(count)
|
||||
dest := make([]driver.Value, 3)
|
||||
for err := rs.next(dest); err != io.EOF; err = rs.next(dest) {
|
||||
if i == rowIndex {
|
||||
ep := newEP(dest[1].(string), dest[2].(int32))
|
||||
return ep, nil
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.New("choose valid standby error!" + err.Error())
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) chooseStandbyUserDefined(connection *DmConnection) *ep {
|
||||
epGroup := connection.dmConnector.group.epList
|
||||
if epGroup == nil {
|
||||
return nil
|
||||
}
|
||||
aliveEp := make([]*ep, len(epGroup))
|
||||
|
||||
aliveCount := 0
|
||||
for i := 0; i < len(epGroup); i++ {
|
||||
ep := epGroup[i]
|
||||
if isAliveStandby(ep, connection) {
|
||||
aliveEp = append(aliveEp, epGroup[i])
|
||||
aliveCount++
|
||||
}
|
||||
}
|
||||
|
||||
if aliveCount > 0 {
|
||||
if connection.rwInfo.rwCounter.indexCount == INT64_MAX {
|
||||
connection.rwInfo.rwCounter.indexCount = 0
|
||||
}
|
||||
ret := aliveEp[int(connection.rwInfo.rwCounter.indexCount)%aliveCount]
|
||||
|
||||
connection.rwInfo.rwCounter.indexCount++
|
||||
return ret
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isAliveStandby(ep *ep, connection *DmConnection) bool {
|
||||
standbyConnectorValue := *connection.dmConnector
|
||||
standbyConnector := &standbyConnectorValue
|
||||
standbyConnector.host = ep.host
|
||||
standbyConnector.port = ep.port
|
||||
standbyConnector.rwStandby = true
|
||||
standbyConnector.group = nil
|
||||
standbyConnector.loginMode = LOGIN_MODE_STANDBY_ONLY
|
||||
standbyConnector.switchTimes = 0
|
||||
standbyConnect, err := standbyConnector.connectSingle(context.Background())
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
defer standbyConnect.close()
|
||||
|
||||
if standbyConnect.SvrMode != SERVER_MODE_STANDBY || standbyConnect.SvrStat != SERVER_STATUS_OPEN {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) afterExceptionOnStandby(connection *DmConnection, e error) {
|
||||
if e.(*DmError).ErrCode == ECGO_COMMUNITION_ERROR.ErrCode {
|
||||
RWUtil.removeStandby(connection)
|
||||
}
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) removeStandby(connection *DmConnection) {
|
||||
if connection.rwInfo.connStandby != nil {
|
||||
connection.rwInfo.connStandby.close()
|
||||
connection.rwInfo.connStandby = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) isCreateStandbyStmt(stmt *DmStatement) bool {
|
||||
return stmt != nil && stmt.rwInfo.readOnly && RWUtil.isStandbyAlive(stmt.dmConn)
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) executeByConn(conn *DmConnection, query string, execute1 func() (interface{}, error), execute2 func(otherConn *DmConnection) (interface{}, error)) (interface{}, error) {
|
||||
|
||||
if err := RWUtil.recoverStandby(conn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
RWUtil.distributeSqlByConn(conn, query)
|
||||
|
||||
turnToPrimary := false
|
||||
|
||||
ret, err := execute1()
|
||||
if err != nil {
|
||||
if conn.rwInfo.connCurrent == conn.rwInfo.connStandby {
|
||||
|
||||
RWUtil.afterExceptionOnStandby(conn, err)
|
||||
turnToPrimary = true
|
||||
} else {
|
||||
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
curConn := conn.rwInfo.connCurrent
|
||||
var otherConn *DmConnection
|
||||
if curConn != conn {
|
||||
otherConn = conn
|
||||
} else {
|
||||
otherConn = conn.rwInfo.connStandby
|
||||
}
|
||||
|
||||
switch curConn.lastExecInfo.retSqlType {
|
||||
case Dm_build_794, Dm_build_795, Dm_build_799, Dm_build_806, Dm_build_805, Dm_build_797:
|
||||
{
|
||||
|
||||
if otherConn != nil {
|
||||
execute2(otherConn)
|
||||
}
|
||||
}
|
||||
case Dm_build_804:
|
||||
{
|
||||
|
||||
sqlhead := regexp.MustCompile("[ (]").Split(strings.TrimSpace(query), 2)[0]
|
||||
if util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_PARA_VALUE") || util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_SESSION_READONLY") {
|
||||
if otherConn != nil {
|
||||
execute2(otherConn)
|
||||
}
|
||||
}
|
||||
}
|
||||
case Dm_build_803:
|
||||
{
|
||||
|
||||
if conn.dmConnector.rwHA && curConn == conn.rwInfo.connStandby &&
|
||||
(curConn.lastExecInfo.rsDatas == nil || len(curConn.lastExecInfo.rsDatas) == 0) {
|
||||
turnToPrimary = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if turnToPrimary {
|
||||
conn.rwInfo.toPrimary()
|
||||
conn.rwInfo.connCurrent = conn
|
||||
|
||||
return execute2(conn)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) executeByStmt(stmt *DmStatement, execute1 func() (interface{}, error), execute2 func(otherStmt *DmStatement) (interface{}, error)) (interface{}, error) {
|
||||
orgStmt := stmt.rwInfo.stmtCurrent
|
||||
query := stmt.nativeSql
|
||||
|
||||
if err := RWUtil.recoverStandby(stmt.dmConn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
RWUtil.distributeSqlByStmt(stmt)
|
||||
if orgStmt != stmt.rwInfo.stmtCurrent {
|
||||
RWUtil.copyStatement(orgStmt, stmt.rwInfo.stmtCurrent)
|
||||
stmt.rwInfo.stmtCurrent.nativeSql = orgStmt.nativeSql
|
||||
}
|
||||
|
||||
turnToPrimary := false
|
||||
|
||||
ret, err := execute1()
|
||||
if err != nil {
|
||||
|
||||
if stmt.rwInfo.stmtCurrent == stmt.rwInfo.stmtStandby {
|
||||
RWUtil.afterExceptionOnStandby(stmt.dmConn, err)
|
||||
turnToPrimary = true
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
curStmt := stmt.rwInfo.stmtCurrent
|
||||
var otherStmt *DmStatement
|
||||
if curStmt != stmt {
|
||||
otherStmt = stmt
|
||||
} else {
|
||||
otherStmt = stmt.rwInfo.stmtStandby
|
||||
}
|
||||
|
||||
switch curStmt.execInfo.retSqlType {
|
||||
case Dm_build_794, Dm_build_795, Dm_build_799, Dm_build_806, Dm_build_805, Dm_build_797:
|
||||
{
|
||||
|
||||
if otherStmt != nil {
|
||||
RWUtil.copyStatement(curStmt, otherStmt)
|
||||
execute2(otherStmt)
|
||||
}
|
||||
}
|
||||
case Dm_build_804:
|
||||
{
|
||||
|
||||
var tmpsql string
|
||||
if query != "" {
|
||||
tmpsql = strings.TrimSpace(query)
|
||||
} else if stmt.nativeSql != "" {
|
||||
tmpsql = strings.TrimSpace(stmt.nativeSql)
|
||||
} else {
|
||||
tmpsql = ""
|
||||
}
|
||||
sqlhead := regexp.MustCompile("[ (]").Split(tmpsql, 2)[0]
|
||||
if util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_PARA_VALUE") || util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_SESSION_READONLY") {
|
||||
if otherStmt != nil {
|
||||
RWUtil.copyStatement(curStmt, otherStmt)
|
||||
execute2(otherStmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
case Dm_build_803:
|
||||
{
|
||||
|
||||
if stmt.dmConn.dmConnector.rwHA && curStmt == stmt.rwInfo.stmtStandby &&
|
||||
(curStmt.execInfo.rsDatas == nil || len(curStmt.execInfo.rsDatas) == 0) {
|
||||
turnToPrimary = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if turnToPrimary {
|
||||
stmt.dmConn.rwInfo.toPrimary()
|
||||
stmt.rwInfo.stmtCurrent = stmt
|
||||
|
||||
RWUtil.copyStatement(stmt.rwInfo.stmtStandby, stmt)
|
||||
|
||||
return execute2(stmt)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) checkReadonlyByConn(conn *DmConnection, sql string) bool {
|
||||
readonly := true
|
||||
|
||||
if sql != "" && !conn.dmConnector.rwIgnoreSql {
|
||||
tmpsql := strings.TrimSpace(sql)
|
||||
sqlhead := strings.SplitN(tmpsql, " ", 2)[0]
|
||||
if util.StringUtil.EqualsIgnoreCase(sqlhead, "INSERT") ||
|
||||
util.StringUtil.EqualsIgnoreCase(sqlhead, "UPDATE") ||
|
||||
util.StringUtil.EqualsIgnoreCase(sqlhead, "DELETE") ||
|
||||
util.StringUtil.EqualsIgnoreCase(sqlhead, "CREATE") ||
|
||||
util.StringUtil.EqualsIgnoreCase(sqlhead, "TRUNCATE") ||
|
||||
util.StringUtil.EqualsIgnoreCase(sqlhead, "DROP") ||
|
||||
util.StringUtil.EqualsIgnoreCase(sqlhead, "ALTER") {
|
||||
readonly = false
|
||||
} else {
|
||||
readonly = true
|
||||
}
|
||||
}
|
||||
return readonly
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) checkReadonlyByStmt(stmt *DmStatement) bool {
|
||||
return RWUtil.checkReadonlyByConn(stmt.dmConn, stmt.nativeSql)
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) distributeSqlByConn(conn *DmConnection, query string) RWSiteEnum {
|
||||
var dest RWSiteEnum
|
||||
if !RWUtil.isStandbyAlive(conn) {
|
||||
|
||||
dest = conn.rwInfo.toPrimary()
|
||||
} else if !RWUtil.checkReadonlyByConn(conn, query) {
|
||||
|
||||
dest = conn.rwInfo.toPrimary()
|
||||
} else if (conn.rwInfo.distribute == PRIMARY && !conn.trxFinish) ||
|
||||
(conn.rwInfo.distribute == STANDBY && !conn.rwInfo.connStandby.trxFinish) {
|
||||
|
||||
dest = conn.rwInfo.distribute
|
||||
} else if conn.IsoLevel != int32(sql.LevelSerializable) {
|
||||
|
||||
dest = conn.rwInfo.toAny()
|
||||
} else {
|
||||
dest = conn.rwInfo.toPrimary()
|
||||
}
|
||||
|
||||
if dest == PRIMARY {
|
||||
conn.rwInfo.connCurrent = conn
|
||||
} else {
|
||||
conn.rwInfo.connCurrent = conn.rwInfo.connStandby
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) distributeSqlByStmt(stmt *DmStatement) RWSiteEnum {
|
||||
var dest RWSiteEnum
|
||||
if !RWUtil.isStandbyAlive(stmt.dmConn) {
|
||||
|
||||
dest = stmt.dmConn.rwInfo.toPrimary()
|
||||
} else if !RWUtil.checkReadonlyByStmt(stmt) {
|
||||
|
||||
dest = stmt.dmConn.rwInfo.toPrimary()
|
||||
} else if (stmt.dmConn.rwInfo.distribute == PRIMARY && !stmt.dmConn.trxFinish) ||
|
||||
(stmt.dmConn.rwInfo.distribute == STANDBY && !stmt.dmConn.rwInfo.connStandby.trxFinish) {
|
||||
|
||||
dest = stmt.dmConn.rwInfo.distribute
|
||||
} else if stmt.dmConn.IsoLevel != int32(sql.LevelSerializable) {
|
||||
|
||||
dest = stmt.dmConn.rwInfo.toAny()
|
||||
} else {
|
||||
dest = stmt.dmConn.rwInfo.toPrimary()
|
||||
}
|
||||
|
||||
if dest == STANDBY && !RWUtil.isStandbyStatementValid(stmt) {
|
||||
|
||||
var err error
|
||||
stmt.rwInfo.stmtStandby, err = stmt.dmConn.rwInfo.connStandby.prepare(stmt.nativeSql)
|
||||
if err != nil {
|
||||
dest = stmt.dmConn.rwInfo.toPrimary()
|
||||
}
|
||||
}
|
||||
|
||||
if dest == PRIMARY {
|
||||
stmt.rwInfo.stmtCurrent = stmt
|
||||
} else {
|
||||
stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) isStandbyAlive(connection *DmConnection) bool {
|
||||
return connection.rwInfo.connStandby != nil && !connection.rwInfo.connStandby.closed.IsSet()
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) isStandbyStatementValid(statement *DmStatement) bool {
|
||||
return statement.rwInfo.stmtStandby != nil && !statement.rwInfo.stmtStandby.closed
|
||||
}
|
||||
|
||||
func (RWUtil rwUtil) copyStatement(srcStmt *DmStatement, destStmt *DmStatement) {
|
||||
destStmt.nativeSql = srcStmt.nativeSql
|
||||
destStmt.serverParams = srcStmt.serverParams
|
||||
destStmt.bindParams = srcStmt.bindParams
|
||||
destStmt.paramCount = srcStmt.paramCount
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
)
|
||||
|
||||
var SQLName sqlName
|
||||
|
||||
type sqlName struct {
|
||||
m_name string // 描述对象自身名称,
|
||||
|
||||
// 若为内置类型,则表示数据库端定义的名称,与dType相对应
|
||||
m_pkgName string // 所在包的名称,适用于包中类型的定义
|
||||
|
||||
m_schName string // 描述对象所在模式名
|
||||
|
||||
m_fulName string // 描述对象完全限定名, 记录用户发送的名称信息;
|
||||
|
||||
// 以及接受服务器响应后,拼成的名称信息
|
||||
|
||||
m_schId int // 保存模式id,模式名无法传出,利用模式id查找
|
||||
|
||||
m_packId int // 保存包的id,包名无法传出,用于查找包名
|
||||
|
||||
m_conn *DmConnection
|
||||
}
|
||||
|
||||
func (SqlName *sqlName) init() {
|
||||
SqlName.m_name = ""
|
||||
SqlName.m_pkgName = ""
|
||||
SqlName.m_schName = ""
|
||||
SqlName.m_fulName = ""
|
||||
SqlName.m_schId = -1
|
||||
SqlName.m_packId = -1
|
||||
SqlName.m_conn = nil
|
||||
}
|
||||
|
||||
func newSqlNameByFulName(fulName string) *sqlName {
|
||||
o := new(sqlName)
|
||||
o.init()
|
||||
o.m_fulName = fulName
|
||||
return o
|
||||
}
|
||||
|
||||
func newSqlNameByConn(conn *DmConnection) *sqlName {
|
||||
o := new(sqlName)
|
||||
o.init()
|
||||
o.m_conn = conn
|
||||
return o
|
||||
}
|
||||
|
||||
func (SqlName *sqlName) getFulName() (string, error) {
|
||||
// 说明非内嵌式数据类型名称描述信息传入或已经获取过描述信息
|
||||
if len(SqlName.m_fulName) > 0 {
|
||||
return SqlName.m_fulName, nil
|
||||
}
|
||||
|
||||
// 内嵌式数据类型无名称描述信息返回,直接返回null
|
||||
if SqlName.m_name == "" {
|
||||
// DBError.throwUnsupportedSQLException();
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// 其他数据名描述信息
|
||||
if SqlName.m_packId != 0 || SqlName.m_schId != 0 {
|
||||
query := "SELECT NAME INTO ? FROM SYS.SYSOBJECTS WHERE ID=?"
|
||||
|
||||
params := make([]driver.Value, 2)
|
||||
var v string
|
||||
params[0] = sql.Out{Dest: &v}
|
||||
if SqlName.m_packId != 0 {
|
||||
params[1] = SqlName.m_packId
|
||||
} else {
|
||||
params[1] = SqlName.m_schId
|
||||
}
|
||||
|
||||
rs, err := SqlName.m_conn.query(query, params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
rs.close()
|
||||
|
||||
// 说明是包中定义的对象
|
||||
if SqlName.m_packId != 0 {
|
||||
// pkg全名
|
||||
SqlName.m_pkgName = v
|
||||
SqlName.m_fulName = SqlName.m_pkgName + "." + SqlName.m_name
|
||||
} else {
|
||||
// 非包中定义的对象
|
||||
// schema 名称
|
||||
SqlName.m_schName = v
|
||||
SqlName.m_fulName = SqlName.m_schName + "." + SqlName.m_name
|
||||
}
|
||||
}
|
||||
// 将有效值返回
|
||||
if len(SqlName.m_fulName) > 0 {
|
||||
return SqlName.m_fulName, nil
|
||||
} else {
|
||||
return SqlName.m_name, nil
|
||||
}
|
||||
|
||||
}
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gitee.com/chunanyong/dm/parser"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
func (dc *DmConnection) lex(sql string) ([]*parser.LVal, error) {
|
||||
if dc.lexer == nil {
|
||||
dc.lexer = parser.NewLexer(strings.NewReader(sql), false)
|
||||
} else {
|
||||
dc.lexer.Reset(strings.NewReader(sql))
|
||||
}
|
||||
|
||||
lexer := dc.lexer
|
||||
var lval *parser.LVal
|
||||
var err error
|
||||
lvalList := make([]*parser.LVal, 0, 64)
|
||||
lval, err = lexer.Yylex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for lval != nil {
|
||||
lvalList = append(lvalList, lval)
|
||||
lval.Position = len(lvalList)
|
||||
lval, err = lexer.Yylex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return lvalList, nil
|
||||
}
|
||||
|
||||
func lexSkipWhitespace(sql string, n int) ([]*parser.LVal, error) {
|
||||
lexer := parser.NewLexer(strings.NewReader(sql), false)
|
||||
|
||||
var lval *parser.LVal
|
||||
var err error
|
||||
lvalList := make([]*parser.LVal, 0, 64)
|
||||
lval, err = lexer.Yylex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for lval != nil && n > 0 {
|
||||
lval.Position = len(lvalList)
|
||||
if lval.Tp == parser.WHITESPACE_OR_COMMENT {
|
||||
continue
|
||||
}
|
||||
|
||||
lvalList = append(lvalList, lval)
|
||||
n--
|
||||
lval, err = lexer.Yylex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return lvalList, nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) escape(sql string, keywords []string) (string, error) {
|
||||
|
||||
if (keywords == nil || len(keywords) == 0) && strings.Index(sql, "{") == -1 {
|
||||
return sql, nil
|
||||
}
|
||||
var keywordMap map[string]interface{}
|
||||
if keywords != nil && len(keywords) > 0 {
|
||||
keywordMap = make(map[string]interface{}, len(keywords))
|
||||
for _, keyword := range keywords {
|
||||
keywordMap[strings.ToUpper(keyword)] = nil
|
||||
}
|
||||
}
|
||||
nsql := bytes.NewBufferString("")
|
||||
stack := make([]bool, 0, 64)
|
||||
lvalList, err := dc.lex(sql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i := 0; i < len(lvalList); i++ {
|
||||
lval0 := lvalList[i]
|
||||
if lval0.Tp == parser.NORMAL {
|
||||
if lval0.Value == "{" {
|
||||
lval1 := next(lvalList, i+1)
|
||||
if lval1 == nil || lval1.Tp != parser.NORMAL {
|
||||
stack = append(stack, false)
|
||||
nsql.WriteString(lval0.Value)
|
||||
} else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "escape") || util.StringUtil.EqualsIgnoreCase(lval1.Value, "call") {
|
||||
stack = append(stack, true)
|
||||
} else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "oj") {
|
||||
stack = append(stack, true)
|
||||
lval1.Value = ""
|
||||
lval1.Tp = parser.WHITESPACE_OR_COMMENT
|
||||
} else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "d") {
|
||||
stack = append(stack, true)
|
||||
lval1.Value = "date"
|
||||
} else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "t") {
|
||||
stack = append(stack, true)
|
||||
lval1.Value = "time"
|
||||
} else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "ts") {
|
||||
stack = append(stack, true)
|
||||
lval1.Value = "datetime"
|
||||
} else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "fn") {
|
||||
stack = append(stack, true)
|
||||
lval1.Value = ""
|
||||
lval1.Tp = parser.WHITESPACE_OR_COMMENT
|
||||
lval2 := next(lvalList, lval1.Position+1)
|
||||
if lval2 != nil && lval2.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval2.Value, "database") {
|
||||
lval2.Value = "cur_database"
|
||||
}
|
||||
} else if util.StringUtil.Equals(lval1.Value, "?") {
|
||||
lval2 := next(lvalList, lval1.Position+1)
|
||||
if lval2 != nil && lval2.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval2.Value, "=") {
|
||||
lval3 := next(lvalList, lval2.Position+1)
|
||||
if lval3 != nil && lval3.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval3.Value, "call") {
|
||||
stack = append(stack, true)
|
||||
lval3.Value = ""
|
||||
lval3.Tp = parser.WHITESPACE_OR_COMMENT
|
||||
} else {
|
||||
stack = append(stack, false)
|
||||
nsql.WriteString(lval0.Value)
|
||||
}
|
||||
} else {
|
||||
stack = append(stack, false)
|
||||
nsql.WriteString(lval0.Value)
|
||||
}
|
||||
} else {
|
||||
stack = append(stack, false)
|
||||
nsql.WriteString(lval0.Value)
|
||||
}
|
||||
} else if util.StringUtil.Equals(lval0.Value, "}") {
|
||||
if len(stack) != 0 && stack[len(stack)-1] {
|
||||
|
||||
} else {
|
||||
nsql.WriteString(lval0.Value)
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
} else {
|
||||
if keywordMap != nil {
|
||||
_, ok := keywordMap[strings.ToUpper(lval0.Value)]
|
||||
if ok {
|
||||
nsql.WriteString("\"" + util.StringUtil.ProcessDoubleQuoteOfName(strings.ToUpper(lval0.Value)) + "\"")
|
||||
} else {
|
||||
nsql.WriteString(lval0.Value)
|
||||
}
|
||||
} else {
|
||||
nsql.WriteString(lval0.Value)
|
||||
}
|
||||
}
|
||||
} else if lval0.Tp == parser.STRING {
|
||||
nsql.WriteString("'" + util.StringUtil.ProcessSingleQuoteOfName(lval0.Value) + "'")
|
||||
} else {
|
||||
nsql.WriteString(lval0.Value)
|
||||
}
|
||||
}
|
||||
|
||||
return nsql.String(), nil
|
||||
}
|
||||
|
||||
func next(lvalList []*parser.LVal, start int) *parser.LVal {
|
||||
var lval *parser.LVal
|
||||
|
||||
size := len(lvalList)
|
||||
for i := start; i < size; i++ {
|
||||
lval = lvalList[i]
|
||||
if lval.Tp != parser.WHITESPACE_OR_COMMENT {
|
||||
break
|
||||
}
|
||||
}
|
||||
return lval
|
||||
}
|
||||
|
||||
func (dc *DmConnection) execOpt(sql string, optParamList []OptParameter, serverEncoding string, backSlashFlag bool) (string, []OptParameter, error) {
|
||||
nsql := bytes.NewBufferString("")
|
||||
|
||||
lvalList, err := dc.lex(sql)
|
||||
if err != nil {
|
||||
return sql, nil, err
|
||||
}
|
||||
|
||||
if nil == lvalList || len(lvalList) == 0 {
|
||||
return sql, nil, nil
|
||||
}
|
||||
|
||||
firstWord := lvalList[0].Value
|
||||
if !(util.StringUtil.EqualsIgnoreCase(firstWord, "INSERT") || util.StringUtil.EqualsIgnoreCase(firstWord, "SELECT") ||
|
||||
util.StringUtil.EqualsIgnoreCase(firstWord, "UPDATE") || util.StringUtil.EqualsIgnoreCase(firstWord, "DELETE")) {
|
||||
return sql, nil, nil
|
||||
}
|
||||
|
||||
breakIndex := 0
|
||||
for i := 0; i < len(lvalList); i++ {
|
||||
lval := lvalList[i]
|
||||
switch lval.Tp {
|
||||
case parser.NULL:
|
||||
{
|
||||
nsql.WriteString("?")
|
||||
optParamList = append(optParamList, newOptParameter(nil, NULL, NULL_PREC))
|
||||
}
|
||||
case parser.INT:
|
||||
{
|
||||
nsql.WriteString("?")
|
||||
value, err := strconv.Atoi(lval.Value)
|
||||
if err != nil {
|
||||
return sql, nil, err
|
||||
}
|
||||
|
||||
if value <= int(INT32_MAX) && value >= int(INT32_MIN) {
|
||||
optParamList = append(optParamList, newOptParameter(G2DB.toInt32(int32(value)), INT, INT_PREC))
|
||||
|
||||
} else {
|
||||
optParamList = append(optParamList, newOptParameter(G2DB.toInt64(int64(value)), BIGINT, BIGINT_PREC))
|
||||
}
|
||||
}
|
||||
case parser.DOUBLE:
|
||||
{
|
||||
nsql.WriteString("?")
|
||||
f, err := strconv.ParseFloat(lval.Value, 64)
|
||||
if err != nil {
|
||||
return sql, nil, err
|
||||
}
|
||||
|
||||
optParamList = append(optParamList, newOptParameter(G2DB.toFloat64(f), DOUBLE, DOUBLE_PREC))
|
||||
}
|
||||
case parser.DECIMAL:
|
||||
{
|
||||
nsql.WriteString("?")
|
||||
bytes, err := G2DB.toDecimal(lval.Value)
|
||||
if err != nil {
|
||||
return sql, nil, err
|
||||
}
|
||||
optParamList = append(optParamList, newOptParameter(bytes, DECIMAL, 0))
|
||||
}
|
||||
case parser.STRING:
|
||||
{
|
||||
|
||||
if len(lval.Value) > int(INT16_MAX) {
|
||||
|
||||
nsql.WriteString("'" + util.StringUtil.ProcessSingleQuoteOfName(lval.Value) + "'")
|
||||
} else {
|
||||
nsql.WriteString("?")
|
||||
|
||||
if backSlashFlag {
|
||||
lval.Value = util.StringUtil.Translate(lval.Value)
|
||||
}
|
||||
optParamList = append(optParamList, newOptParameter(Dm_build_1346.Dm_build_1562(lval.Value, serverEncoding, dc), VARCHAR, VARCHAR_PREC))
|
||||
}
|
||||
}
|
||||
case parser.HEX_INT:
|
||||
|
||||
nsql.WriteString(lval.Value)
|
||||
default:
|
||||
|
||||
nsql.WriteString(lval.Value)
|
||||
}
|
||||
|
||||
if breakIndex > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if breakIndex > 0 {
|
||||
for i := breakIndex + 1; i < len(lvalList); i++ {
|
||||
nsql.WriteString(lvalList[i].Value)
|
||||
}
|
||||
}
|
||||
|
||||
return nsql.String(), optParamList, nil
|
||||
}
|
||||
|
||||
func (dc *DmConnection) hasConst(sql string) (bool, error) {
|
||||
lvalList, err := dc.lex(sql)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if nil == lvalList || len(lvalList) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for i := 0; i < len(lvalList); i++ {
|
||||
switch lvalList[i].Tp {
|
||||
case parser.NULL, parser.INT, parser.DOUBLE, parser.DECIMAL, parser.STRING, parser.HEX_INT:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type OptParameter struct {
|
||||
bytes []byte
|
||||
ioType byte
|
||||
tp int
|
||||
prec int
|
||||
scale int
|
||||
}
|
||||
|
||||
func newOptParameter(bytes []byte, tp int, prec int) OptParameter {
|
||||
o := new(OptParameter)
|
||||
o.bytes = bytes
|
||||
o.tp = tp
|
||||
o.prec = prec
|
||||
return *o
|
||||
}
|
||||
|
||||
func (parameter *OptParameter) String() string {
|
||||
if parameter.bytes == nil {
|
||||
return ""
|
||||
}
|
||||
return string(parameter.bytes)
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
type StructDescriptor struct {
|
||||
m_typeDesc *TypeDescriptor
|
||||
}
|
||||
|
||||
func newStructDescriptor(fulName string, conn *DmConnection) (*StructDescriptor, error) {
|
||||
sd := new(StructDescriptor)
|
||||
if fulName == "" {
|
||||
return nil, ECGO_INVALID_COMPLEX_TYPE_NAME.throw()
|
||||
}
|
||||
|
||||
sd.m_typeDesc = newTypeDescriptorWithFulName(fulName, conn)
|
||||
|
||||
err := sd.m_typeDesc.parseDescByName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
func newStructDescriptorByTypeDescriptor(desc *TypeDescriptor) *StructDescriptor {
|
||||
sd := new(StructDescriptor)
|
||||
sd.m_typeDesc = desc
|
||||
return sd
|
||||
}
|
||||
|
||||
func (sd *StructDescriptor) getSize() int {
|
||||
return sd.m_typeDesc.m_size
|
||||
}
|
||||
|
||||
func (sd *StructDescriptor) getObjId() int {
|
||||
return sd.m_typeDesc.m_objId
|
||||
}
|
||||
|
||||
func (sd *StructDescriptor) getItemsDesc() []TypeDescriptor {
|
||||
return sd.m_typeDesc.m_fieldsObj
|
||||
}
|
||||
+478
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
package dm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gitee.com/chunanyong/dm/util"
|
||||
)
|
||||
|
||||
var LogDirDef, _ = os.Getwd()
|
||||
|
||||
var StatDirDef, _ = os.Getwd()
|
||||
|
||||
const (
|
||||
DEFAULT_PORT int32 = 5236
|
||||
|
||||
//log level
|
||||
LOG_OFF int = 0
|
||||
|
||||
LOG_ERROR int = 1
|
||||
|
||||
LOG_WARN int = 2
|
||||
|
||||
LOG_SQL int = 3
|
||||
|
||||
LOG_INFO int = 4
|
||||
|
||||
LOG_DEBUG int = 5
|
||||
|
||||
LOG_ALL int = 9
|
||||
|
||||
//stat
|
||||
STAT_SQL_REMOVE_LATEST int = 0
|
||||
|
||||
STAT_SQL_REMOVE_OLDEST int = 1
|
||||
|
||||
// 编码字符集
|
||||
ENCODING_UTF8 string = "UTF-8"
|
||||
|
||||
ENCODING_EUCKR string = "EUC-KR"
|
||||
|
||||
ENCODING_GB18030 string = "GB18030"
|
||||
|
||||
ENCODING_BIG5 string = "BIG5"
|
||||
|
||||
DbAliveCheckFreqDef = 0
|
||||
|
||||
LocaleDef = LANGUAGE_CN
|
||||
|
||||
// log
|
||||
LogLevelDef = LOG_OFF // 日志级别:off, error, warn, sql, info, all
|
||||
|
||||
LogFlushFreqDef = 10 // 日志刷盘时间s (>=0)
|
||||
|
||||
LogFlushQueueSizeDef = 100 //日志队列大小
|
||||
|
||||
LogBufferSizeDef = 32 * 1024 // 日志缓冲区大小 (>0)
|
||||
|
||||
// stat
|
||||
StatEnableDef = false //
|
||||
|
||||
StatFlushFreqDef = 3 // 日志刷盘时间s (>=0)
|
||||
|
||||
StatSlowSqlCountDef = 100 // 慢sql top行数,(0-1000)
|
||||
|
||||
StatHighFreqSqlCountDef = 100 // 高频sql top行数, (0-1000)
|
||||
|
||||
StatSqlMaxCountDef = 100000 // sql 统计最大值(0-100000)
|
||||
|
||||
StatSqlRemoveModeDef = STAT_SQL_REMOVE_LATEST // 记录sql数超过最大值时,sql淘汰方式
|
||||
|
||||
ClobToBytesDef = false //Clob是否转换为bytes
|
||||
)
|
||||
|
||||
var (
|
||||
DbAliveCheckFreq = DbAliveCheckFreqDef
|
||||
|
||||
Locale = LocaleDef // 0:简体中文 1:英文 2:繁体中文
|
||||
|
||||
// log
|
||||
LogLevel = LogLevelDef // 日志级别:off, error, warn, sql, info, all
|
||||
|
||||
LogDir = LogDirDef
|
||||
|
||||
LogFlushFreq = LogFlushFreqDef // 日志刷盘时间s (>=0)
|
||||
|
||||
LogFlushQueueSize = LogFlushQueueSizeDef
|
||||
|
||||
LogBufferSize = LogBufferSizeDef // 日志缓冲区大小 (>0)
|
||||
|
||||
// stat
|
||||
StatEnable = StatEnableDef //
|
||||
|
||||
StatDir = StatDirDef // jdbc工作目录,所有生成的文件都在该目录下
|
||||
|
||||
StatFlushFreq = StatFlushFreqDef // 日志刷盘时间s (>=0)
|
||||
|
||||
StatSlowSqlCount = StatSlowSqlCountDef // 慢sql top行数,(0-1000)
|
||||
|
||||
StatHighFreqSqlCount = StatHighFreqSqlCountDef // 高频sql top行数, (0-1000)
|
||||
|
||||
StatSqlMaxCount = StatSqlMaxCountDef // sql 统计最大值(0-100000)
|
||||
|
||||
StatSqlRemoveMode = StatSqlRemoveModeDef // 记录sql数超过最大值时,sql淘汰方式
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
ServerGroupMap sync.Map
|
||||
|
||||
GlobalProperties = NewProperties()
|
||||
)
|
||||
|
||||
// filePath: dm_svc.conf 文件路径
|
||||
func load(filePath string) {
|
||||
if filePath == "" {
|
||||
// 如果设置了环境变量则环境变量优先
|
||||
filePath = os.Getenv("DM_SVC_PATH")
|
||||
if filePath == "" {
|
||||
// 否则使用默认
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
filePath = os.Getenv("SystemRoot") + "\\system32\\dm_svc.conf"
|
||||
case "linux":
|
||||
filePath = "/etc/dm_svc.conf"
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果设置了连接串上svcConfPath,则串上优先
|
||||
file, err := os.Open(filePath)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fileReader := bufio.NewReader(file)
|
||||
|
||||
// GlobalProperties = NewProperties()
|
||||
var groupProps *Properties
|
||||
var line string //dm_svc.conf读取到的一行
|
||||
|
||||
for line, err = fileReader.ReadString('\n'); line != "" && (err == nil || err == io.EOF); line, err = fileReader.ReadString('\n') {
|
||||
// 去除#标记的注释
|
||||
if notesIndex := strings.IndexByte(line, '#'); notesIndex != -1 {
|
||||
line = line[:notesIndex]
|
||||
}
|
||||
// 去除前后多余的空格
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
||||
groupName := strings.ToLower(line[1 : len(line)-1])
|
||||
dbGroup, ok := ServerGroupMap.Load(groupName)
|
||||
if groupName == "" || !ok {
|
||||
continue
|
||||
}
|
||||
groupProps = dbGroup.(*epGroup).props
|
||||
if groupProps.IsNil() {
|
||||
groupProps = NewProperties()
|
||||
groupProps.SetProperties(GlobalProperties)
|
||||
dbGroup.(*epGroup).props = groupProps
|
||||
}
|
||||
|
||||
} else {
|
||||
cfgInfo := [2]string{}
|
||||
if index := strings.Index(line, "="); index > 0 {
|
||||
cfgInfo[0] = line[0:index]
|
||||
cfgInfo[1] = line[index+1:]
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
key := strings.TrimSpace(cfgInfo[0])
|
||||
value := strings.TrimSpace(cfgInfo[1])
|
||||
if strings.HasPrefix(value, "(") && strings.HasSuffix(value, ")") {
|
||||
value = strings.TrimSpace(value[1 : len(value)-1])
|
||||
}
|
||||
if key == "" || value == "" {
|
||||
continue
|
||||
}
|
||||
// 区分属性是全局的还是组的
|
||||
var success bool
|
||||
if groupProps.IsNil() {
|
||||
success = SetServerGroupProperties(GlobalProperties, key, value)
|
||||
} else {
|
||||
success = SetServerGroupProperties(groupProps, key, value)
|
||||
}
|
||||
if !success {
|
||||
var serverGroup = parseServerName(key, value)
|
||||
if serverGroup != nil {
|
||||
serverGroup.props = NewProperties()
|
||||
serverGroup.props.SetProperties(GlobalProperties)
|
||||
ServerGroupMap.Store(strings.ToLower(key), serverGroup)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetServerGroupProperties(props *Properties, key string, value string) bool {
|
||||
key = strings.ToUpper(key)
|
||||
if key == "ADDRESS_REMAP" {
|
||||
tmp := props.GetString(AddressRemapKey, "")
|
||||
props.Set(AddressRemapKey, tmp+"("+value+")")
|
||||
} else if key == "ALWAYS_ALLOW_COMMIT" {
|
||||
props.Set(AlwayseAllowCommitKey, value)
|
||||
} else if key == "APP_NAME" {
|
||||
props.Set(AppNameKey, value)
|
||||
} else if key == "AUTO_COMMIT" {
|
||||
props.Set(AutoCommitKey, value)
|
||||
} else if key == "BATCH_ALLOW_MAX_ERRORS" {
|
||||
props.Set(BatchAllowMaxErrorsKey, value)
|
||||
} else if key == "BATCH_CONTINUE_ON_ERROR" ||
|
||||
key == "CONTINUE_BATCH_ON_ERROR" {
|
||||
props.Set(ContinueBatchOnErrorKey, value)
|
||||
} else if key == "BATCH_NOT_ON_CALL" {
|
||||
props.Set(BatchNotOnCallKey, value)
|
||||
} else if key == "BATCH_TYPE" {
|
||||
props.Set(BatchTypeKey, value)
|
||||
} else if key == "BUF_PREFETCH" {
|
||||
props.Set(BufPrefetchKey, value)
|
||||
} else if key == "CIPHER_PATH" {
|
||||
props.Set(CipherPathKey, value)
|
||||
} else if key == "CLUSTER" {
|
||||
props.Set(ClusterKey, value)
|
||||
} else if key == "COLUMN_NAME_UPPER_CASE" {
|
||||
props.Set(ColumnNameUpperCaseKey, value)
|
||||
} else if key == "COLUMN_NAME_CASE" {
|
||||
props.Set(ColumnNameCaseKey, value)
|
||||
} else if key == "COMPATIBLE_MODE" {
|
||||
props.Set(CompatibleModeKey, value)
|
||||
} else if key == "COMPRESS" ||
|
||||
key == "COMPRESS_MSG" {
|
||||
props.Set(CompressKey, value)
|
||||
} else if key == "COMPRESS_ID" {
|
||||
props.Set(CompressIdKey, value)
|
||||
} else if key == "CONNECT_TIMEOUT" {
|
||||
props.Set(ConnectTimeoutKey, value)
|
||||
} else if key == "DO_SWITCH" ||
|
||||
key == "AUTO_RECONNECT" {
|
||||
props.Set(DoSwitchKey, value)
|
||||
} else if key == "ENABLE_RS_CACHE" {
|
||||
props.Set(EnRsCacheKey, value)
|
||||
} else if key == "EP_SELECTION" {
|
||||
props.Set(EpSelectorKey, value)
|
||||
} else if key == "ESCAPE_PROCESS" {
|
||||
props.Set(EscapeProcessKey, value)
|
||||
} else if key == "IS_BDTA_RS" {
|
||||
props.Set(IsBdtaRSKey, value)
|
||||
} else if key == "KEY_WORDS" ||
|
||||
key == "KEYWORDS" {
|
||||
props.Set(KeywordsKey, value)
|
||||
} else if key == "LANGUAGE" {
|
||||
props.Set(LanguageKey, value)
|
||||
} else if key == "LOB_MODE" {
|
||||
props.Set(LobModeKey, value)
|
||||
} else if key == "LOG_BUFFER_SIZE" {
|
||||
props.Set(LogBufferSizeKey, value)
|
||||
} else if key == "LOG_DIR" {
|
||||
props.Set(LogDirKey, value)
|
||||
} else if key == "LOG_FLUSH_FREQ" {
|
||||
props.Set(LogFlushFreqKey, value)
|
||||
} else if key == "LOG_FLUSHER_QUEUESIZE" {
|
||||
props.Set(LogFlusherQueueSizeKey, value)
|
||||
} else if key == "LOG_LEVEL" {
|
||||
props.Set(LogLevelKey, value)
|
||||
} else if key == "LOGIN_DSC_CTRL" {
|
||||
props.Set(LoginDscCtrlKey, value)
|
||||
} else if key == "LOGIN_ENCRYPT" {
|
||||
props.Set(LoginEncryptKey, value)
|
||||
} else if key == "LOGIN_MODE" {
|
||||
props.Set(LoginModeKey, value)
|
||||
} else if key == "LOGIN_STATUS" {
|
||||
props.Set(LoginStatusKey, value)
|
||||
} else if key == "MAX_ROWS" {
|
||||
props.Set(MaxRowsKey, value)
|
||||
} else if key == "MPP_LOCAL" {
|
||||
props.Set(MppLocalKey, value)
|
||||
} else if key == "OS_NAME" {
|
||||
props.Set(OsNameKey, value)
|
||||
} else if key == "RS_CACHE_SIZE" {
|
||||
props.Set(RsCacheSizeKey, value)
|
||||
} else if key == "RS_REFRESH_FREQ" {
|
||||
props.Set(RsRefreshFreqKey, value)
|
||||
} else if key == "RW_HA" {
|
||||
props.Set(RwHAKey, value)
|
||||
} else if key == "RW_IGNORE_SQL" {
|
||||
props.Set(RwIgnoreSqlKey, value)
|
||||
} else if key == "RW_PERCENT" {
|
||||
props.Set(RwPercentKey, value)
|
||||
} else if key == "RW_SEPARATE" {
|
||||
props.Set(RwSeparateKey, value)
|
||||
} else if key == "RW_STANDBY_RECOVER_TIME" {
|
||||
props.Set(RwStandbyRecoverTimeKey, value)
|
||||
} else if key == "SCHEMA" {
|
||||
props.Set(SchemaKey, value)
|
||||
} else if key == "CATALOG" {
|
||||
props.Set(CatalogKey, value)
|
||||
} else if key == "SESS_ENCODE" {
|
||||
if IsSupportedCharset(value) {
|
||||
props.Set("sessEncode", value)
|
||||
}
|
||||
} else if key == "SESSION_TIMEOUT" {
|
||||
props.Set(SessionTimeoutKey, value)
|
||||
} else if key == "SOCKET_TIMEOUT" {
|
||||
props.Set(SocketTimeoutKey, value)
|
||||
} else if key == "SSL_CERT_PATH" {
|
||||
props.Set(SslCertPathKey, value)
|
||||
} else if key == "SSL_FILES_PATH" {
|
||||
props.Set(SslFilesPathKey, value)
|
||||
} else if key == "SSL_KEY_PATH" {
|
||||
props.Set(SslKeyPathKey, value)
|
||||
} else if key == "STAT_DIR" {
|
||||
props.Set(StatDirKey, value)
|
||||
} else if key == "STAT_ENABLE" {
|
||||
props.Set(StatEnableKey, value)
|
||||
} else if key == "STAT_FLUSH_FREQ" {
|
||||
props.Set(StatFlushFreqKey, value)
|
||||
} else if key == "STAT_HIGH_FREQ_SQL_COUNT" {
|
||||
props.Set(StatHighFreqSqlCountKey, value)
|
||||
} else if key == "STAT_SLOW_SQL_COUNT" {
|
||||
props.Set(StatSlowSqlCountKey, value)
|
||||
} else if key == "STAT_SQL_MAX_COUNT" {
|
||||
props.Set(StatSqlMaxCountKey, value)
|
||||
} else if key == "STAT_SQL_REMOVE_MODE" {
|
||||
props.Set(StatSqlRemoveModeKey, value)
|
||||
} else if key == "SWITCH_INTERVAL" {
|
||||
props.Set(SwitchIntervalKey, value)
|
||||
} else if key == "SWITCH_TIME" ||
|
||||
key == "SWITCH_TIMES" {
|
||||
props.Set(SwitchTimesKey, value)
|
||||
} else if key == "TIME_ZONE" {
|
||||
props.Set(TimeZoneKey, value)
|
||||
props.Set("localTimezone", value)
|
||||
} else if key == "USER_REMAP" {
|
||||
tmp := props.GetString(UserRemapKey, "")
|
||||
props.Set(UserRemapKey, tmp+"("+value+")")
|
||||
} else if key == "SERVER_OPTION" {
|
||||
props.Set(ServerOptionKey, value)
|
||||
} else if key == "CLOB_TO_BYTES" {
|
||||
props.Set(ClobToBytesKey, value)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func parseServerName(name string, value string) *epGroup {
|
||||
values := strings.Split(value, ",")
|
||||
|
||||
var tmpVals []string
|
||||
var tmpName string
|
||||
var tmpPort int
|
||||
var svrList = make([]*ep, 0, len(values))
|
||||
|
||||
for _, v := range values {
|
||||
|
||||
var tmp *ep
|
||||
// 先查找IPV6,以[]包括
|
||||
begin := strings.IndexByte(v, '[')
|
||||
end := -1
|
||||
if begin != -1 {
|
||||
end = strings.IndexByte(v[begin:], ']')
|
||||
}
|
||||
if end != -1 {
|
||||
//tmpName = v[begin+1 : end]
|
||||
tmpName = v[begin : end+1]
|
||||
|
||||
// port
|
||||
if portIndex := strings.IndexByte(v[end:], ':'); portIndex != -1 {
|
||||
tmpPort, _ = strconv.Atoi(strings.TrimSpace(v[end+portIndex+1:]))
|
||||
} else {
|
||||
tmpPort = int(DEFAULT_PORT)
|
||||
}
|
||||
tmp = newEP(tmpName, int32(tmpPort))
|
||||
svrList = append(svrList, tmp)
|
||||
continue
|
||||
}
|
||||
// IPV4
|
||||
tmpVals = strings.Split(v, ":")
|
||||
tmpName = strings.TrimSpace(tmpVals[0])
|
||||
if len(tmpVals) >= 2 {
|
||||
tmpPort, _ = strconv.Atoi(tmpVals[1])
|
||||
} else {
|
||||
tmpPort = int(DEFAULT_PORT)
|
||||
}
|
||||
tmp = newEP(tmpName, int32(tmpPort))
|
||||
svrList = append(svrList, tmp)
|
||||
}
|
||||
|
||||
if len(svrList) == 0 {
|
||||
return nil
|
||||
}
|
||||
return newEPGroup(name, svrList)
|
||||
}
|
||||
|
||||
func setDriverAttributes(props *Properties) {
|
||||
if props == nil || props.Len() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
parseLanguage(props.GetString(LanguageKey, "cn"))
|
||||
DbAliveCheckFreq = props.GetInt(DbAliveCheckFreqKey, DbAliveCheckFreqDef, 1, int(INT32_MAX))
|
||||
//// log
|
||||
//LogLevel = ParseLogLevel(props)
|
||||
//LogDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef))
|
||||
//LogBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX))
|
||||
//LogFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX))
|
||||
//LogFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX))
|
||||
//
|
||||
//// stat
|
||||
//StatEnable = props.GetBool(StatEnableKey, StatEnableDef)
|
||||
//StatDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef))
|
||||
//StatFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX))
|
||||
//StatHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000)
|
||||
//StatSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000)
|
||||
//StatSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000)
|
||||
//parseStatSqlRemoveMode(props)
|
||||
}
|
||||
|
||||
func parseLanguage(value string) {
|
||||
if util.StringUtil.EqualsIgnoreCase("cn", value) {
|
||||
Locale = 0
|
||||
} else if util.StringUtil.EqualsIgnoreCase("en", value) {
|
||||
Locale = 1
|
||||
} else if util.StringUtil.EqualsIgnoreCase("cnt_hk", value) ||
|
||||
util.StringUtil.EqualsIgnoreCase("hk", value) ||
|
||||
util.StringUtil.EqualsIgnoreCase("tw", value) {
|
||||
Locale = 2
|
||||
}
|
||||
}
|
||||
|
||||
func IsSupportedCharset(charset string) bool {
|
||||
if util.StringUtil.EqualsIgnoreCase(ENCODING_UTF8, charset) ||
|
||||
util.StringUtil.EqualsIgnoreCase(ENCODING_GB18030, charset) ||
|
||||
util.StringUtil.EqualsIgnoreCase(ENCODING_EUCKR, charset) ||
|
||||
util.StringUtil.EqualsIgnoreCase(ENCODING_BIG5, charset) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ParseLogLevel(props *Properties) int {
|
||||
logLevel := LOG_OFF
|
||||
value := props.GetString(LogLevelKey, "")
|
||||
if value != "" && !util.StringUtil.IsDigit(value) {
|
||||
if util.StringUtil.EqualsIgnoreCase("debug", value) {
|
||||
logLevel = LOG_DEBUG
|
||||
} else if util.StringUtil.EqualsIgnoreCase("info", value) {
|
||||
logLevel = LOG_INFO
|
||||
} else if util.StringUtil.EqualsIgnoreCase("sql", value) {
|
||||
logLevel = LOG_SQL
|
||||
} else if util.StringUtil.EqualsIgnoreCase("warn", value) {
|
||||
logLevel = LOG_WARN
|
||||
} else if util.StringUtil.EqualsIgnoreCase("error", value) {
|
||||
logLevel = LOG_ERROR
|
||||
} else if util.StringUtil.EqualsIgnoreCase("off", value) {
|
||||
logLevel = LOG_OFF
|
||||
} else if util.StringUtil.EqualsIgnoreCase("all", value) {
|
||||
logLevel = LOG_ALL
|
||||
}
|
||||
} else {
|
||||
logLevel = props.GetInt(LogLevelKey, logLevel, LOG_OFF, LOG_INFO)
|
||||
}
|
||||
|
||||
return logLevel
|
||||
}
|
||||
+450
@@ -0,0 +1,450 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
INT8_MAX int8 = math.MaxInt8
|
||||
|
||||
INT8_MIN int8 = math.MinInt8
|
||||
|
||||
BYTE_MAX byte = math.MaxUint8
|
||||
|
||||
BYTE_MIN byte = 0
|
||||
|
||||
INT16_MAX int16 = math.MaxInt16
|
||||
|
||||
INT16_MIN int16 = math.MinInt16
|
||||
|
||||
UINT16_MAX uint16 = math.MaxUint16
|
||||
|
||||
UINT16_MIN uint16 = 0
|
||||
|
||||
INT32_MAX int32 = math.MaxInt32
|
||||
|
||||
INT32_MIN int32 = math.MinInt32
|
||||
|
||||
UINT32_MAX uint32 = math.MaxUint32
|
||||
|
||||
UINT32_MIN uint32 = 0
|
||||
|
||||
INT64_MAX int64 = math.MaxInt64
|
||||
|
||||
INT64_MIN int64 = math.MinInt64
|
||||
|
||||
UINT64_MAX uint64 = math.MaxUint64
|
||||
|
||||
UINT64_MIN uint64 = 0
|
||||
|
||||
FLOAT32_MAX float32 = 3.4e+38
|
||||
|
||||
FLOAT32_MIN float32 = -3.4e+38
|
||||
|
||||
BYTE_SIZE = 1
|
||||
|
||||
USINT_SIZE = 2
|
||||
|
||||
ULINT_SIZE = 4
|
||||
|
||||
DDWORD_SIZE = 8
|
||||
|
||||
LINT64_SIZE = 8
|
||||
|
||||
CHAR = 0
|
||||
|
||||
VARCHAR2 = 1
|
||||
|
||||
VARCHAR = 2
|
||||
|
||||
BIT = 3
|
||||
|
||||
TINYINT = 5
|
||||
|
||||
SMALLINT = 6
|
||||
|
||||
INT = 7
|
||||
|
||||
BIGINT = 8
|
||||
|
||||
DECIMAL = 9
|
||||
|
||||
REAL = 10
|
||||
|
||||
DOUBLE = 11
|
||||
|
||||
BLOB = 12
|
||||
|
||||
BOOLEAN = 13
|
||||
|
||||
DATE = 14
|
||||
|
||||
TIME = 15
|
||||
|
||||
DATETIME = 16
|
||||
|
||||
BINARY = 17
|
||||
|
||||
VARBINARY = 18
|
||||
|
||||
CLOB = 19
|
||||
|
||||
INTERVAL_YM = 20
|
||||
|
||||
INTERVAL_DT = 21
|
||||
|
||||
TIME_TZ = 22
|
||||
|
||||
DATETIME_TZ = 23
|
||||
|
||||
XDEC_INT32 = 24
|
||||
|
||||
XDEC_INT64 = 25
|
||||
|
||||
DATETIME2 = 26
|
||||
|
||||
DATETIME2_TZ = 27
|
||||
|
||||
NULL = 28
|
||||
|
||||
ANY = 31
|
||||
|
||||
STAR_ALL = 32
|
||||
|
||||
STAR = 33
|
||||
|
||||
RECORD = 40
|
||||
|
||||
TYPE = 41
|
||||
|
||||
TYPE_REF = 42
|
||||
|
||||
UNKNOWN = 54
|
||||
|
||||
ARRAY = 117
|
||||
|
||||
CLASS = 119
|
||||
|
||||
CURSOR = 120
|
||||
|
||||
PLTYPE_RECORD = 121
|
||||
|
||||
SARRAY = 122
|
||||
|
||||
CURSOR_ORACLE = -10
|
||||
|
||||
BIT_PREC = BYTE_SIZE
|
||||
|
||||
TINYINT_PREC = BYTE_SIZE
|
||||
|
||||
SMALLINT_PREC = USINT_SIZE
|
||||
|
||||
INT_PREC = ULINT_SIZE
|
||||
|
||||
BIGINT_PREC = LINT64_SIZE
|
||||
|
||||
REAL_PREC = 4
|
||||
|
||||
DOUBLE_PREC = 8
|
||||
|
||||
DATE_PREC = 3
|
||||
|
||||
TIME_PREC = 5
|
||||
|
||||
DATETIME_PREC = 8
|
||||
|
||||
DATETIME2_PREC = 9
|
||||
|
||||
TIME_TZ_PREC = TIME_PREC + 2
|
||||
|
||||
DATETIME_TZ_PREC = DATETIME_PREC + 2
|
||||
|
||||
DATETIME2_TZ_PREC = DATETIME2_PREC + 2
|
||||
|
||||
INTERVAL_YM_PREC = 3 * ULINT_SIZE
|
||||
|
||||
INTERVAL_DT_PREC = 6 * ULINT_SIZE
|
||||
|
||||
VARCHAR_PREC = 8188
|
||||
|
||||
VARBINARY_PREC = 8188
|
||||
|
||||
BLOB_PREC int32 = INT32_MAX
|
||||
|
||||
CLOB_PREC int32 = INT32_MAX
|
||||
|
||||
NULL_PREC = 0
|
||||
|
||||
LOCAL_TIME_ZONE_SCALE_MASK = 0x00001000
|
||||
|
||||
BFILE_PREC = 512
|
||||
|
||||
BFILE_SCALE = 6
|
||||
|
||||
COMPLEX_SCALE = 5
|
||||
|
||||
CURRENCY_PREC = 19
|
||||
|
||||
CURRENCY_SCALE = 4
|
||||
|
||||
LOCAL_DATETIME_SCALE_MASK int32 = 0x00001000
|
||||
|
||||
ORACLE_FLOAT_SCALE_MASK int32 = 0x81
|
||||
|
||||
ORACLE_DATE_SCALE_MASK int32 = 0x00002000
|
||||
)
|
||||
|
||||
func isComplexType(colType int, scale int) bool {
|
||||
return (colType == BLOB && scale == COMPLEX_SCALE) || colType == ARRAY || colType == SARRAY || colType == CLASS || colType == PLTYPE_RECORD
|
||||
}
|
||||
|
||||
func isLocalTimeZone(colType int, scale int) bool {
|
||||
return (colType == DATETIME || colType == DATETIME2) && (scale&LOCAL_TIME_ZONE_SCALE_MASK) != 0
|
||||
}
|
||||
|
||||
func getLocalTimeZoneScale(colType int, scale int) int {
|
||||
return scale & (^LOCAL_TIME_ZONE_SCALE_MASK)
|
||||
}
|
||||
|
||||
func isFloat(colType int, scale int) bool {
|
||||
return colType == DECIMAL && scale == int(ORACLE_FLOAT_SCALE_MASK)
|
||||
}
|
||||
|
||||
func getFloatPrec(prec int) int {
|
||||
return int(math.Round(float64(prec)*0.30103)) + 1
|
||||
}
|
||||
|
||||
func getFloatScale(scale int) int {
|
||||
return scale & (^int(ORACLE_FLOAT_SCALE_MASK))
|
||||
}
|
||||
|
||||
var (
|
||||
scanTypeFloat32 = reflect.TypeOf(float32(0))
|
||||
scanTypeFloat64 = reflect.TypeOf(float64(0))
|
||||
scanTypeBool = reflect.TypeOf(false)
|
||||
scanTypeInt8 = reflect.TypeOf(int8(0))
|
||||
scanTypeInt16 = reflect.TypeOf(int16(0))
|
||||
scanTypeInt32 = reflect.TypeOf(int32(0))
|
||||
scanTypeInt64 = reflect.TypeOf(int64(0))
|
||||
scanTypeNullBool = reflect.TypeOf(sql.NullBool{})
|
||||
scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
|
||||
scanTypeNullInt = reflect.TypeOf(sql.NullInt64{})
|
||||
scanTypeNullString = reflect.TypeOf(sql.NullString{})
|
||||
scanTypeNullTime = reflect.TypeOf(sql.NullTime{})
|
||||
scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{})
|
||||
scanTypeString = reflect.TypeOf("")
|
||||
scanTypeTime = reflect.TypeOf(time.Now())
|
||||
scanTypeUnknown = reflect.TypeOf(new(interface{}))
|
||||
)
|
||||
|
||||
func (column *column) ScanType() reflect.Type {
|
||||
|
||||
switch column.colType {
|
||||
case BOOLEAN:
|
||||
if column.nullable {
|
||||
return scanTypeNullBool
|
||||
}
|
||||
|
||||
return scanTypeBool
|
||||
|
||||
case BIT:
|
||||
if strings.ToLower(column.typeName) == "boolean" {
|
||||
|
||||
if column.nullable {
|
||||
return scanTypeNullBool
|
||||
}
|
||||
|
||||
return scanTypeBool
|
||||
} else {
|
||||
|
||||
if column.nullable {
|
||||
return scanTypeNullInt
|
||||
}
|
||||
return scanTypeInt8
|
||||
}
|
||||
|
||||
case TINYINT:
|
||||
if column.nullable {
|
||||
return scanTypeNullInt
|
||||
}
|
||||
return scanTypeInt8
|
||||
|
||||
case SMALLINT:
|
||||
if column.nullable {
|
||||
return scanTypeNullInt
|
||||
}
|
||||
return scanTypeInt16
|
||||
|
||||
case INT:
|
||||
if column.nullable {
|
||||
return scanTypeNullInt
|
||||
}
|
||||
|
||||
return scanTypeInt32
|
||||
|
||||
case BIGINT:
|
||||
if column.nullable {
|
||||
return scanTypeNullInt
|
||||
}
|
||||
return scanTypeInt64
|
||||
|
||||
case REAL:
|
||||
if column.nullable {
|
||||
return scanTypeNullFloat
|
||||
}
|
||||
|
||||
return scanTypeFloat32
|
||||
|
||||
case DOUBLE:
|
||||
|
||||
if strings.ToLower(column.typeName) == "float" {
|
||||
if column.nullable {
|
||||
return scanTypeNullFloat
|
||||
}
|
||||
|
||||
return scanTypeFloat32
|
||||
}
|
||||
|
||||
if column.nullable {
|
||||
return scanTypeNullFloat
|
||||
}
|
||||
|
||||
return scanTypeFloat64
|
||||
case DATE, TIME, TIME_TZ, DATETIME, DATETIME_TZ, DATETIME2, DATETIME2_TZ:
|
||||
if column.nullable {
|
||||
return scanTypeNullTime
|
||||
}
|
||||
|
||||
return scanTypeTime
|
||||
|
||||
case DECIMAL, BINARY, VARBINARY, BLOB:
|
||||
return scanTypeRawBytes
|
||||
|
||||
case CHAR, VARCHAR2, VARCHAR, CLOB:
|
||||
if column.nullable {
|
||||
return scanTypeNullString
|
||||
}
|
||||
return scanTypeString
|
||||
}
|
||||
|
||||
return scanTypeUnknown
|
||||
}
|
||||
|
||||
func (column *column) Length() (length int64, ok bool) {
|
||||
switch column.colType {
|
||||
case BINARY, VARBINARY, BLOB, CHAR, VARCHAR2, VARCHAR, CLOB:
|
||||
return int64(column.prec), true
|
||||
}
|
||||
|
||||
return int64(0), false
|
||||
}
|
||||
|
||||
func (column *column) PrecisionScale() (precision, scale int64, ok bool) {
|
||||
switch column.colType {
|
||||
case DECIMAL:
|
||||
if column.prec == 0 {
|
||||
return 38, int64(column.scale), true
|
||||
} else {
|
||||
return int64(column.prec), int64(column.scale), true
|
||||
}
|
||||
}
|
||||
|
||||
return int64(0), int64(0), false
|
||||
}
|
||||
|
||||
func (column *column) getColumnData(bytes []byte, conn *DmConnection) (driver.Value, error) {
|
||||
if bytes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch column.colType {
|
||||
case BOOLEAN:
|
||||
return bytes[0] != 0, nil
|
||||
case BIT:
|
||||
if strings.ToLower(column.typeName) == "boolean" {
|
||||
return bytes[0] != 0, nil
|
||||
}
|
||||
|
||||
return int8(bytes[0]), nil
|
||||
case TINYINT:
|
||||
return int8(bytes[0]), nil
|
||||
case SMALLINT:
|
||||
return Dm_build_1346.Dm_build_1443(bytes, 0), nil
|
||||
case INT:
|
||||
return Dm_build_1346.Dm_build_1448(bytes, 0), nil
|
||||
case BIGINT:
|
||||
return Dm_build_1346.Dm_build_1453(bytes, 0), nil
|
||||
case REAL:
|
||||
return Dm_build_1346.Dm_build_1458(bytes, 0), nil
|
||||
case DOUBLE:
|
||||
|
||||
return Dm_build_1346.Dm_build_1462(bytes, 0), nil
|
||||
case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ:
|
||||
return DB2G.toTime(bytes, column, conn)
|
||||
case INTERVAL_DT:
|
||||
return newDmIntervalDTByBytes(bytes).String(), nil
|
||||
case INTERVAL_YM:
|
||||
return newDmIntervalYMByBytes(bytes).String(), nil
|
||||
case DECIMAL:
|
||||
tmp, err := DB2G.toDmDecimal(bytes, column, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tmp.String(), nil
|
||||
|
||||
case BINARY, VARBINARY:
|
||||
return bytes, nil
|
||||
case BLOB:
|
||||
if isComplexType(int(column.colType), int(column.scale)) {
|
||||
return DB2G.toComplexType(bytes, column, conn)
|
||||
}
|
||||
blob := DB2G.toDmBlob(bytes, column, conn)
|
||||
|
||||
l, err := blob.GetLength()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blob.getBytes(1, int32(l))
|
||||
|
||||
case CHAR, VARCHAR2, VARCHAR:
|
||||
return Dm_build_1346.Dm_build_1503(bytes, 0, len(bytes), conn.getServerEncoding(), conn), nil
|
||||
case CLOB:
|
||||
clob := DB2G.toDmClob(bytes, conn, column)
|
||||
|
||||
l, err := clob.GetLength()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
str, err := clob.getSubString(1, int32(l))
|
||||
if err != nil {
|
||||
return str, err
|
||||
}
|
||||
if conn.dmConnector.clobToBytes {
|
||||
return []byte(str), err
|
||||
} else {
|
||||
return str, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
func emptyStringToNil(t int32) bool {
|
||||
switch t {
|
||||
case BOOLEAN, BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, DOUBLE, DECIMAL, DATE, TIME,
|
||||
DATETIME, INTERVAL_DT, INTERVAL_YM, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
+1389
File diff suppressed because it is too large
Load Diff
+763
@@ -0,0 +1,763 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2018, 达梦数据库有限公司.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package dm
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
)
|
||||
|
||||
const (
|
||||
OBJ_BLOB_MAGIC = 78111999
|
||||
|
||||
CLTN_TYPE_IND_TABLE = 3
|
||||
|
||||
CLTN_TYPE_NST_TABLE = 2
|
||||
|
||||
CLTN_TYPE_VARRAY = 1
|
||||
)
|
||||
|
||||
type TypeDescriptor struct {
|
||||
column *column
|
||||
|
||||
m_sqlName *sqlName
|
||||
|
||||
m_objId int
|
||||
|
||||
m_objVersion int
|
||||
|
||||
m_outerId int
|
||||
|
||||
m_outerVer int
|
||||
|
||||
m_subId int
|
||||
|
||||
m_cltnType int
|
||||
|
||||
m_maxCnt int
|
||||
|
||||
m_length int
|
||||
|
||||
m_size int
|
||||
|
||||
m_conn *DmConnection
|
||||
|
||||
m_serverEncoding string
|
||||
|
||||
m_arrObj *TypeDescriptor
|
||||
|
||||
m_fieldsObj []TypeDescriptor
|
||||
|
||||
m_descBuf []byte
|
||||
}
|
||||
|
||||
func newTypeDescriptorWithFulName(fulName string, conn *DmConnection) *TypeDescriptor {
|
||||
td := new(TypeDescriptor)
|
||||
td.init()
|
||||
td.m_sqlName = newSqlNameByFulName(fulName)
|
||||
td.m_conn = conn
|
||||
return td
|
||||
}
|
||||
|
||||
func newTypeDescriptor(conn *DmConnection) *TypeDescriptor {
|
||||
td := new(TypeDescriptor)
|
||||
td.init()
|
||||
td.m_sqlName = newSqlNameByConn(conn)
|
||||
td.m_conn = conn
|
||||
return td
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) init() {
|
||||
typeDescriptor.column = new(column).InitColumn()
|
||||
|
||||
typeDescriptor.m_sqlName = nil
|
||||
|
||||
typeDescriptor.m_objId = -1
|
||||
|
||||
typeDescriptor.m_objVersion = -1
|
||||
|
||||
typeDescriptor.m_outerId = 0
|
||||
|
||||
typeDescriptor.m_outerVer = 0
|
||||
|
||||
typeDescriptor.m_subId = 0
|
||||
|
||||
typeDescriptor.m_cltnType = 0
|
||||
|
||||
typeDescriptor.m_maxCnt = 0
|
||||
|
||||
typeDescriptor.m_length = 0
|
||||
|
||||
typeDescriptor.m_size = 0
|
||||
|
||||
typeDescriptor.m_conn = nil
|
||||
|
||||
typeDescriptor.m_serverEncoding = ""
|
||||
|
||||
typeDescriptor.m_arrObj = nil
|
||||
|
||||
typeDescriptor.m_fieldsObj = nil
|
||||
|
||||
typeDescriptor.m_descBuf = nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) parseDescByName() error {
|
||||
sql := "BEGIN ? = SF_DESCRIBE_TYPE(?); END;"
|
||||
|
||||
params := make([]driver.Value, 2)
|
||||
params[1] = typeDescriptor.m_sqlName.m_fulName
|
||||
|
||||
rs, err := typeDescriptor.m_conn.query(sql, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rs.close()
|
||||
l, err := params[0].(*DmBlob).GetLength()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf, err := params[0].(*DmBlob).getBytes(1, int32(l))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
typeDescriptor.m_serverEncoding = typeDescriptor.m_conn.getServerEncoding()
|
||||
err = typeDescriptor.unpack(Dm_build_83(buf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getFulName() (string, error) {
|
||||
return typeDescriptor.m_sqlName.getFulName()
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getDType() int {
|
||||
return int(typeDescriptor.column.colType)
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getPrec() int {
|
||||
return int(typeDescriptor.column.prec)
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getScale() int {
|
||||
return int(typeDescriptor.column.scale)
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getServerEncoding() string {
|
||||
if typeDescriptor.m_serverEncoding == "" {
|
||||
return typeDescriptor.m_conn.getServerEncoding()
|
||||
} else {
|
||||
return typeDescriptor.m_serverEncoding
|
||||
}
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getObjId() int {
|
||||
return typeDescriptor.m_objId
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getStaticArrayLength() int {
|
||||
return typeDescriptor.m_length
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getStrctMemSize() int {
|
||||
return typeDescriptor.m_size
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getOuterId() int {
|
||||
return typeDescriptor.m_outerId
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getCltnType() int {
|
||||
return typeDescriptor.m_cltnType
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getMaxCnt() int {
|
||||
return typeDescriptor.m_maxCnt
|
||||
}
|
||||
|
||||
func getPackSize(typeDesc *TypeDescriptor) (int, error) {
|
||||
len := 0
|
||||
|
||||
switch typeDesc.column.colType {
|
||||
case ARRAY, SARRAY:
|
||||
return getPackArraySize(typeDesc)
|
||||
|
||||
case CLASS:
|
||||
return getPackClassSize(typeDesc)
|
||||
|
||||
case PLTYPE_RECORD:
|
||||
return getPackRecordSize(typeDesc)
|
||||
}
|
||||
|
||||
len += ULINT_SIZE
|
||||
|
||||
len += ULINT_SIZE
|
||||
|
||||
len += ULINT_SIZE
|
||||
|
||||
return len, nil
|
||||
}
|
||||
|
||||
func pack(typeDesc *TypeDescriptor, msg *Dm_build_78) error {
|
||||
switch typeDesc.column.colType {
|
||||
case ARRAY, SARRAY:
|
||||
return packArray(typeDesc, msg)
|
||||
case CLASS:
|
||||
return packClass(typeDesc, msg)
|
||||
case PLTYPE_RECORD:
|
||||
return packRecord(typeDesc, msg)
|
||||
}
|
||||
|
||||
msg.Dm_build_133(typeDesc.column.colType)
|
||||
|
||||
msg.Dm_build_133(typeDesc.column.prec)
|
||||
|
||||
msg.Dm_build_133(typeDesc.column.scale)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPackArraySize(arrDesc *TypeDescriptor) (int, error) {
|
||||
l := 0
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
name := arrDesc.m_sqlName.m_name
|
||||
l += USINT_SIZE
|
||||
|
||||
serverEncoding := arrDesc.getServerEncoding()
|
||||
ret := Dm_build_1346.Dm_build_1562(name, serverEncoding, arrDesc.m_conn)
|
||||
l += len(ret)
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
i, err := getPackSize(arrDesc.m_arrObj)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
l += i
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func packArray(arrDesc *TypeDescriptor, msg *Dm_build_78) error {
|
||||
|
||||
msg.Dm_build_133(arrDesc.column.colType)
|
||||
|
||||
msg.Dm_build_189(arrDesc.m_sqlName.m_name, arrDesc.getServerEncoding(), arrDesc.m_conn)
|
||||
|
||||
msg.Dm_build_133(int32(arrDesc.m_objId))
|
||||
|
||||
msg.Dm_build_133(int32(arrDesc.m_objVersion))
|
||||
|
||||
msg.Dm_build_133(int32(arrDesc.m_length))
|
||||
|
||||
return pack(arrDesc.m_arrObj, msg)
|
||||
}
|
||||
|
||||
func packRecord(strctDesc *TypeDescriptor, msg *Dm_build_78) error {
|
||||
|
||||
msg.Dm_build_133(strctDesc.column.colType)
|
||||
|
||||
msg.Dm_build_189(strctDesc.m_sqlName.m_name, strctDesc.getServerEncoding(), strctDesc.m_conn)
|
||||
|
||||
msg.Dm_build_133(int32(strctDesc.m_objId))
|
||||
|
||||
msg.Dm_build_133(int32(strctDesc.m_objVersion))
|
||||
|
||||
msg.Dm_build_129(int16(strctDesc.m_size))
|
||||
|
||||
for i := 0; i < strctDesc.m_size; i++ {
|
||||
err := pack(&strctDesc.m_fieldsObj[i], msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPackRecordSize(strctDesc *TypeDescriptor) (int, error) {
|
||||
l := 0
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
name := strctDesc.m_sqlName.m_name
|
||||
l += USINT_SIZE
|
||||
|
||||
serverEncoding := strctDesc.getServerEncoding()
|
||||
ret := Dm_build_1346.Dm_build_1562(name, serverEncoding, strctDesc.m_conn)
|
||||
l += len(ret)
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
l += USINT_SIZE
|
||||
|
||||
for i := 0; i < strctDesc.m_size; i++ {
|
||||
i, err := getPackSize(&strctDesc.m_fieldsObj[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
l += i
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func getPackClassSize(strctDesc *TypeDescriptor) (int, error) {
|
||||
l := 0
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
name := strctDesc.m_sqlName.m_name
|
||||
l += USINT_SIZE
|
||||
|
||||
serverEncoding := strctDesc.getServerEncoding()
|
||||
ret := Dm_build_1346.Dm_build_1562(name, serverEncoding, strctDesc.m_conn)
|
||||
l += len(ret)
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
if strctDesc.m_objId == 4 {
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
l += ULINT_SIZE
|
||||
|
||||
l += USINT_SIZE
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func packClass(strctDesc *TypeDescriptor, msg *Dm_build_78) error {
|
||||
|
||||
msg.Dm_build_133(strctDesc.column.colType)
|
||||
|
||||
msg.Dm_build_189(strctDesc.m_sqlName.m_name, strctDesc.getServerEncoding(), strctDesc.m_conn)
|
||||
|
||||
msg.Dm_build_133(int32(strctDesc.m_objId))
|
||||
|
||||
msg.Dm_build_133(int32(strctDesc.m_objVersion))
|
||||
|
||||
if strctDesc.m_objId == 4 {
|
||||
|
||||
msg.Dm_build_133(int32(strctDesc.m_outerId))
|
||||
|
||||
msg.Dm_build_133(int32(strctDesc.m_outerVer))
|
||||
|
||||
msg.Dm_build_141(uint16(strctDesc.m_subId))
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) unpack(buffer *Dm_build_78) error {
|
||||
|
||||
typeDescriptor.column.colType = buffer.Dm_build_207()
|
||||
|
||||
switch typeDescriptor.column.colType {
|
||||
case ARRAY, SARRAY:
|
||||
return typeDescriptor.unpackArray(buffer)
|
||||
case CLASS:
|
||||
return typeDescriptor.unpackClass(buffer)
|
||||
case PLTYPE_RECORD:
|
||||
return typeDescriptor.unpackRecord(buffer)
|
||||
}
|
||||
|
||||
typeDescriptor.column.prec = buffer.Dm_build_207()
|
||||
|
||||
typeDescriptor.column.scale = buffer.Dm_build_207()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) unpackArray(buffer *Dm_build_78) error {
|
||||
|
||||
typeDescriptor.m_sqlName.m_name = buffer.Dm_build_257(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn)
|
||||
|
||||
typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_objId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_objVersion = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_length = int(buffer.Dm_build_207())
|
||||
if typeDescriptor.column.colType == ARRAY {
|
||||
typeDescriptor.m_length = 0
|
||||
}
|
||||
|
||||
typeDescriptor.m_arrObj = newTypeDescriptor(typeDescriptor.m_conn)
|
||||
return typeDescriptor.m_arrObj.unpack(buffer)
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) unpackRecord(buffer *Dm_build_78) error {
|
||||
|
||||
typeDescriptor.m_sqlName.m_name = buffer.Dm_build_257(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn)
|
||||
|
||||
typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_objId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_objVersion = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_size = int(buffer.Dm_build_222())
|
||||
|
||||
typeDescriptor.m_fieldsObj = make([]TypeDescriptor, typeDescriptor.m_size)
|
||||
for i := 0; i < typeDescriptor.m_size; i++ {
|
||||
typeDescriptor.m_fieldsObj[i] = *newTypeDescriptor(typeDescriptor.m_conn)
|
||||
typeDescriptor.m_fieldsObj[i].unpack(buffer)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) unpackClnt_nestTab(buffer *Dm_build_78) error {
|
||||
|
||||
typeDescriptor.m_maxCnt = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_arrObj = newTypeDescriptor(typeDescriptor.m_conn)
|
||||
|
||||
typeDescriptor.m_arrObj.unpack(buffer)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) unpackClnt(buffer *Dm_build_78) error {
|
||||
|
||||
typeDescriptor.m_outerId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_outerVer = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_subId = int(buffer.Dm_build_222())
|
||||
|
||||
typeDescriptor.m_cltnType = int(buffer.Dm_build_222())
|
||||
|
||||
switch typeDescriptor.m_cltnType {
|
||||
case CLTN_TYPE_IND_TABLE:
|
||||
return ECGO_UNSUPPORTED_TYPE.throw()
|
||||
|
||||
case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY:
|
||||
return typeDescriptor.unpackClnt_nestTab(buffer)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) unpackClass(buffer *Dm_build_78) error {
|
||||
|
||||
typeDescriptor.m_sqlName.m_name = buffer.Dm_build_257(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn)
|
||||
|
||||
typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_objId = int(buffer.Dm_build_207())
|
||||
|
||||
typeDescriptor.m_objVersion = int(buffer.Dm_build_207())
|
||||
|
||||
if typeDescriptor.m_objId == 4 {
|
||||
return typeDescriptor.unpackClnt(buffer)
|
||||
} else {
|
||||
|
||||
typeDescriptor.m_size = int(buffer.Dm_build_222())
|
||||
|
||||
typeDescriptor.m_fieldsObj = make([]TypeDescriptor, typeDescriptor.m_size)
|
||||
for i := 0; i < typeDescriptor.m_size; i++ {
|
||||
typeDescriptor.m_fieldsObj[i] = *newTypeDescriptor(typeDescriptor.m_conn)
|
||||
err := typeDescriptor.m_fieldsObj[i].unpack(buffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func calcChkDescLen_array(desc *TypeDescriptor) (int, error) {
|
||||
offset := 0
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
offset += ULINT_SIZE
|
||||
|
||||
tmp, err := calcChkDescLen(desc)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
offset += tmp
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func calcChkDescLen_record(desc *TypeDescriptor) (int, error) {
|
||||
offset := 0
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
for i := 0; i < desc.m_size; i++ {
|
||||
tmp, err := calcChkDescLen(&desc.m_fieldsObj[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset += tmp
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func calcChkDescLen_class_normal(desc *TypeDescriptor) (int, error) {
|
||||
offset := 0
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
for i := 0; i < desc.m_size; i++ {
|
||||
tmp, err := calcChkDescLen(&desc.m_fieldsObj[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset += tmp
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func calcChkDescLen_class_cnlt(desc *TypeDescriptor) (int, error) {
|
||||
offset := 0
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
offset += ULINT_SIZE
|
||||
|
||||
switch desc.getCltnType() {
|
||||
case CLTN_TYPE_IND_TABLE:
|
||||
return 0, ECGO_UNSUPPORTED_TYPE.throw()
|
||||
|
||||
case CLTN_TYPE_VARRAY, CLTN_TYPE_NST_TABLE:
|
||||
|
||||
i, err := calcChkDescLen(desc.m_arrObj)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
offset += i
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func calcChkDescLen_class(desc *TypeDescriptor) (int, error) {
|
||||
offset := 0
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
offset += BYTE_SIZE
|
||||
|
||||
if desc.m_objId == 4 {
|
||||
i, err := calcChkDescLen_class_cnlt(desc)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset += i
|
||||
} else {
|
||||
i, err := calcChkDescLen_class_normal(desc)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
offset += i
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func calcChkDescLen_buildin() int {
|
||||
offset := 0
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
offset += USINT_SIZE
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
func calcChkDescLen(desc *TypeDescriptor) (int, error) {
|
||||
|
||||
switch desc.getDType() {
|
||||
case ARRAY, SARRAY:
|
||||
return calcChkDescLen_array(desc)
|
||||
|
||||
case PLTYPE_RECORD:
|
||||
return calcChkDescLen_record(desc)
|
||||
|
||||
case CLASS:
|
||||
return calcChkDescLen_class(desc)
|
||||
|
||||
default:
|
||||
return calcChkDescLen_buildin(), nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) makeChkDesc_array(offset int, desc *TypeDescriptor) (int, error) {
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, ARRAY)
|
||||
offset += USINT_SIZE
|
||||
|
||||
Dm_build_1346.Dm_build_1362(typeDescriptor.m_descBuf, offset, int32(desc.m_length))
|
||||
offset += ULINT_SIZE
|
||||
|
||||
return typeDescriptor.makeChkDesc(offset, desc)
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) makeChkDesc_record(offset int, desc *TypeDescriptor) (int, error) {
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, PLTYPE_RECORD)
|
||||
offset += USINT_SIZE
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(desc.m_size))
|
||||
offset += USINT_SIZE
|
||||
var err error
|
||||
for i := 0; i < desc.m_size; i++ {
|
||||
offset, err = typeDescriptor.makeChkDesc(offset, &desc.m_fieldsObj[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) makeChkDesc_buildin(offset int, desc *TypeDescriptor) int {
|
||||
dtype := int16(desc.getDType())
|
||||
prec := 0
|
||||
scale := 0
|
||||
|
||||
if dtype != BLOB {
|
||||
prec = desc.getPrec()
|
||||
scale = desc.getScale()
|
||||
}
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, dtype)
|
||||
offset += USINT_SIZE
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(prec))
|
||||
offset += USINT_SIZE
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(scale))
|
||||
offset += USINT_SIZE
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) makeChkDesc_class_normal(offset int, desc *TypeDescriptor) (int, error) {
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(desc.m_size))
|
||||
offset += USINT_SIZE
|
||||
var err error
|
||||
|
||||
for i := 0; i < desc.m_size; i++ {
|
||||
offset, err = typeDescriptor.makeChkDesc(offset, &desc.m_fieldsObj[i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) makeChkDesc_class_clnt(offset int, desc *TypeDescriptor) (int, error) {
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(desc.m_cltnType))
|
||||
offset += USINT_SIZE
|
||||
|
||||
Dm_build_1346.Dm_build_1362(typeDescriptor.m_descBuf, offset, int32(desc.getMaxCnt()))
|
||||
offset += ULINT_SIZE
|
||||
|
||||
switch desc.m_cltnType {
|
||||
case CLTN_TYPE_IND_TABLE:
|
||||
return 0, ECGO_UNSUPPORTED_TYPE.throw()
|
||||
|
||||
case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY:
|
||||
|
||||
return typeDescriptor.makeChkDesc(offset, desc.m_arrObj)
|
||||
}
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) makeChkDesc_class(offset int, desc *TypeDescriptor) (int, error) {
|
||||
|
||||
Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, CLASS)
|
||||
offset += USINT_SIZE
|
||||
|
||||
isClnt := false
|
||||
if desc.m_objId == 4 {
|
||||
isClnt = true
|
||||
}
|
||||
|
||||
if isClnt {
|
||||
Dm_build_1346.Dm_build_1347(typeDescriptor.m_descBuf, offset, byte(1))
|
||||
} else {
|
||||
Dm_build_1346.Dm_build_1347(typeDescriptor.m_descBuf, offset, byte(0))
|
||||
}
|
||||
|
||||
offset += BYTE_SIZE
|
||||
|
||||
if isClnt {
|
||||
return typeDescriptor.makeChkDesc_class_clnt(offset, desc)
|
||||
} else {
|
||||
return typeDescriptor.makeChkDesc_class_normal(offset, desc)
|
||||
}
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) makeChkDesc(offset int, subDesc *TypeDescriptor) (int, error) {
|
||||
switch subDesc.getDType() {
|
||||
case ARRAY, SARRAY:
|
||||
return typeDescriptor.makeChkDesc_array(offset, subDesc)
|
||||
|
||||
case PLTYPE_RECORD:
|
||||
return typeDescriptor.makeChkDesc_record(offset, subDesc)
|
||||
|
||||
case CLASS:
|
||||
return typeDescriptor.makeChkDesc_class(offset, subDesc)
|
||||
|
||||
default:
|
||||
return typeDescriptor.makeChkDesc_buildin(offset, subDesc), nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (typeDescriptor *TypeDescriptor) getClassDescChkInfo() ([]byte, error) {
|
||||
if typeDescriptor.m_descBuf != nil {
|
||||
return typeDescriptor.m_descBuf, nil
|
||||
}
|
||||
|
||||
l, err := calcChkDescLen(typeDescriptor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typeDescriptor.m_descBuf = make([]byte, l)
|
||||
|
||||
typeDescriptor.makeChkDesc(0, typeDescriptor)
|
||||
return typeDescriptor.m_descBuf, nil
|
||||
}
|
||||
+249
@@ -0,0 +1,249 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run maketables.go
|
||||
|
||||
// Package charmap provides simple character encodings such as IBM Code Page 437
|
||||
// and Windows 1252.
|
||||
package charmap // import "golang.org/x/text/encoding/charmap"
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// These encodings vary only in the way clients should interpret them. Their
|
||||
// coded character set is identical and a single implementation can be shared.
|
||||
var (
|
||||
// ISO8859_6E is the ISO 8859-6E encoding.
|
||||
ISO8859_6E encoding.Encoding = &iso8859_6E
|
||||
|
||||
// ISO8859_6I is the ISO 8859-6I encoding.
|
||||
ISO8859_6I encoding.Encoding = &iso8859_6I
|
||||
|
||||
// ISO8859_8E is the ISO 8859-8E encoding.
|
||||
ISO8859_8E encoding.Encoding = &iso8859_8E
|
||||
|
||||
// ISO8859_8I is the ISO 8859-8I encoding.
|
||||
ISO8859_8I encoding.Encoding = &iso8859_8I
|
||||
|
||||
iso8859_6E = internal.Encoding{
|
||||
Encoding: ISO8859_6,
|
||||
Name: "ISO-8859-6E",
|
||||
MIB: identifier.ISO88596E,
|
||||
}
|
||||
|
||||
iso8859_6I = internal.Encoding{
|
||||
Encoding: ISO8859_6,
|
||||
Name: "ISO-8859-6I",
|
||||
MIB: identifier.ISO88596I,
|
||||
}
|
||||
|
||||
iso8859_8E = internal.Encoding{
|
||||
Encoding: ISO8859_8,
|
||||
Name: "ISO-8859-8E",
|
||||
MIB: identifier.ISO88598E,
|
||||
}
|
||||
|
||||
iso8859_8I = internal.Encoding{
|
||||
Encoding: ISO8859_8,
|
||||
Name: "ISO-8859-8I",
|
||||
MIB: identifier.ISO88598I,
|
||||
}
|
||||
)
|
||||
|
||||
// All is a list of all defined encodings in this package.
|
||||
var All []encoding.Encoding = listAll
|
||||
|
||||
// TODO: implement these encodings, in order of importance.
|
||||
// ASCII, ISO8859_1: Rather common. Close to Windows 1252.
|
||||
// ISO8859_9: Close to Windows 1254.
|
||||
|
||||
// utf8Enc holds a rune's UTF-8 encoding in data[:len].
|
||||
type utf8Enc struct {
|
||||
len uint8
|
||||
data [3]byte
|
||||
}
|
||||
|
||||
// Charmap is an 8-bit character set encoding.
|
||||
type Charmap struct {
|
||||
// name is the encoding's name.
|
||||
name string
|
||||
// mib is the encoding type of this encoder.
|
||||
mib identifier.MIB
|
||||
// asciiSuperset states whether the encoding is a superset of ASCII.
|
||||
asciiSuperset bool
|
||||
// low is the lower bound of the encoded byte for a non-ASCII rune. If
|
||||
// Charmap.asciiSuperset is true then this will be 0x80, otherwise 0x00.
|
||||
low uint8
|
||||
// replacement is the encoded replacement character.
|
||||
replacement byte
|
||||
// decode is the map from encoded byte to UTF-8.
|
||||
decode [256]utf8Enc
|
||||
// encoding is the map from runes to encoded bytes. Each entry is a
|
||||
// uint32: the high 8 bits are the encoded byte and the low 24 bits are
|
||||
// the rune. The table entries are sorted by ascending rune.
|
||||
encode [256]uint32
|
||||
}
|
||||
|
||||
// NewDecoder implements the encoding.Encoding interface.
|
||||
func (m *Charmap) NewDecoder() *encoding.Decoder {
|
||||
return &encoding.Decoder{Transformer: charmapDecoder{charmap: m}}
|
||||
}
|
||||
|
||||
// NewEncoder implements the encoding.Encoding interface.
|
||||
func (m *Charmap) NewEncoder() *encoding.Encoder {
|
||||
return &encoding.Encoder{Transformer: charmapEncoder{charmap: m}}
|
||||
}
|
||||
|
||||
// String returns the Charmap's name.
|
||||
func (m *Charmap) String() string {
|
||||
return m.name
|
||||
}
|
||||
|
||||
// ID implements an internal interface.
|
||||
func (m *Charmap) ID() (mib identifier.MIB, other string) {
|
||||
return m.mib, ""
|
||||
}
|
||||
|
||||
// charmapDecoder implements transform.Transformer by decoding to UTF-8.
|
||||
type charmapDecoder struct {
|
||||
transform.NopResetter
|
||||
charmap *Charmap
|
||||
}
|
||||
|
||||
func (m charmapDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
for i, c := range src {
|
||||
if m.charmap.asciiSuperset && c < utf8.RuneSelf {
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = c
|
||||
nDst++
|
||||
nSrc = i + 1
|
||||
continue
|
||||
}
|
||||
|
||||
decode := &m.charmap.decode[c]
|
||||
n := int(decode.len)
|
||||
if nDst+n > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
// It's 15% faster to avoid calling copy for these tiny slices.
|
||||
for j := 0; j < n; j++ {
|
||||
dst[nDst] = decode.data[j]
|
||||
nDst++
|
||||
}
|
||||
nSrc = i + 1
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
// DecodeByte returns the Charmap's rune decoding of the byte b.
|
||||
func (m *Charmap) DecodeByte(b byte) rune {
|
||||
switch x := &m.decode[b]; x.len {
|
||||
case 1:
|
||||
return rune(x.data[0])
|
||||
case 2:
|
||||
return rune(x.data[0]&0x1f)<<6 | rune(x.data[1]&0x3f)
|
||||
default:
|
||||
return rune(x.data[0]&0x0f)<<12 | rune(x.data[1]&0x3f)<<6 | rune(x.data[2]&0x3f)
|
||||
}
|
||||
}
|
||||
|
||||
// charmapEncoder implements transform.Transformer by encoding from UTF-8.
|
||||
type charmapEncoder struct {
|
||||
transform.NopResetter
|
||||
charmap *Charmap
|
||||
}
|
||||
|
||||
func (m charmapEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
loop:
|
||||
for nSrc < len(src) {
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
if m.charmap.asciiSuperset {
|
||||
nSrc++
|
||||
dst[nDst] = uint8(r)
|
||||
nDst++
|
||||
continue
|
||||
}
|
||||
size = 1
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
} else {
|
||||
err = internal.RepertoireError(m.charmap.replacement)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Binary search in [low, high) for that rune in the m.charmap.encode table.
|
||||
for low, high := int(m.charmap.low), 0x100; ; {
|
||||
if low >= high {
|
||||
err = internal.RepertoireError(m.charmap.replacement)
|
||||
break loop
|
||||
}
|
||||
mid := (low + high) / 2
|
||||
got := m.charmap.encode[mid]
|
||||
gotRune := rune(got & (1<<24 - 1))
|
||||
if gotRune < r {
|
||||
low = mid + 1
|
||||
} else if gotRune > r {
|
||||
high = mid
|
||||
} else {
|
||||
dst[nDst] = byte(got >> 24)
|
||||
nDst++
|
||||
break
|
||||
}
|
||||
}
|
||||
nSrc += size
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
// EncodeRune returns the Charmap's byte encoding of the rune r. ok is whether
|
||||
// r is in the Charmap's repertoire. If not, b is set to the Charmap's
|
||||
// replacement byte. This is often the ASCII substitute character '\x1a'.
|
||||
func (m *Charmap) EncodeRune(r rune) (b byte, ok bool) {
|
||||
if r < utf8.RuneSelf && m.asciiSuperset {
|
||||
return byte(r), true
|
||||
}
|
||||
for low, high := int(m.low), 0x100; ; {
|
||||
if low >= high {
|
||||
return m.replacement, false
|
||||
}
|
||||
mid := (low + high) / 2
|
||||
got := m.encode[mid]
|
||||
gotRune := rune(got & (1<<24 - 1))
|
||||
if gotRune < r {
|
||||
low = mid + 1
|
||||
} else if gotRune > r {
|
||||
high = mid
|
||||
} else {
|
||||
return byte(got >> 24), true
|
||||
}
|
||||
}
|
||||
}
|
||||
+7410
File diff suppressed because it is too large
Load Diff
+335
@@ -0,0 +1,335 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package encoding defines an interface for character encodings, such as Shift
|
||||
// JIS and Windows 1252, that can convert to and from UTF-8.
|
||||
//
|
||||
// Encoding implementations are provided in other packages, such as
|
||||
// golang.org/x/text/encoding/charmap and
|
||||
// golang.org/x/text/encoding/japanese.
|
||||
package encoding // import "golang.org/x/text/encoding"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// TODO:
|
||||
// - There seems to be some inconsistency in when decoders return errors
|
||||
// and when not. Also documentation seems to suggest they shouldn't return
|
||||
// errors at all (except for UTF-16).
|
||||
// - Encoders seem to rely on or at least benefit from the input being in NFC
|
||||
// normal form. Perhaps add an example how users could prepare their output.
|
||||
|
||||
// Encoding is a character set encoding that can be transformed to and from
|
||||
// UTF-8.
|
||||
type Encoding interface {
|
||||
// NewDecoder returns a Decoder.
|
||||
NewDecoder() *Decoder
|
||||
|
||||
// NewEncoder returns an Encoder.
|
||||
NewEncoder() *Encoder
|
||||
}
|
||||
|
||||
// A Decoder converts bytes to UTF-8. It implements transform.Transformer.
|
||||
//
|
||||
// Transforming source bytes that are not of that encoding will not result in an
|
||||
// error per se. Each byte that cannot be transcoded will be represented in the
|
||||
// output by the UTF-8 encoding of '\uFFFD', the replacement rune.
|
||||
type Decoder struct {
|
||||
transform.Transformer
|
||||
|
||||
// This forces external creators of Decoders to use names in struct
|
||||
// initializers, allowing for future extendibility without having to break
|
||||
// code.
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// Bytes converts the given encoded bytes to UTF-8. It returns the converted
|
||||
// bytes or nil, err if any error occurred.
|
||||
func (d *Decoder) Bytes(b []byte) ([]byte, error) {
|
||||
b, _, err := transform.Bytes(d, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// String converts the given encoded string to UTF-8. It returns the converted
|
||||
// string or "", err if any error occurred.
|
||||
func (d *Decoder) String(s string) (string, error) {
|
||||
s, _, err := transform.String(d, s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Reader wraps another Reader to decode its bytes.
|
||||
//
|
||||
// The Decoder may not be used for any other operation as long as the returned
|
||||
// Reader is in use.
|
||||
func (d *Decoder) Reader(r io.Reader) io.Reader {
|
||||
return transform.NewReader(r, d)
|
||||
}
|
||||
|
||||
// An Encoder converts bytes from UTF-8. It implements transform.Transformer.
|
||||
//
|
||||
// Each rune that cannot be transcoded will result in an error. In this case,
|
||||
// the transform will consume all source byte up to, not including the offending
|
||||
// rune. Transforming source bytes that are not valid UTF-8 will be replaced by
|
||||
// `\uFFFD`. To return early with an error instead, use transform.Chain to
|
||||
// preprocess the data with a UTF8Validator.
|
||||
type Encoder struct {
|
||||
transform.Transformer
|
||||
|
||||
// This forces external creators of Encoders to use names in struct
|
||||
// initializers, allowing for future extendibility without having to break
|
||||
// code.
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// Bytes converts bytes from UTF-8. It returns the converted bytes or nil, err if
|
||||
// any error occurred.
|
||||
func (e *Encoder) Bytes(b []byte) ([]byte, error) {
|
||||
b, _, err := transform.Bytes(e, b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// String converts a string from UTF-8. It returns the converted string or
|
||||
// "", err if any error occurred.
|
||||
func (e *Encoder) String(s string) (string, error) {
|
||||
s, _, err := transform.String(e, s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Writer wraps another Writer to encode its UTF-8 output.
|
||||
//
|
||||
// The Encoder may not be used for any other operation as long as the returned
|
||||
// Writer is in use.
|
||||
func (e *Encoder) Writer(w io.Writer) io.Writer {
|
||||
return transform.NewWriter(w, e)
|
||||
}
|
||||
|
||||
// ASCIISub is the ASCII substitute character, as recommended by
|
||||
// https://unicode.org/reports/tr36/#Text_Comparison
|
||||
const ASCIISub = '\x1a'
|
||||
|
||||
// Nop is the nop encoding. Its transformed bytes are the same as the source
|
||||
// bytes; it does not replace invalid UTF-8 sequences.
|
||||
var Nop Encoding = nop{}
|
||||
|
||||
type nop struct{}
|
||||
|
||||
func (nop) NewDecoder() *Decoder {
|
||||
return &Decoder{Transformer: transform.Nop}
|
||||
}
|
||||
func (nop) NewEncoder() *Encoder {
|
||||
return &Encoder{Transformer: transform.Nop}
|
||||
}
|
||||
|
||||
// Replacement is the replacement encoding. Decoding from the replacement
|
||||
// encoding yields a single '\uFFFD' replacement rune. Encoding from UTF-8 to
|
||||
// the replacement encoding yields the same as the source bytes except that
|
||||
// invalid UTF-8 is converted to '\uFFFD'.
|
||||
//
|
||||
// It is defined at http://encoding.spec.whatwg.org/#replacement
|
||||
var Replacement Encoding = replacement{}
|
||||
|
||||
type replacement struct{}
|
||||
|
||||
func (replacement) NewDecoder() *Decoder {
|
||||
return &Decoder{Transformer: replacementDecoder{}}
|
||||
}
|
||||
|
||||
func (replacement) NewEncoder() *Encoder {
|
||||
return &Encoder{Transformer: replacementEncoder{}}
|
||||
}
|
||||
|
||||
func (replacement) ID() (mib identifier.MIB, other string) {
|
||||
return identifier.Replacement, ""
|
||||
}
|
||||
|
||||
type replacementDecoder struct{ transform.NopResetter }
|
||||
|
||||
func (replacementDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
if len(dst) < 3 {
|
||||
return 0, 0, transform.ErrShortDst
|
||||
}
|
||||
if atEOF {
|
||||
const fffd = "\ufffd"
|
||||
dst[0] = fffd[0]
|
||||
dst[1] = fffd[1]
|
||||
dst[2] = fffd[2]
|
||||
nDst = 3
|
||||
}
|
||||
return nDst, len(src), nil
|
||||
}
|
||||
|
||||
type replacementEncoder struct{ transform.NopResetter }
|
||||
|
||||
func (replacementEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break
|
||||
}
|
||||
r = '\ufffd'
|
||||
}
|
||||
}
|
||||
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
// HTMLEscapeUnsupported wraps encoders to replace source runes outside the
|
||||
// repertoire of the destination encoding with HTML escape sequences.
|
||||
//
|
||||
// This wrapper exists to comply to URL and HTML forms requiring a
|
||||
// non-terminating legacy encoder. The produced sequences may lead to data
|
||||
// loss as they are indistinguishable from legitimate input. To avoid this
|
||||
// issue, use UTF-8 encodings whenever possible.
|
||||
func HTMLEscapeUnsupported(e *Encoder) *Encoder {
|
||||
return &Encoder{Transformer: &errorHandler{e, errorToHTML}}
|
||||
}
|
||||
|
||||
// ReplaceUnsupported wraps encoders to replace source runes outside the
|
||||
// repertoire of the destination encoding with an encoding-specific
|
||||
// replacement.
|
||||
//
|
||||
// This wrapper is only provided for backwards compatibility and legacy
|
||||
// handling. Its use is strongly discouraged. Use UTF-8 whenever possible.
|
||||
func ReplaceUnsupported(e *Encoder) *Encoder {
|
||||
return &Encoder{Transformer: &errorHandler{e, errorToReplacement}}
|
||||
}
|
||||
|
||||
type errorHandler struct {
|
||||
*Encoder
|
||||
handler func(dst []byte, r rune, err repertoireError) (n int, ok bool)
|
||||
}
|
||||
|
||||
// TODO: consider making this error public in some form.
|
||||
type repertoireError interface {
|
||||
Replacement() byte
|
||||
}
|
||||
|
||||
func (h errorHandler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
nDst, nSrc, err = h.Transformer.Transform(dst, src, atEOF)
|
||||
for err != nil {
|
||||
rerr, ok := err.(repertoireError)
|
||||
if !ok {
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
r, sz := utf8.DecodeRune(src[nSrc:])
|
||||
n, ok := h.handler(dst[nDst:], r, rerr)
|
||||
if !ok {
|
||||
return nDst, nSrc, transform.ErrShortDst
|
||||
}
|
||||
err = nil
|
||||
nDst += n
|
||||
if nSrc += sz; nSrc < len(src) {
|
||||
var dn, sn int
|
||||
dn, sn, err = h.Transformer.Transform(dst[nDst:], src[nSrc:], atEOF)
|
||||
nDst += dn
|
||||
nSrc += sn
|
||||
}
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
func errorToHTML(dst []byte, r rune, err repertoireError) (n int, ok bool) {
|
||||
buf := [8]byte{}
|
||||
b := strconv.AppendUint(buf[:0], uint64(r), 10)
|
||||
if n = len(b) + len("&#;"); n >= len(dst) {
|
||||
return 0, false
|
||||
}
|
||||
dst[0] = '&'
|
||||
dst[1] = '#'
|
||||
dst[copy(dst[2:], b)+2] = ';'
|
||||
return n, true
|
||||
}
|
||||
|
||||
func errorToReplacement(dst []byte, r rune, err repertoireError) (n int, ok bool) {
|
||||
if len(dst) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
dst[0] = err.Replacement()
|
||||
return 1, true
|
||||
}
|
||||
|
||||
// ErrInvalidUTF8 means that a transformer encountered invalid UTF-8.
|
||||
var ErrInvalidUTF8 = errors.New("encoding: invalid UTF-8")
|
||||
|
||||
// UTF8Validator is a transformer that returns ErrInvalidUTF8 on the first
|
||||
// input byte that is not valid UTF-8.
|
||||
var UTF8Validator transform.Transformer = utf8Validator{}
|
||||
|
||||
type utf8Validator struct{ transform.NopResetter }
|
||||
|
||||
func (utf8Validator) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
n := len(src)
|
||||
if n > len(dst) {
|
||||
n = len(dst)
|
||||
}
|
||||
for i := 0; i < n; {
|
||||
if c := src[i]; c < utf8.RuneSelf {
|
||||
dst[i] = c
|
||||
i++
|
||||
continue
|
||||
}
|
||||
_, size := utf8.DecodeRune(src[i:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
err = ErrInvalidUTF8
|
||||
if !atEOF && !utf8.FullRune(src[i:]) {
|
||||
err = transform.ErrShortSrc
|
||||
}
|
||||
return i, i, err
|
||||
}
|
||||
if i+size > len(dst) {
|
||||
return i, i, transform.ErrShortDst
|
||||
}
|
||||
for ; size > 0; size-- {
|
||||
dst[i] = src[i]
|
||||
i++
|
||||
}
|
||||
}
|
||||
if len(src) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
}
|
||||
return n, n, err
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ianaindex
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
type asciiDecoder struct {
|
||||
transform.NopResetter
|
||||
}
|
||||
|
||||
func (d asciiDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
for _, c := range src {
|
||||
if c > unicode.MaxASCII {
|
||||
r := unicode.ReplacementChar
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
nSrc++
|
||||
continue
|
||||
}
|
||||
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = c
|
||||
nDst++
|
||||
nSrc++
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type asciiEncoder struct {
|
||||
transform.NopResetter
|
||||
}
|
||||
|
||||
func (d asciiEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
for _, c := range src {
|
||||
if c > unicode.MaxASCII {
|
||||
err = internal.RepertoireError(encoding.ASCIISub)
|
||||
break
|
||||
}
|
||||
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = c
|
||||
nDst++
|
||||
nSrc++
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
var asciiEnc = &internal.Encoding{
|
||||
Encoding: &internal.SimpleEncoding{
|
||||
asciiDecoder{},
|
||||
asciiEncoder{},
|
||||
},
|
||||
Name: "US-ASCII",
|
||||
MIB: identifier.ASCII,
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
// Package ianaindex maps names to Encodings as specified by the IANA registry.
|
||||
// This includes both the MIME and IANA names.
|
||||
//
|
||||
// See http://www.iana.org/assignments/character-sets/character-sets.xhtml for
|
||||
// more details.
|
||||
package ianaindex
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/encoding/japanese"
|
||||
"golang.org/x/text/encoding/korean"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/encoding/traditionalchinese"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
)
|
||||
|
||||
// TODO: remove the "Status... incomplete" in the package doc comment.
|
||||
// TODO: allow users to specify their own aliases?
|
||||
// TODO: allow users to specify their own indexes?
|
||||
// TODO: allow canonicalizing names
|
||||
|
||||
// NOTE: only use these top-level variables if we can get the linker to drop
|
||||
// the indexes when they are not used. Make them a function or perhaps only
|
||||
// support MIME otherwise.
|
||||
|
||||
var (
|
||||
// MIME is an index to map MIME names.
|
||||
MIME *Index = mime
|
||||
|
||||
// IANA is an index that supports all names and aliases using IANA names as
|
||||
// the canonical identifier.
|
||||
IANA *Index = iana
|
||||
|
||||
// MIB is an index that associates the MIB display name with an Encoding.
|
||||
MIB *Index = mib
|
||||
|
||||
mime = &Index{mimeName, ianaToMIB, ianaAliases, encodings[:]}
|
||||
iana = &Index{ianaName, ianaToMIB, ianaAliases, encodings[:]}
|
||||
mib = &Index{mibName, ianaToMIB, ianaAliases, encodings[:]}
|
||||
)
|
||||
|
||||
// Index maps names registered by IANA to Encodings.
|
||||
// Currently different Indexes only differ in the names they return for
|
||||
// encodings. In the future they may also differ in supported aliases.
|
||||
type Index struct {
|
||||
names func(i int) string
|
||||
toMIB []identifier.MIB // Sorted slice of supported MIBs
|
||||
alias map[string]int
|
||||
enc []encoding.Encoding
|
||||
}
|
||||
|
||||
var (
|
||||
errInvalidName = errors.New("ianaindex: invalid encoding name")
|
||||
errUnknown = errors.New("ianaindex: unknown Encoding")
|
||||
errUnsupported = errors.New("ianaindex: unsupported Encoding")
|
||||
)
|
||||
|
||||
// Encoding returns an Encoding for IANA-registered names. Matching is
|
||||
// case-insensitive.
|
||||
//
|
||||
// If the provided name doesn't match a IANA-registered charset, an error is
|
||||
// returned. If the name matches a IANA-registered charset but isn't supported,
|
||||
// a nil encoding and a nil error are returned.
|
||||
func (x *Index) Encoding(name string) (encoding.Encoding, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
// First try without lowercasing (possibly creating an allocation).
|
||||
i, ok := x.alias[name]
|
||||
if !ok {
|
||||
i, ok = x.alias[strings.ToLower(name)]
|
||||
if !ok {
|
||||
return nil, errInvalidName
|
||||
}
|
||||
}
|
||||
return x.enc[i], nil
|
||||
}
|
||||
|
||||
// Name reports the canonical name of the given Encoding. It will return an
|
||||
// error if the e is not associated with a known encoding scheme.
|
||||
func (x *Index) Name(e encoding.Encoding) (string, error) {
|
||||
id, ok := e.(identifier.Interface)
|
||||
if !ok {
|
||||
return "", errUnknown
|
||||
}
|
||||
mib, _ := id.ID()
|
||||
if mib == 0 {
|
||||
return "", errUnknown
|
||||
}
|
||||
v := findMIB(x.toMIB, mib)
|
||||
if v == -1 {
|
||||
return "", errUnsupported
|
||||
}
|
||||
return x.names(v), nil
|
||||
}
|
||||
|
||||
// TODO: the coverage of this index is rather spotty. Allowing users to set
|
||||
// encodings would allow:
|
||||
// - users to increase coverage
|
||||
// - allow a partially loaded set of encodings in case the user doesn't need to
|
||||
// them all.
|
||||
// - write an OS-specific wrapper for supported encodings and set them.
|
||||
// The exact definition of Set depends a bit on if and how we want to let users
|
||||
// write their own Encoding implementations. Also, it is not possible yet to
|
||||
// only partially load the encodings without doing some refactoring. Until this
|
||||
// is solved, we might as well not support Set.
|
||||
// // Set sets the e to be used for the encoding scheme identified by name. Only
|
||||
// // canonical names may be used. An empty name assigns e to its internally
|
||||
// // associated encoding scheme.
|
||||
// func (x *Index) Set(name string, e encoding.Encoding) error {
|
||||
// panic("TODO: implement")
|
||||
// }
|
||||
|
||||
func findMIB(x []identifier.MIB, mib identifier.MIB) int {
|
||||
i := sort.Search(len(x), func(i int) bool { return x[i] >= mib })
|
||||
if i < len(x) && x[i] == mib {
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
const maxMIMENameLen = '0' - 1 // officially 40, but we leave some buffer.
|
||||
|
||||
func mimeName(x int) string {
|
||||
n := ianaNames[x]
|
||||
// See gen.go for a description of the encoding.
|
||||
if n[0] <= maxMIMENameLen {
|
||||
return n[1:n[0]]
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func ianaName(x int) string {
|
||||
n := ianaNames[x]
|
||||
// See gen.go for a description of the encoding.
|
||||
if n[0] <= maxMIMENameLen {
|
||||
return n[n[0]:]
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func mibName(x int) string {
|
||||
return mibNames[x]
|
||||
}
|
||||
|
||||
var encodings = [numIANA]encoding.Encoding{
|
||||
enc3: asciiEnc,
|
||||
enc106: unicode.UTF8,
|
||||
enc1015: unicode.UTF16(unicode.BigEndian, unicode.UseBOM),
|
||||
enc1013: unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM),
|
||||
enc1014: unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM),
|
||||
enc2028: charmap.CodePage037,
|
||||
enc2011: charmap.CodePage437,
|
||||
enc2009: charmap.CodePage850,
|
||||
enc2010: charmap.CodePage852,
|
||||
enc2046: charmap.CodePage855,
|
||||
enc2089: charmap.CodePage858,
|
||||
enc2048: charmap.CodePage860,
|
||||
enc2013: charmap.CodePage862,
|
||||
enc2050: charmap.CodePage863,
|
||||
enc2052: charmap.CodePage865,
|
||||
enc2086: charmap.CodePage866,
|
||||
enc2102: charmap.CodePage1047,
|
||||
enc2091: charmap.CodePage1140,
|
||||
enc4: charmap.ISO8859_1,
|
||||
enc5: charmap.ISO8859_2,
|
||||
enc6: charmap.ISO8859_3,
|
||||
enc7: charmap.ISO8859_4,
|
||||
enc8: charmap.ISO8859_5,
|
||||
enc9: charmap.ISO8859_6,
|
||||
enc81: charmap.ISO8859_6E,
|
||||
enc82: charmap.ISO8859_6I,
|
||||
enc10: charmap.ISO8859_7,
|
||||
enc11: charmap.ISO8859_8,
|
||||
enc84: charmap.ISO8859_8E,
|
||||
enc85: charmap.ISO8859_8I,
|
||||
enc12: charmap.ISO8859_9,
|
||||
enc13: charmap.ISO8859_10,
|
||||
enc109: charmap.ISO8859_13,
|
||||
enc110: charmap.ISO8859_14,
|
||||
enc111: charmap.ISO8859_15,
|
||||
enc112: charmap.ISO8859_16,
|
||||
enc2084: charmap.KOI8R,
|
||||
enc2088: charmap.KOI8U,
|
||||
enc2027: charmap.Macintosh,
|
||||
enc2109: charmap.Windows874,
|
||||
enc2250: charmap.Windows1250,
|
||||
enc2251: charmap.Windows1251,
|
||||
enc2252: charmap.Windows1252,
|
||||
enc2253: charmap.Windows1253,
|
||||
enc2254: charmap.Windows1254,
|
||||
enc2255: charmap.Windows1255,
|
||||
enc2256: charmap.Windows1256,
|
||||
enc2257: charmap.Windows1257,
|
||||
enc2258: charmap.Windows1258,
|
||||
enc18: japanese.EUCJP,
|
||||
enc39: japanese.ISO2022JP,
|
||||
enc17: japanese.ShiftJIS,
|
||||
enc38: korean.EUCKR,
|
||||
enc114: simplifiedchinese.GB18030,
|
||||
enc113: simplifiedchinese.GBK,
|
||||
enc2085: simplifiedchinese.HZGB2312,
|
||||
enc2026: traditionalchinese.Big5,
|
||||
}
|
||||
+2348
File diff suppressed because it is too large
Load Diff
+81
@@ -0,0 +1,81 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
// Package identifier defines the contract between implementations of Encoding
|
||||
// and Index by defining identifiers that uniquely identify standardized coded
|
||||
// character sets (CCS) and character encoding schemes (CES), which we will
|
||||
// together refer to as encodings, for which Encoding implementations provide
|
||||
// converters to and from UTF-8. This package is typically only of concern to
|
||||
// implementers of Indexes and Encodings.
|
||||
//
|
||||
// One part of the identifier is the MIB code, which is defined by IANA and
|
||||
// uniquely identifies a CCS or CES. Each code is associated with data that
|
||||
// references authorities, official documentation as well as aliases and MIME
|
||||
// names.
|
||||
//
|
||||
// Not all CESs are covered by the IANA registry. The "other" string that is
|
||||
// returned by ID can be used to identify other character sets or versions of
|
||||
// existing ones.
|
||||
//
|
||||
// It is recommended that each package that provides a set of Encodings provide
|
||||
// the All and Common variables to reference all supported encodings and
|
||||
// commonly used subset. This allows Index implementations to include all
|
||||
// available encodings without explicitly referencing or knowing about them.
|
||||
package identifier
|
||||
|
||||
// Note: this package is internal, but could be made public if there is a need
|
||||
// for writing third-party Indexes and Encodings.
|
||||
|
||||
// References:
|
||||
// - http://source.icu-project.org/repos/icu/icu/trunk/source/data/mappings/convrtrs.txt
|
||||
// - http://www.iana.org/assignments/character-sets/character-sets.xhtml
|
||||
// - http://www.iana.org/assignments/ianacharset-mib/ianacharset-mib
|
||||
// - http://www.ietf.org/rfc/rfc2978.txt
|
||||
// - https://www.unicode.org/reports/tr22/
|
||||
// - http://www.w3.org/TR/encoding/
|
||||
// - https://encoding.spec.whatwg.org/
|
||||
// - https://encoding.spec.whatwg.org/encodings.json
|
||||
// - https://tools.ietf.org/html/rfc6657#section-5
|
||||
|
||||
// Interface can be implemented by Encodings to define the CCS or CES for which
|
||||
// it implements conversions.
|
||||
type Interface interface {
|
||||
// ID returns an encoding identifier. Exactly one of the mib and other
|
||||
// values should be non-zero.
|
||||
//
|
||||
// In the usual case it is only necessary to indicate the MIB code. The
|
||||
// other string can be used to specify encodings for which there is no MIB,
|
||||
// such as "x-mac-dingbat".
|
||||
//
|
||||
// The other string may only contain the characters a-z, A-Z, 0-9, - and _.
|
||||
ID() (mib MIB, other string)
|
||||
|
||||
// NOTE: the restrictions on the encoding are to allow extending the syntax
|
||||
// with additional information such as versions, vendors and other variants.
|
||||
}
|
||||
|
||||
// A MIB identifies an encoding. It is derived from the IANA MIB codes and adds
|
||||
// some identifiers for some encodings that are not covered by the IANA
|
||||
// standard.
|
||||
//
|
||||
// See http://www.iana.org/assignments/ianacharset-mib.
|
||||
type MIB uint16
|
||||
|
||||
// These additional MIB types are not defined in IANA. They are added because
|
||||
// they are common and defined within the text repo.
|
||||
const (
|
||||
// Unofficial marks the start of encodings not registered by IANA.
|
||||
Unofficial MIB = 10000 + iota
|
||||
|
||||
// Replacement is the WhatWG replacement encoding.
|
||||
Replacement
|
||||
|
||||
// XUserDefined is the code for x-user-defined.
|
||||
XUserDefined
|
||||
|
||||
// MacintoshCyrillic is the code for x-mac-cyrillic.
|
||||
MacintoshCyrillic
|
||||
)
|
||||
+1619
File diff suppressed because it is too large
Load Diff
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package internal contains code that is shared among encoding implementations.
|
||||
package internal
|
||||
|
||||
import (
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// Encoding is an implementation of the Encoding interface that adds the String
|
||||
// and ID methods to an existing encoding.
|
||||
type Encoding struct {
|
||||
encoding.Encoding
|
||||
Name string
|
||||
MIB identifier.MIB
|
||||
}
|
||||
|
||||
// _ verifies that Encoding implements identifier.Interface.
|
||||
var _ identifier.Interface = (*Encoding)(nil)
|
||||
|
||||
func (e *Encoding) String() string {
|
||||
return e.Name
|
||||
}
|
||||
|
||||
func (e *Encoding) ID() (mib identifier.MIB, other string) {
|
||||
return e.MIB, ""
|
||||
}
|
||||
|
||||
// SimpleEncoding is an Encoding that combines two Transformers.
|
||||
type SimpleEncoding struct {
|
||||
Decoder transform.Transformer
|
||||
Encoder transform.Transformer
|
||||
}
|
||||
|
||||
func (e *SimpleEncoding) NewDecoder() *encoding.Decoder {
|
||||
return &encoding.Decoder{Transformer: e.Decoder}
|
||||
}
|
||||
|
||||
func (e *SimpleEncoding) NewEncoder() *encoding.Encoder {
|
||||
return &encoding.Encoder{Transformer: e.Encoder}
|
||||
}
|
||||
|
||||
// FuncEncoding is an Encoding that combines two functions returning a new
|
||||
// Transformer.
|
||||
type FuncEncoding struct {
|
||||
Decoder func() transform.Transformer
|
||||
Encoder func() transform.Transformer
|
||||
}
|
||||
|
||||
func (e FuncEncoding) NewDecoder() *encoding.Decoder {
|
||||
return &encoding.Decoder{Transformer: e.Decoder()}
|
||||
}
|
||||
|
||||
func (e FuncEncoding) NewEncoder() *encoding.Encoder {
|
||||
return &encoding.Encoder{Transformer: e.Encoder()}
|
||||
}
|
||||
|
||||
// A RepertoireError indicates a rune is not in the repertoire of a destination
|
||||
// encoding. It is associated with an encoding-specific suggested replacement
|
||||
// byte.
|
||||
type RepertoireError byte
|
||||
|
||||
// Error implements the error interrface.
|
||||
func (r RepertoireError) Error() string {
|
||||
return "encoding: rune not supported by encoding."
|
||||
}
|
||||
|
||||
// Replacement returns the replacement string associated with this error.
|
||||
func (r RepertoireError) Replacement() byte { return byte(r) }
|
||||
|
||||
var ErrASCIIReplacement = RepertoireError(encoding.ASCIISub)
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package japanese
|
||||
|
||||
import (
|
||||
"golang.org/x/text/encoding"
|
||||
)
|
||||
|
||||
// All is a list of all defined encodings in this package.
|
||||
var All = []encoding.Encoding{EUCJP, ISO2022JP, ShiftJIS}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package japanese
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// EUCJP is the EUC-JP encoding.
|
||||
var EUCJP encoding.Encoding = &eucJP
|
||||
|
||||
var eucJP = internal.Encoding{
|
||||
&internal.SimpleEncoding{eucJPDecoder{}, eucJPEncoder{}},
|
||||
"EUC-JP",
|
||||
identifier.EUCPkdFmtJapanese,
|
||||
}
|
||||
|
||||
type eucJPDecoder struct{ transform.NopResetter }
|
||||
|
||||
// See https://encoding.spec.whatwg.org/#euc-jp-decoder.
|
||||
func (eucJPDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
loop:
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
switch c0 := src[nSrc]; {
|
||||
case c0 < utf8.RuneSelf:
|
||||
r, size = rune(c0), 1
|
||||
|
||||
case c0 == 0x8e:
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
break
|
||||
}
|
||||
c1 := src[nSrc+1]
|
||||
switch {
|
||||
case c1 < 0xa1:
|
||||
r, size = utf8.RuneError, 1
|
||||
case c1 > 0xdf:
|
||||
r, size = utf8.RuneError, 2
|
||||
if c1 == 0xff {
|
||||
size = 1
|
||||
}
|
||||
default:
|
||||
r, size = rune(c1)+(0xff61-0xa1), 2
|
||||
}
|
||||
case c0 == 0x8f:
|
||||
if nSrc+2 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
if p := nSrc + 1; p < len(src) && 0xa1 <= src[p] && src[p] < 0xfe {
|
||||
size = 2
|
||||
}
|
||||
break
|
||||
}
|
||||
c1 := src[nSrc+1]
|
||||
if c1 < 0xa1 || 0xfe < c1 {
|
||||
r, size = utf8.RuneError, 1
|
||||
break
|
||||
}
|
||||
c2 := src[nSrc+2]
|
||||
if c2 < 0xa1 || 0xfe < c2 {
|
||||
r, size = utf8.RuneError, 2
|
||||
break
|
||||
}
|
||||
r, size = utf8.RuneError, 3
|
||||
if i := int(c1-0xa1)*94 + int(c2-0xa1); i < len(jis0212Decode) {
|
||||
r = rune(jis0212Decode[i])
|
||||
if r == 0 {
|
||||
r = utf8.RuneError
|
||||
}
|
||||
}
|
||||
|
||||
case 0xa1 <= c0 && c0 <= 0xfe:
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
break
|
||||
}
|
||||
c1 := src[nSrc+1]
|
||||
if c1 < 0xa1 || 0xfe < c1 {
|
||||
r, size = utf8.RuneError, 1
|
||||
break
|
||||
}
|
||||
r, size = utf8.RuneError, 2
|
||||
if i := int(c0-0xa1)*94 + int(c1-0xa1); i < len(jis0208Decode) {
|
||||
r = rune(jis0208Decode[i])
|
||||
if r == 0 {
|
||||
r = utf8.RuneError
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
r, size = utf8.RuneError, 1
|
||||
}
|
||||
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type eucJPEncoder struct{ transform.NopResetter }
|
||||
|
||||
func (eucJPEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// func init checks that the switch covers all tables.
|
||||
switch {
|
||||
case encode0Low <= r && r < encode0High:
|
||||
if r = rune(encode0[r-encode0Low]); r != 0 {
|
||||
goto write2or3
|
||||
}
|
||||
case encode1Low <= r && r < encode1High:
|
||||
if r = rune(encode1[r-encode1Low]); r != 0 {
|
||||
goto write2or3
|
||||
}
|
||||
case encode2Low <= r && r < encode2High:
|
||||
if r = rune(encode2[r-encode2Low]); r != 0 {
|
||||
goto write2or3
|
||||
}
|
||||
case encode3Low <= r && r < encode3High:
|
||||
if r = rune(encode3[r-encode3Low]); r != 0 {
|
||||
goto write2or3
|
||||
}
|
||||
case encode4Low <= r && r < encode4High:
|
||||
if r = rune(encode4[r-encode4Low]); r != 0 {
|
||||
goto write2or3
|
||||
}
|
||||
case encode5Low <= r && r < encode5High:
|
||||
if 0xff61 <= r && r < 0xffa0 {
|
||||
goto write2
|
||||
}
|
||||
if r = rune(encode5[r-encode5Low]); r != 0 {
|
||||
goto write2or3
|
||||
}
|
||||
}
|
||||
err = internal.ErrASCIIReplacement
|
||||
break
|
||||
}
|
||||
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r)
|
||||
nDst++
|
||||
continue
|
||||
|
||||
write2or3:
|
||||
if r>>tableShift == jis0208 {
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
} else {
|
||||
if nDst+3 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = 0x8f
|
||||
nDst++
|
||||
}
|
||||
dst[nDst+0] = 0xa1 + uint8(r>>codeShift)&codeMask
|
||||
dst[nDst+1] = 0xa1 + uint8(r)&codeMask
|
||||
nDst += 2
|
||||
continue
|
||||
|
||||
write2:
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = 0x8e
|
||||
dst[nDst+1] = uint8(r - (0xff61 - 0xa1))
|
||||
nDst += 2
|
||||
continue
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Check that the hard-coded encode switch covers all tables.
|
||||
if numEncodeTables != 6 {
|
||||
panic("bad numEncodeTables")
|
||||
}
|
||||
}
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package japanese
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// ISO2022JP is the ISO-2022-JP encoding.
|
||||
var ISO2022JP encoding.Encoding = &iso2022JP
|
||||
|
||||
var iso2022JP = internal.Encoding{
|
||||
internal.FuncEncoding{iso2022JPNewDecoder, iso2022JPNewEncoder},
|
||||
"ISO-2022-JP",
|
||||
identifier.ISO2022JP,
|
||||
}
|
||||
|
||||
func iso2022JPNewDecoder() transform.Transformer {
|
||||
return new(iso2022JPDecoder)
|
||||
}
|
||||
|
||||
func iso2022JPNewEncoder() transform.Transformer {
|
||||
return new(iso2022JPEncoder)
|
||||
}
|
||||
|
||||
const (
|
||||
asciiState = iota
|
||||
katakanaState
|
||||
jis0208State
|
||||
jis0212State
|
||||
)
|
||||
|
||||
const asciiEsc = 0x1b
|
||||
|
||||
type iso2022JPDecoder int
|
||||
|
||||
func (d *iso2022JPDecoder) Reset() {
|
||||
*d = asciiState
|
||||
}
|
||||
|
||||
func (d *iso2022JPDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
c0 := src[nSrc]
|
||||
if c0 >= utf8.RuneSelf {
|
||||
r, size = '\ufffd', 1
|
||||
goto write
|
||||
}
|
||||
|
||||
if c0 == asciiEsc {
|
||||
if nSrc+2 >= len(src) {
|
||||
if !atEOF {
|
||||
return nDst, nSrc, transform.ErrShortSrc
|
||||
}
|
||||
// TODO: is it correct to only skip 1??
|
||||
r, size = '\ufffd', 1
|
||||
goto write
|
||||
}
|
||||
size = 3
|
||||
c1 := src[nSrc+1]
|
||||
c2 := src[nSrc+2]
|
||||
switch {
|
||||
case c1 == '$' && (c2 == '@' || c2 == 'B'): // 0x24 {0x40, 0x42}
|
||||
*d = jis0208State
|
||||
continue
|
||||
case c1 == '$' && c2 == '(': // 0x24 0x28
|
||||
if nSrc+3 >= len(src) {
|
||||
if !atEOF {
|
||||
return nDst, nSrc, transform.ErrShortSrc
|
||||
}
|
||||
r, size = '\ufffd', 1
|
||||
goto write
|
||||
}
|
||||
size = 4
|
||||
if src[nSrc+3] == 'D' {
|
||||
*d = jis0212State
|
||||
continue
|
||||
}
|
||||
case c1 == '(' && (c2 == 'B' || c2 == 'J'): // 0x28 {0x42, 0x4A}
|
||||
*d = asciiState
|
||||
continue
|
||||
case c1 == '(' && c2 == 'I': // 0x28 0x49
|
||||
*d = katakanaState
|
||||
continue
|
||||
}
|
||||
r, size = '\ufffd', 1
|
||||
goto write
|
||||
}
|
||||
|
||||
switch *d {
|
||||
case asciiState:
|
||||
r, size = rune(c0), 1
|
||||
|
||||
case katakanaState:
|
||||
if c0 < 0x21 || 0x60 <= c0 {
|
||||
r, size = '\ufffd', 1
|
||||
goto write
|
||||
}
|
||||
r, size = rune(c0)+(0xff61-0x21), 1
|
||||
|
||||
default:
|
||||
if c0 == 0x0a {
|
||||
*d = asciiState
|
||||
r, size = rune(c0), 1
|
||||
goto write
|
||||
}
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
return nDst, nSrc, transform.ErrShortSrc
|
||||
}
|
||||
r, size = '\ufffd', 1
|
||||
goto write
|
||||
}
|
||||
size = 2
|
||||
c1 := src[nSrc+1]
|
||||
i := int(c0-0x21)*94 + int(c1-0x21)
|
||||
if *d == jis0208State && i < len(jis0208Decode) {
|
||||
r = rune(jis0208Decode[i])
|
||||
} else if *d == jis0212State && i < len(jis0212Decode) {
|
||||
r = rune(jis0212Decode[i])
|
||||
} else {
|
||||
r = '\ufffd'
|
||||
goto write
|
||||
}
|
||||
if r == 0 {
|
||||
r = '\ufffd'
|
||||
}
|
||||
}
|
||||
|
||||
write:
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
return nDst, nSrc, transform.ErrShortDst
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type iso2022JPEncoder int
|
||||
|
||||
func (e *iso2022JPEncoder) Reset() {
|
||||
*e = asciiState
|
||||
}
|
||||
|
||||
func (e *iso2022JPEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// func init checks that the switch covers all tables.
|
||||
//
|
||||
// http://encoding.spec.whatwg.org/#iso-2022-jp says that "the index jis0212
|
||||
// is not used by the iso-2022-jp encoder due to lack of widespread support".
|
||||
//
|
||||
// TODO: do we have to special-case U+00A5 and U+203E, as per
|
||||
// http://encoding.spec.whatwg.org/#iso-2022-jp
|
||||
// Doing so would mean that "\u00a5" would not be preserved
|
||||
// after an encode-decode round trip.
|
||||
switch {
|
||||
case encode0Low <= r && r < encode0High:
|
||||
if r = rune(encode0[r-encode0Low]); r>>tableShift == jis0208 {
|
||||
goto writeJIS
|
||||
}
|
||||
case encode1Low <= r && r < encode1High:
|
||||
if r = rune(encode1[r-encode1Low]); r>>tableShift == jis0208 {
|
||||
goto writeJIS
|
||||
}
|
||||
case encode2Low <= r && r < encode2High:
|
||||
if r = rune(encode2[r-encode2Low]); r>>tableShift == jis0208 {
|
||||
goto writeJIS
|
||||
}
|
||||
case encode3Low <= r && r < encode3High:
|
||||
if r = rune(encode3[r-encode3Low]); r>>tableShift == jis0208 {
|
||||
goto writeJIS
|
||||
}
|
||||
case encode4Low <= r && r < encode4High:
|
||||
if r = rune(encode4[r-encode4Low]); r>>tableShift == jis0208 {
|
||||
goto writeJIS
|
||||
}
|
||||
case encode5Low <= r && r < encode5High:
|
||||
if 0xff61 <= r && r < 0xffa0 {
|
||||
goto writeKatakana
|
||||
}
|
||||
if r = rune(encode5[r-encode5Low]); r>>tableShift == jis0208 {
|
||||
goto writeJIS
|
||||
}
|
||||
}
|
||||
|
||||
// Switch back to ASCII state in case of error so that an ASCII
|
||||
// replacement character can be written in the correct state.
|
||||
if *e != asciiState {
|
||||
if nDst+3 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
*e = asciiState
|
||||
dst[nDst+0] = asciiEsc
|
||||
dst[nDst+1] = '('
|
||||
dst[nDst+2] = 'B'
|
||||
nDst += 3
|
||||
}
|
||||
err = internal.ErrASCIIReplacement
|
||||
break
|
||||
}
|
||||
|
||||
if *e != asciiState {
|
||||
if nDst+4 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
*e = asciiState
|
||||
dst[nDst+0] = asciiEsc
|
||||
dst[nDst+1] = '('
|
||||
dst[nDst+2] = 'B'
|
||||
nDst += 3
|
||||
} else if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r)
|
||||
nDst++
|
||||
continue
|
||||
|
||||
writeJIS:
|
||||
if *e != jis0208State {
|
||||
if nDst+5 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
*e = jis0208State
|
||||
dst[nDst+0] = asciiEsc
|
||||
dst[nDst+1] = '$'
|
||||
dst[nDst+2] = 'B'
|
||||
nDst += 3
|
||||
} else if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = 0x21 + uint8(r>>codeShift)&codeMask
|
||||
dst[nDst+1] = 0x21 + uint8(r)&codeMask
|
||||
nDst += 2
|
||||
continue
|
||||
|
||||
writeKatakana:
|
||||
if *e != katakanaState {
|
||||
if nDst+4 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
*e = katakanaState
|
||||
dst[nDst+0] = asciiEsc
|
||||
dst[nDst+1] = '('
|
||||
dst[nDst+2] = 'I'
|
||||
nDst += 3
|
||||
} else if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r - (0xff61 - 0x21))
|
||||
nDst++
|
||||
continue
|
||||
}
|
||||
if atEOF && err == nil && *e != asciiState {
|
||||
if nDst+3 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
} else {
|
||||
*e = asciiState
|
||||
dst[nDst+0] = asciiEsc
|
||||
dst[nDst+1] = '('
|
||||
dst[nDst+2] = 'B'
|
||||
nDst += 3
|
||||
}
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package japanese
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// ShiftJIS is the Shift JIS encoding, also known as Code Page 932 and
|
||||
// Windows-31J.
|
||||
var ShiftJIS encoding.Encoding = &shiftJIS
|
||||
|
||||
var shiftJIS = internal.Encoding{
|
||||
&internal.SimpleEncoding{shiftJISDecoder{}, shiftJISEncoder{}},
|
||||
"Shift JIS",
|
||||
identifier.ShiftJIS,
|
||||
}
|
||||
|
||||
type shiftJISDecoder struct{ transform.NopResetter }
|
||||
|
||||
func (shiftJISDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
loop:
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
switch c0 := src[nSrc]; {
|
||||
case c0 < utf8.RuneSelf:
|
||||
r, size = rune(c0), 1
|
||||
|
||||
case 0xa1 <= c0 && c0 < 0xe0:
|
||||
r, size = rune(c0)+(0xff61-0xa1), 1
|
||||
|
||||
case (0x81 <= c0 && c0 < 0xa0) || (0xe0 <= c0 && c0 < 0xfd):
|
||||
if c0 <= 0x9f {
|
||||
c0 -= 0x70
|
||||
} else {
|
||||
c0 -= 0xb0
|
||||
}
|
||||
c0 = 2*c0 - 0x21
|
||||
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = '\ufffd', 1
|
||||
goto write
|
||||
}
|
||||
c1 := src[nSrc+1]
|
||||
switch {
|
||||
case c1 < 0x40:
|
||||
r, size = '\ufffd', 1 // c1 is ASCII so output on next round
|
||||
goto write
|
||||
case c1 < 0x7f:
|
||||
c0--
|
||||
c1 -= 0x40
|
||||
case c1 == 0x7f:
|
||||
r, size = '\ufffd', 1 // c1 is ASCII so output on next round
|
||||
goto write
|
||||
case c1 < 0x9f:
|
||||
c0--
|
||||
c1 -= 0x41
|
||||
case c1 < 0xfd:
|
||||
c1 -= 0x9f
|
||||
default:
|
||||
r, size = '\ufffd', 2
|
||||
goto write
|
||||
}
|
||||
r, size = '\ufffd', 2
|
||||
if i := int(c0)*94 + int(c1); i < len(jis0208Decode) {
|
||||
r = rune(jis0208Decode[i])
|
||||
if r == 0 {
|
||||
r = '\ufffd'
|
||||
}
|
||||
}
|
||||
|
||||
case c0 == 0x80:
|
||||
r, size = 0x80, 1
|
||||
|
||||
default:
|
||||
r, size = '\ufffd', 1
|
||||
}
|
||||
write:
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type shiftJISEncoder struct{ transform.NopResetter }
|
||||
|
||||
func (shiftJISEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
loop:
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
// func init checks that the switch covers all tables.
|
||||
switch {
|
||||
case encode0Low <= r && r < encode0High:
|
||||
if r = rune(encode0[r-encode0Low]); r>>tableShift == jis0208 {
|
||||
goto write2
|
||||
}
|
||||
case encode1Low <= r && r < encode1High:
|
||||
if r = rune(encode1[r-encode1Low]); r>>tableShift == jis0208 {
|
||||
goto write2
|
||||
}
|
||||
case encode2Low <= r && r < encode2High:
|
||||
if r = rune(encode2[r-encode2Low]); r>>tableShift == jis0208 {
|
||||
goto write2
|
||||
}
|
||||
case encode3Low <= r && r < encode3High:
|
||||
if r = rune(encode3[r-encode3Low]); r>>tableShift == jis0208 {
|
||||
goto write2
|
||||
}
|
||||
case encode4Low <= r && r < encode4High:
|
||||
if r = rune(encode4[r-encode4Low]); r>>tableShift == jis0208 {
|
||||
goto write2
|
||||
}
|
||||
case encode5Low <= r && r < encode5High:
|
||||
if 0xff61 <= r && r < 0xffa0 {
|
||||
r -= 0xff61 - 0xa1
|
||||
goto write1
|
||||
}
|
||||
if r = rune(encode5[r-encode5Low]); r>>tableShift == jis0208 {
|
||||
goto write2
|
||||
}
|
||||
}
|
||||
err = internal.ErrASCIIReplacement
|
||||
break
|
||||
}
|
||||
|
||||
write1:
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r)
|
||||
nDst++
|
||||
continue
|
||||
|
||||
write2:
|
||||
j1 := uint8(r>>codeShift) & codeMask
|
||||
j2 := uint8(r) & codeMask
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
if j1 <= 61 {
|
||||
dst[nDst+0] = 129 + j1/2
|
||||
} else {
|
||||
dst[nDst+0] = 193 + j1/2
|
||||
}
|
||||
if j1&1 == 0 {
|
||||
dst[nDst+1] = j2 + j2/63 + 64
|
||||
} else {
|
||||
dst[nDst+1] = j2 + 159
|
||||
}
|
||||
nDst += 2
|
||||
continue
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
+26971
File diff suppressed because it is too large
Load Diff
+177
@@ -0,0 +1,177 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package korean
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// All is a list of all defined encodings in this package.
|
||||
var All = []encoding.Encoding{EUCKR}
|
||||
|
||||
// EUCKR is the EUC-KR encoding, also known as Code Page 949.
|
||||
var EUCKR encoding.Encoding = &eucKR
|
||||
|
||||
var eucKR = internal.Encoding{
|
||||
&internal.SimpleEncoding{eucKRDecoder{}, eucKREncoder{}},
|
||||
"EUC-KR",
|
||||
identifier.EUCKR,
|
||||
}
|
||||
|
||||
type eucKRDecoder struct{ transform.NopResetter }
|
||||
|
||||
func (eucKRDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
loop:
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
switch c0 := src[nSrc]; {
|
||||
case c0 < utf8.RuneSelf:
|
||||
r, size = rune(c0), 1
|
||||
|
||||
case 0x81 <= c0 && c0 < 0xff:
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
break
|
||||
}
|
||||
c1 := src[nSrc+1]
|
||||
size = 2
|
||||
if c0 < 0xc7 {
|
||||
r = 178 * rune(c0-0x81)
|
||||
switch {
|
||||
case 0x41 <= c1 && c1 < 0x5b:
|
||||
r += rune(c1) - (0x41 - 0*26)
|
||||
case 0x61 <= c1 && c1 < 0x7b:
|
||||
r += rune(c1) - (0x61 - 1*26)
|
||||
case 0x81 <= c1 && c1 < 0xff:
|
||||
r += rune(c1) - (0x81 - 2*26)
|
||||
default:
|
||||
goto decError
|
||||
}
|
||||
} else if 0xa1 <= c1 && c1 < 0xff {
|
||||
r = 178*(0xc7-0x81) + rune(c0-0xc7)*94 + rune(c1-0xa1)
|
||||
} else {
|
||||
goto decError
|
||||
}
|
||||
if int(r) < len(decode) {
|
||||
r = rune(decode[r])
|
||||
if r != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
decError:
|
||||
r = utf8.RuneError
|
||||
if c1 < utf8.RuneSelf {
|
||||
size = 1
|
||||
}
|
||||
|
||||
default:
|
||||
r, size = utf8.RuneError, 1
|
||||
break
|
||||
}
|
||||
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type eucKREncoder struct{ transform.NopResetter }
|
||||
|
||||
func (eucKREncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r)
|
||||
nDst++
|
||||
continue
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// func init checks that the switch covers all tables.
|
||||
switch {
|
||||
case encode0Low <= r && r < encode0High:
|
||||
if r = rune(encode0[r-encode0Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode1Low <= r && r < encode1High:
|
||||
if r = rune(encode1[r-encode1Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode2Low <= r && r < encode2High:
|
||||
if r = rune(encode2[r-encode2Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode3Low <= r && r < encode3High:
|
||||
if r = rune(encode3[r-encode3Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode4Low <= r && r < encode4High:
|
||||
if r = rune(encode4[r-encode4Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode5Low <= r && r < encode5High:
|
||||
if r = rune(encode5[r-encode5Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode6Low <= r && r < encode6High:
|
||||
if r = rune(encode6[r-encode6Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
}
|
||||
err = internal.ErrASCIIReplacement
|
||||
break
|
||||
}
|
||||
|
||||
write2:
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = uint8(r >> 8)
|
||||
dst[nDst+1] = uint8(r)
|
||||
nDst += 2
|
||||
continue
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Check that the hard-coded encode switch covers all tables.
|
||||
if numEncodeTables != 7 {
|
||||
panic("bad numEncodeTables")
|
||||
}
|
||||
}
|
||||
+34152
File diff suppressed because it is too large
Load Diff
+12
@@ -0,0 +1,12 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package simplifiedchinese
|
||||
|
||||
import (
|
||||
"golang.org/x/text/encoding"
|
||||
)
|
||||
|
||||
// All is a list of all defined encodings in this package.
|
||||
var All = []encoding.Encoding{GB18030, GBK, HZGB2312}
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package simplifiedchinese
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
var (
|
||||
// GB18030 is the GB18030 encoding.
|
||||
GB18030 encoding.Encoding = &gbk18030
|
||||
// GBK is the GBK encoding. It encodes an extension of the GB2312 character set
|
||||
// and is also known as Code Page 936.
|
||||
GBK encoding.Encoding = &gbk
|
||||
)
|
||||
|
||||
var gbk = internal.Encoding{
|
||||
&internal.SimpleEncoding{
|
||||
gbkDecoder{gb18030: false},
|
||||
gbkEncoder{gb18030: false},
|
||||
},
|
||||
"GBK",
|
||||
identifier.GBK,
|
||||
}
|
||||
|
||||
var gbk18030 = internal.Encoding{
|
||||
&internal.SimpleEncoding{
|
||||
gbkDecoder{gb18030: true},
|
||||
gbkEncoder{gb18030: true},
|
||||
},
|
||||
"GB18030",
|
||||
identifier.GB18030,
|
||||
}
|
||||
|
||||
type gbkDecoder struct {
|
||||
transform.NopResetter
|
||||
gb18030 bool
|
||||
}
|
||||
|
||||
func (d gbkDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
loop:
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
switch c0 := src[nSrc]; {
|
||||
case c0 < utf8.RuneSelf:
|
||||
r, size = rune(c0), 1
|
||||
|
||||
// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC
|
||||
// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk
|
||||
// says to treat "gbk" as Code Page 936.
|
||||
case c0 == 0x80:
|
||||
r, size = '€', 1
|
||||
|
||||
case c0 < 0xff:
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
c1 := src[nSrc+1]
|
||||
switch {
|
||||
case 0x40 <= c1 && c1 < 0x7f:
|
||||
c1 -= 0x40
|
||||
case 0x80 <= c1 && c1 < 0xff:
|
||||
c1 -= 0x41
|
||||
case d.gb18030 && 0x30 <= c1 && c1 < 0x40:
|
||||
if nSrc+3 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
// The second byte here is always ASCII, so we can set size
|
||||
// to 1 in all cases.
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
c2 := src[nSrc+2]
|
||||
if c2 < 0x81 || 0xff <= c2 {
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
c3 := src[nSrc+3]
|
||||
if c3 < 0x30 || 0x3a <= c3 {
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
size = 4
|
||||
r = ((rune(c0-0x81)*10+rune(c1-0x30))*126+rune(c2-0x81))*10 + rune(c3-0x30)
|
||||
if r < 39420 {
|
||||
i, j := 0, len(gb18030)
|
||||
for i < j {
|
||||
h := i + (j-i)/2
|
||||
if r >= rune(gb18030[h][0]) {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
dec := &gb18030[i-1]
|
||||
r += rune(dec[1]) - rune(dec[0])
|
||||
goto write
|
||||
}
|
||||
r -= 189000
|
||||
if 0 <= r && r < 0x100000 {
|
||||
r += 0x10000
|
||||
} else {
|
||||
r, size = utf8.RuneError, 1
|
||||
}
|
||||
goto write
|
||||
default:
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
r, size = '\ufffd', 2
|
||||
if i := int(c0-0x81)*190 + int(c1); i < len(decode) {
|
||||
r = rune(decode[i])
|
||||
if r == 0 {
|
||||
r = '\ufffd'
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
r, size = utf8.RuneError, 1
|
||||
}
|
||||
|
||||
write:
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type gbkEncoder struct {
|
||||
transform.NopResetter
|
||||
gb18030 bool
|
||||
}
|
||||
|
||||
func (e gbkEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, r2, size := rune(0), rune(0), 0
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// func init checks that the switch covers all tables.
|
||||
switch {
|
||||
case encode0Low <= r && r < encode0High:
|
||||
if r2 = rune(encode0[r-encode0Low]); r2 != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode1Low <= r && r < encode1High:
|
||||
// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC
|
||||
// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk
|
||||
// says to treat "gbk" as Code Page 936.
|
||||
if r == '€' {
|
||||
r = 0x80
|
||||
goto write1
|
||||
}
|
||||
if r2 = rune(encode1[r-encode1Low]); r2 != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode2Low <= r && r < encode2High:
|
||||
if r2 = rune(encode2[r-encode2Low]); r2 != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode3Low <= r && r < encode3High:
|
||||
if r2 = rune(encode3[r-encode3Low]); r2 != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode4Low <= r && r < encode4High:
|
||||
if r2 = rune(encode4[r-encode4Low]); r2 != 0 {
|
||||
goto write2
|
||||
}
|
||||
}
|
||||
|
||||
if e.gb18030 {
|
||||
if r < 0x10000 {
|
||||
i, j := 0, len(gb18030)
|
||||
for i < j {
|
||||
h := i + (j-i)/2
|
||||
if r >= rune(gb18030[h][1]) {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
dec := &gb18030[i-1]
|
||||
r += rune(dec[0]) - rune(dec[1])
|
||||
goto write4
|
||||
} else if r < 0x110000 {
|
||||
r += 189000 - 0x10000
|
||||
goto write4
|
||||
}
|
||||
}
|
||||
err = internal.ErrASCIIReplacement
|
||||
break
|
||||
}
|
||||
|
||||
write1:
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r)
|
||||
nDst++
|
||||
continue
|
||||
|
||||
write2:
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = uint8(r2 >> 8)
|
||||
dst[nDst+1] = uint8(r2)
|
||||
nDst += 2
|
||||
continue
|
||||
|
||||
write4:
|
||||
if nDst+4 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+3] = uint8(r%10 + 0x30)
|
||||
r /= 10
|
||||
dst[nDst+2] = uint8(r%126 + 0x81)
|
||||
r /= 126
|
||||
dst[nDst+1] = uint8(r%10 + 0x30)
|
||||
r /= 10
|
||||
dst[nDst+0] = uint8(r + 0x81)
|
||||
nDst += 4
|
||||
continue
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Check that the hard-coded encode switch covers all tables.
|
||||
if numEncodeTables != 5 {
|
||||
panic("bad numEncodeTables")
|
||||
}
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package simplifiedchinese
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// HZGB2312 is the HZ-GB2312 encoding.
|
||||
var HZGB2312 encoding.Encoding = &hzGB2312
|
||||
|
||||
var hzGB2312 = internal.Encoding{
|
||||
internal.FuncEncoding{hzGB2312NewDecoder, hzGB2312NewEncoder},
|
||||
"HZ-GB2312",
|
||||
identifier.HZGB2312,
|
||||
}
|
||||
|
||||
func hzGB2312NewDecoder() transform.Transformer {
|
||||
return new(hzGB2312Decoder)
|
||||
}
|
||||
|
||||
func hzGB2312NewEncoder() transform.Transformer {
|
||||
return new(hzGB2312Encoder)
|
||||
}
|
||||
|
||||
const (
|
||||
asciiState = iota
|
||||
gbState
|
||||
)
|
||||
|
||||
type hzGB2312Decoder int
|
||||
|
||||
func (d *hzGB2312Decoder) Reset() {
|
||||
*d = asciiState
|
||||
}
|
||||
|
||||
func (d *hzGB2312Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
loop:
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
c0 := src[nSrc]
|
||||
if c0 >= utf8.RuneSelf {
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
|
||||
if c0 == '~' {
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
size = 2
|
||||
switch src[nSrc+1] {
|
||||
case '{':
|
||||
*d = gbState
|
||||
continue
|
||||
case '}':
|
||||
*d = asciiState
|
||||
continue
|
||||
case '~':
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
dst[nDst] = '~'
|
||||
nDst++
|
||||
continue
|
||||
case '\n':
|
||||
continue
|
||||
default:
|
||||
r = utf8.RuneError
|
||||
goto write
|
||||
}
|
||||
}
|
||||
|
||||
if *d == asciiState {
|
||||
r, size = rune(c0), 1
|
||||
} else {
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
size = 2
|
||||
c1 := src[nSrc+1]
|
||||
if c0 < 0x21 || 0x7e <= c0 || c1 < 0x21 || 0x7f <= c1 {
|
||||
// error
|
||||
} else if i := int(c0-0x01)*190 + int(c1+0x3f); i < len(decode) {
|
||||
r = rune(decode[i])
|
||||
if r != 0 {
|
||||
goto write
|
||||
}
|
||||
}
|
||||
if c1 > utf8.RuneSelf {
|
||||
// Be consistent and always treat non-ASCII as a single error.
|
||||
size = 1
|
||||
}
|
||||
r = utf8.RuneError
|
||||
}
|
||||
|
||||
write:
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type hzGB2312Encoder int
|
||||
|
||||
func (d *hzGB2312Encoder) Reset() {
|
||||
*d = asciiState
|
||||
}
|
||||
|
||||
func (e *hzGB2312Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
if r == '~' {
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = '~'
|
||||
dst[nDst+1] = '~'
|
||||
nDst += 2
|
||||
continue
|
||||
} else if *e != asciiState {
|
||||
if nDst+3 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
*e = asciiState
|
||||
dst[nDst+0] = '~'
|
||||
dst[nDst+1] = '}'
|
||||
nDst += 2
|
||||
} else if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r)
|
||||
nDst += 1
|
||||
continue
|
||||
|
||||
}
|
||||
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// func init checks that the switch covers all tables.
|
||||
switch {
|
||||
case encode0Low <= r && r < encode0High:
|
||||
if r = rune(encode0[r-encode0Low]); r != 0 {
|
||||
goto writeGB
|
||||
}
|
||||
case encode1Low <= r && r < encode1High:
|
||||
if r = rune(encode1[r-encode1Low]); r != 0 {
|
||||
goto writeGB
|
||||
}
|
||||
case encode2Low <= r && r < encode2High:
|
||||
if r = rune(encode2[r-encode2Low]); r != 0 {
|
||||
goto writeGB
|
||||
}
|
||||
case encode3Low <= r && r < encode3High:
|
||||
if r = rune(encode3[r-encode3Low]); r != 0 {
|
||||
goto writeGB
|
||||
}
|
||||
case encode4Low <= r && r < encode4High:
|
||||
if r = rune(encode4[r-encode4Low]); r != 0 {
|
||||
goto writeGB
|
||||
}
|
||||
}
|
||||
|
||||
terminateInASCIIState:
|
||||
// Switch back to ASCII state in case of error so that an ASCII
|
||||
// replacement character can be written in the correct state.
|
||||
if *e != asciiState {
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = '~'
|
||||
dst[nDst+1] = '}'
|
||||
nDst += 2
|
||||
}
|
||||
err = internal.ErrASCIIReplacement
|
||||
break
|
||||
|
||||
writeGB:
|
||||
c0 := uint8(r>>8) - 0x80
|
||||
c1 := uint8(r) - 0x80
|
||||
if c0 < 0x21 || 0x7e <= c0 || c1 < 0x21 || 0x7f <= c1 {
|
||||
goto terminateInASCIIState
|
||||
}
|
||||
if *e == asciiState {
|
||||
if nDst+4 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
*e = gbState
|
||||
dst[nDst+0] = '~'
|
||||
dst[nDst+1] = '{'
|
||||
nDst += 2
|
||||
} else if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = c0
|
||||
dst[nDst+1] = c1
|
||||
nDst += 2
|
||||
continue
|
||||
}
|
||||
// TODO: should one always terminate in ASCII state to make it safe to
|
||||
// concatenate two HZ-GB2312-encoded strings?
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
+43999
File diff suppressed because it is too large
Load Diff
+199
@@ -0,0 +1,199 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package traditionalchinese
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/internal"
|
||||
"golang.org/x/text/encoding/internal/identifier"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// All is a list of all defined encodings in this package.
|
||||
var All = []encoding.Encoding{Big5}
|
||||
|
||||
// Big5 is the Big5 encoding, also known as Code Page 950.
|
||||
var Big5 encoding.Encoding = &big5
|
||||
|
||||
var big5 = internal.Encoding{
|
||||
&internal.SimpleEncoding{big5Decoder{}, big5Encoder{}},
|
||||
"Big5",
|
||||
identifier.Big5,
|
||||
}
|
||||
|
||||
type big5Decoder struct{ transform.NopResetter }
|
||||
|
||||
func (big5Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size, s := rune(0), 0, ""
|
||||
loop:
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
switch c0 := src[nSrc]; {
|
||||
case c0 < utf8.RuneSelf:
|
||||
r, size = rune(c0), 1
|
||||
|
||||
case 0x81 <= c0 && c0 < 0xff:
|
||||
if nSrc+1 >= len(src) {
|
||||
if !atEOF {
|
||||
err = transform.ErrShortSrc
|
||||
break loop
|
||||
}
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
}
|
||||
c1 := src[nSrc+1]
|
||||
switch {
|
||||
case 0x40 <= c1 && c1 < 0x7f:
|
||||
c1 -= 0x40
|
||||
case 0xa1 <= c1 && c1 < 0xff:
|
||||
c1 -= 0x62
|
||||
case c1 < 0x40:
|
||||
r, size = utf8.RuneError, 1
|
||||
goto write
|
||||
default:
|
||||
r, size = utf8.RuneError, 2
|
||||
goto write
|
||||
}
|
||||
r, size = '\ufffd', 2
|
||||
if i := int(c0-0x81)*157 + int(c1); i < len(decode) {
|
||||
if 1133 <= i && i < 1167 {
|
||||
// The two-rune special cases for LATIN CAPITAL / SMALL E WITH CIRCUMFLEX
|
||||
// AND MACRON / CARON are from http://encoding.spec.whatwg.org/#big5
|
||||
switch i {
|
||||
case 1133:
|
||||
s = "\u00CA\u0304"
|
||||
goto writeStr
|
||||
case 1135:
|
||||
s = "\u00CA\u030C"
|
||||
goto writeStr
|
||||
case 1164:
|
||||
s = "\u00EA\u0304"
|
||||
goto writeStr
|
||||
case 1166:
|
||||
s = "\u00EA\u030C"
|
||||
goto writeStr
|
||||
}
|
||||
}
|
||||
r = rune(decode[i])
|
||||
if r == 0 {
|
||||
r = '\ufffd'
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
r, size = utf8.RuneError, 1
|
||||
}
|
||||
|
||||
write:
|
||||
if nDst+utf8.RuneLen(r) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
nDst += utf8.EncodeRune(dst[nDst:], r)
|
||||
continue loop
|
||||
|
||||
writeStr:
|
||||
if nDst+len(s) > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break loop
|
||||
}
|
||||
nDst += copy(dst[nDst:], s)
|
||||
continue loop
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
type big5Encoder struct{ transform.NopResetter }
|
||||
|
||||
func (big5Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||
r, size := rune(0), 0
|
||||
for ; nSrc < len(src); nSrc += size {
|
||||
r = rune(src[nSrc])
|
||||
|
||||
// Decode a 1-byte rune.
|
||||
if r < utf8.RuneSelf {
|
||||
size = 1
|
||||
if nDst >= len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst] = uint8(r)
|
||||
nDst++
|
||||
continue
|
||||
|
||||
} else {
|
||||
// Decode a multi-byte rune.
|
||||
r, size = utf8.DecodeRune(src[nSrc:])
|
||||
if size == 1 {
|
||||
// All valid runes of size 1 (those below utf8.RuneSelf) were
|
||||
// handled above. We have invalid UTF-8 or we haven't seen the
|
||||
// full character yet.
|
||||
if !atEOF && !utf8.FullRune(src[nSrc:]) {
|
||||
err = transform.ErrShortSrc
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r >= utf8.RuneSelf {
|
||||
// func init checks that the switch covers all tables.
|
||||
switch {
|
||||
case encode0Low <= r && r < encode0High:
|
||||
if r = rune(encode0[r-encode0Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode1Low <= r && r < encode1High:
|
||||
if r = rune(encode1[r-encode1Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode2Low <= r && r < encode2High:
|
||||
if r = rune(encode2[r-encode2Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode3Low <= r && r < encode3High:
|
||||
if r = rune(encode3[r-encode3Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode4Low <= r && r < encode4High:
|
||||
if r = rune(encode4[r-encode4Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode5Low <= r && r < encode5High:
|
||||
if r = rune(encode5[r-encode5Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode6Low <= r && r < encode6High:
|
||||
if r = rune(encode6[r-encode6Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
case encode7Low <= r && r < encode7High:
|
||||
if r = rune(encode7[r-encode7Low]); r != 0 {
|
||||
goto write2
|
||||
}
|
||||
}
|
||||
err = internal.ErrASCIIReplacement
|
||||
break
|
||||
}
|
||||
|
||||
write2:
|
||||
if nDst+2 > len(dst) {
|
||||
err = transform.ErrShortDst
|
||||
break
|
||||
}
|
||||
dst[nDst+0] = uint8(r >> 8)
|
||||
dst[nDst+1] = uint8(r)
|
||||
nDst += 2
|
||||
continue
|
||||
}
|
||||
return nDst, nSrc, err
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Check that the hard-coded encode switch covers all tables.
|
||||
if numEncodeTables != 8 {
|
||||
panic("bad numEncodeTables")
|
||||
}
|
||||
}
|
||||
+37142
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user