Files
mayfly-go/server/internal/db/dbm/oracle/helper.go
zongyangleo 6343173cf8 !124 一些更新和bug
* fix: 代码合并
* feat:支持数据库版本兼容,目前兼容了oracle11g部分特性
* fix: 修改数据同步bug,数据sql里指定修改字段别,导致未正确记录修改字段值
* feat: 数据库迁移支持定时迁移和迁移到sql文件
2024-10-20 03:52:23 +00:00

186 lines
5.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package oracle
import (
"fmt"
"mayfly-go/internal/db/dbm/dbi"
"mayfly-go/pkg/utils/anyx"
"mayfly-go/pkg/utils/collx"
"regexp"
"strings"
"time"
"github.com/may-fly/cast"
)
var (
// 数字类型
numberTypeRegexp = regexp.MustCompile(`(?i)int|double|float|number|decimal|byte|bit`)
dateTimeReg = regexp.MustCompile(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$`)
dateTimeIsoReg = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*$`)
// 日期时间类型
datetimeTypeRegexp = regexp.MustCompile(`(?i)date|timestamp`)
// oracle数据类型 映射 公共数据类型
commonColumnTypeMap = map[string]dbi.ColumnDataType{
"CHAR": dbi.CommonTypeChar,
"NCHAR": dbi.CommonTypeChar,
"VARCHAR2": dbi.CommonTypeVarchar,
"NVARCHAR2": dbi.CommonTypeVarchar,
"NUMBER": dbi.CommonTypeNumber,
"INTEGER": dbi.CommonTypeInt,
"INT": dbi.CommonTypeInt,
"DECIMAL": dbi.CommonTypeNumber,
"FLOAT": dbi.CommonTypeNumber,
"REAL": dbi.CommonTypeNumber,
"BINARY_FLOAT": dbi.CommonTypeNumber,
"BINARY_DOUBLE": dbi.CommonTypeNumber,
"DATE": dbi.CommonTypeDate,
"TIMESTAMP": dbi.CommonTypeDatetime,
"LONG": dbi.CommonTypeLongtext,
"BLOB": dbi.CommonTypeLongtext,
"CLOB": dbi.CommonTypeLongtext,
"NCLOB": dbi.CommonTypeLongtext,
"BFILE": dbi.CommonTypeBinary,
}
// 公共数据类型 映射 oracle数据类型
oracleColumnTypeMap = map[dbi.ColumnDataType]string{
dbi.CommonTypeVarchar: "NVARCHAR2",
dbi.CommonTypeChar: "NCHAR",
dbi.CommonTypeText: "CLOB",
dbi.CommonTypeBlob: "CLOB",
dbi.CommonTypeLongblob: "CLOB",
dbi.CommonTypeLongtext: "CLOB",
dbi.CommonTypeBinary: "BFILE",
dbi.CommonTypeMediumblob: "CLOB",
dbi.CommonTypeMediumtext: "CLOB",
dbi.CommonTypeVarbinary: "BFILE",
dbi.CommonTypeInt: "INT",
dbi.CommonTypeSmallint: "INT",
dbi.CommonTypeTinyint: "INT",
dbi.CommonTypeNumber: "NUMBER",
dbi.CommonTypeBigint: "NUMBER",
dbi.CommonTypeDatetime: "DATE",
dbi.CommonTypeDate: "DATE",
dbi.CommonTypeTime: "DATE",
dbi.CommonTypeTimestamp: "TIMESTAMP",
dbi.CommonTypeEnum: "CLOB",
dbi.CommonTypeJSON: "CLOB",
}
)
type DataHelper struct {
}
func (dc *DataHelper) GetDataType(dbColumnType string) dbi.DataType {
if numberTypeRegexp.MatchString(dbColumnType) {
return dbi.DataTypeNumber
}
// 日期时间类型
if datetimeTypeRegexp.MatchString(dbColumnType) {
return dbi.DataTypeDateTime
}
return dbi.DataTypeString
}
func (dc *DataHelper) FormatData(dbColumnValue any, dataType dbi.DataType) string {
str := anyx.ToString(dbColumnValue)
if dateTimeReg.MatchString(str) || dateTimeIsoReg.MatchString(str) {
dataType = dbi.DataTypeDateTime
}
switch dataType {
// oracle把日期类型数据格式化输出
case dbi.DataTypeDateTime: // "2024-01-02T22:08:22.275697+08:00"
// 尝试用时间格式解析
res, err := time.Parse(time.DateTime, str)
if err == nil {
return str
}
res, _ = time.Parse(time.RFC3339, str)
return res.Format(time.DateTime)
}
return str
}
func (dc *DataHelper) ParseData(dbColumnValue any, dataType dbi.DataType) any {
// oracle把日期类型的数据转化为time类型
if dataType == dbi.DataTypeDateTime {
res, _ := time.Parse(time.RFC3339, cast.ToString(dbColumnValue))
return res
}
return dbColumnValue
}
func (dc *DataHelper) WrapValue(dbColumnValue any, dataType dbi.DataType) string {
if dbColumnValue == nil {
return "NULL"
}
switch dataType {
case dbi.DataTypeNumber:
return fmt.Sprintf("%v", dbColumnValue)
case dbi.DataTypeString:
val := fmt.Sprintf("%v", dbColumnValue)
// 转义单引号
val = strings.Replace(val, `'`, `''`, -1)
val = strings.Replace(val, `\''`, `\'`, -1)
// 转义换行符
val = strings.Replace(val, "\n", "\\n", -1)
return fmt.Sprintf("'%s'", val)
case dbi.DataTypeDate, dbi.DataTypeDateTime, dbi.DataTypeTime:
return fmt.Sprintf("to_date('%s', 'yyyy-mm-dd hh24:mi:ss')", dc.FormatData(dbColumnValue, dataType))
}
return fmt.Sprintf("'%s'", dbColumnValue)
}
type ColumnHelper struct {
}
func (ch *ColumnHelper) ToCommonColumn(dialectColumn *dbi.Column) {
// 翻译为通用数据库类型
dataType := dialectColumn.DataType
t1 := commonColumnTypeMap[string(dataType)]
if t1 == "" {
dialectColumn.DataType = dbi.CommonTypeVarchar
dialectColumn.CharMaxLength = 2000
} else {
dialectColumn.DataType = t1
// 如果是number类型需要根据公共类型加上长度, 如 bigint 需要转换为number(19,0)
if strings.Contains(string(t1), "NUMBER") {
dialectColumn.CharMaxLength = 19
}
}
}
func (ch *ColumnHelper) ToColumn(commonColumn *dbi.Column) {
ctype := oracleColumnTypeMap[commonColumn.DataType]
if ctype == "" {
commonColumn.DataType = "NVARCHAR2"
commonColumn.CharMaxLength = 2000
} else {
commonColumn.DataType = dbi.ColumnDataType(ctype)
ch.FixColumn(commonColumn)
}
}
func (ch *ColumnHelper) FixColumn(column *dbi.Column) {
// 如果默认值包含.nextval说明是序列默认值为null
if strings.Contains(column.ColumnDefault, ".nextval") {
column.ColumnDefault = ""
}
// 统一处理一下数据类型的长度
if collx.ArrayAnyMatches([]string{"date", "time", "lob", "int"}, strings.ToLower(string(column.DataType))) {
// 如果是不需要设置长度的类型
column.CharMaxLength = 0
column.NumPrecision = 0
} else if strings.Contains(strings.ToLower(string(column.DataType)), "char") {
// 如果是字符串类型长度最大4000否则修改字段类型为clob
if column.CharMaxLength > 4000 {
column.DataType = "NCLOB"
column.CharMaxLength = 0
column.NumPrecision = 0
}
}
}