feat(db): 添加对达梦数据库的支持
- 在应用程序中新增对达梦数据库(DM)的配置和连接支持 - 实现 SetDmDB 函数以配置达梦数据库连接 - 更新数据库操作逻辑,支持达梦特有的 SQL 语法和功能 - 在相关文件中添加达梦数据库的处理逻辑,包括表创建、数据插入和查询 - 更新 go.mod 和 go.sum 文件以引入达梦数据库驱动 - 增强文档,详细说明达梦数据库的配置和使用方法
This commit is contained in:
+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++
|
||||
}
|
||||
Reference in New Issue
Block a user