2024-03-11 20:04:20 +08:00
package mssql
import (
"fmt"
"mayfly-go/internal/db/dbm/dbi"
"mayfly-go/pkg/errorx"
2024-03-21 03:35:18 +00:00
"mayfly-go/pkg/logx"
2024-03-11 20:04:20 +08:00
"mayfly-go/pkg/utils/anyx"
"mayfly-go/pkg/utils/collx"
2024-03-18 12:25:40 +08:00
"mayfly-go/pkg/utils/stringx"
2024-03-15 13:31:53 +08:00
"regexp"
2024-03-11 20:04:20 +08:00
"strings"
2024-03-15 13:31:53 +08:00
"time"
2024-03-21 17:15:52 +08:00
"github.com/may-fly/cast"
2024-03-11 20:04:20 +08:00
)
const (
2024-03-21 03:35:18 +00:00
MSSQL_META_FILE = "metasql/mssql_meta.sql"
MSSQL_DBS_KEY = "MSSQL_DBS"
MSSQL_DB_SCHEMAS_KEY = "MSSQL_DB_SCHEMAS"
MSSQL_TABLE_INFO_KEY = "MSSQL_TABLE_INFO"
MSSQL_INDEX_INFO_KEY = "MSSQL_INDEX_INFO"
MSSQL_COLUMN_MA_KEY = "MSSQL_COLUMN_MA"
2024-03-11 20:04:20 +08:00
)
type MssqlMetaData struct {
2024-03-15 13:31:53 +08:00
dbi . DefaultMetaData
2024-03-11 20:04:20 +08:00
dc * dbi . DbConn
}
func ( md * MssqlMetaData ) GetDbServer ( ) ( * dbi . DbServer , error ) {
_ , res , err := md . dc . Query ( "SELECT @@VERSION as version" )
if err != nil {
return nil , err
}
ds := & dbi . DbServer {
2024-03-21 17:15:52 +08:00
Version : cast . ToString ( res [ 0 ] [ "version" ] ) ,
2024-03-11 20:04:20 +08:00
}
return ds , nil
}
func ( md * MssqlMetaData ) GetDbNames ( ) ( [ ] string , error ) {
_ , res , err := md . dc . Query ( dbi . GetLocalSql ( MSSQL_META_FILE , MSSQL_DBS_KEY ) )
if err != nil {
return nil , err
}
databases := make ( [ ] string , 0 )
for _ , re := range res {
2024-03-21 17:15:52 +08:00
databases = append ( databases , cast . ToString ( re [ "dbname" ] ) )
2024-03-11 20:04:20 +08:00
}
return databases , nil
}
// 获取表基础元信息, 如表名等
2024-03-15 09:01:51 +00:00
func ( md * MssqlMetaData ) GetTables ( tableNames ... string ) ( [ ] dbi . Table , error ) {
meta := md . dc . GetMetaData ( )
schema := md . dc . Info . CurrentSchema ( )
names := strings . Join ( collx . ArrayMap [ string , string ] ( tableNames , func ( val string ) string {
return fmt . Sprintf ( "'%s'" , meta . RemoveQuote ( val ) )
} ) , "," )
var res [ ] map [ string ] any
var err error
2024-03-18 12:25:40 +08:00
sql , err := stringx . TemplateParse ( dbi . GetLocalSql ( MSSQL_META_FILE , MSSQL_TABLE_INFO_KEY ) , collx . M { "tableNames" : names } )
if err != nil {
return nil , err
2024-03-15 09:01:51 +00:00
}
2024-03-11 20:04:20 +08:00
2024-03-18 12:25:40 +08:00
_ , res , err = md . dc . Query ( sql , schema )
2024-03-11 20:04:20 +08:00
if err != nil {
return nil , err
}
tables := make ( [ ] dbi . Table , 0 )
for _ , re := range res {
tables = append ( tables , dbi . Table {
2024-03-21 17:15:52 +08:00
TableName : cast . ToString ( re [ "tableName" ] ) ,
TableComment : cast . ToString ( re [ "tableComment" ] ) ,
CreateTime : cast . ToString ( re [ "createTime" ] ) ,
TableRows : cast . ToInt ( re [ "tableRows" ] ) ,
DataLength : cast . ToInt64 ( re [ "dataLength" ] ) ,
IndexLength : cast . ToInt64 ( re [ "indexLength" ] ) ,
2024-03-11 20:04:20 +08:00
} )
}
return tables , nil
}
// 获取列元信息, 如列名等
func ( md * MssqlMetaData ) GetColumns ( tableNames ... string ) ( [ ] dbi . Column , error ) {
2024-03-15 09:01:51 +00:00
meta := md . dc . GetMetaData ( )
2024-03-11 20:04:20 +08:00
tableName := strings . Join ( collx . ArrayMap [ string , string ] ( tableNames , func ( val string ) string {
2024-03-15 09:01:51 +00:00
return fmt . Sprintf ( "'%s'" , meta . RemoveQuote ( val ) )
2024-03-11 20:04:20 +08:00
} ) , "," )
_ , res , err := md . dc . Query ( fmt . Sprintf ( dbi . GetLocalSql ( MSSQL_META_FILE , MSSQL_COLUMN_MA_KEY ) , tableName ) , md . dc . Info . CurrentSchema ( ) )
if err != nil {
return nil , err
}
columns := make ( [ ] dbi . Column , 0 )
for _ , re := range res {
2024-03-21 03:35:18 +00:00
column := dbi . Column {
2024-03-11 20:04:20 +08:00
TableName : anyx . ToString ( re [ "TABLE_NAME" ] ) ,
ColumnName : anyx . ToString ( re [ "COLUMN_NAME" ] ) ,
2024-03-21 03:35:18 +00:00
DataType : dbi . ColumnDataType ( anyx . ToString ( re [ "DATA_TYPE" ] ) ) ,
2024-03-21 17:15:52 +08:00
CharMaxLength : cast . ToInt ( re [ "CHAR_MAX_LENGTH" ] ) ,
2024-03-11 20:04:20 +08:00
ColumnComment : anyx . ToString ( re [ "COLUMN_COMMENT" ] ) ,
2024-03-21 20:28:24 +08:00
Nullable : anyx . ToString ( re [ "NULLABLE" ] ) == "YES" ,
2024-03-21 17:15:52 +08:00
IsPrimaryKey : cast . ToInt ( re [ "IS_PRIMARY_KEY" ] ) == 1 ,
IsIdentity : cast . ToInt ( re [ "IS_IDENTITY" ] ) == 1 ,
ColumnDefault : cast . ToString ( re [ "COLUMN_DEFAULT" ] ) ,
NumPrecision : cast . ToInt ( re [ "NUM_PRECISION" ] ) ,
NumScale : cast . ToInt ( re [ "NUM_SCALE" ] ) ,
2024-03-21 03:35:18 +00:00
}
2024-03-26 09:05:28 +00:00
md . FixColumn ( & column )
2024-03-21 03:35:18 +00:00
columns = append ( columns , column )
2024-03-11 20:04:20 +08:00
}
return columns , nil
}
2024-03-26 09:05:28 +00:00
func ( md * MssqlMetaData ) FixColumn ( column * dbi . Column ) {
dataType := strings . ToLower ( string ( column . DataType ) )
if collx . ArrayAnyMatches ( [ ] string { "date" , "time" } , dataType ) {
// 如果是datetime, 精度取NumScale字段
column . CharMaxLength = column . NumScale
} else if collx . ArrayAnyMatches ( [ ] string { "int" , "bit" , "real" , "text" , "xml" } , dataType ) {
// 不显示长度的类型
column . NumPrecision = 0
column . CharMaxLength = 0
} else if collx . ArrayAnyMatches ( [ ] string { "numeric" , "decimal" , "float" } , dataType ) {
// 如果是num, 长度取精度和小数位数
column . CharMaxLength = 0
} else if collx . ArrayAnyMatches ( [ ] string { "nvarchar" , "nchar" } , dataType ) {
// 如果是nvarchar, 可视长度减半
column . CharMaxLength = column . CharMaxLength / 2
}
}
2024-03-11 20:04:20 +08:00
// 获取表主键字段名,不存在主键标识则默认第一个字段
func ( md * MssqlMetaData ) GetPrimaryKey ( tablename string ) ( string , error ) {
columns , err := md . GetColumns ( tablename )
if err != nil {
return "" , err
}
if len ( columns ) == 0 {
return "" , errorx . NewBiz ( "[%s] 表不存在" , tablename )
}
for _ , v := range columns {
if v . IsPrimaryKey {
return v . ColumnName , nil
}
}
return columns [ 0 ] . ColumnName , nil
}
func ( md * MssqlMetaData ) getTableIndexWithPK ( tableName string ) ( [ ] dbi . Index , error ) {
_ , res , err := md . dc . Query ( dbi . GetLocalSql ( MSSQL_META_FILE , MSSQL_INDEX_INFO_KEY ) , md . dc . Info . CurrentSchema ( ) , tableName )
if err != nil {
return nil , err
}
indexs := make ( [ ] dbi . Index , 0 )
for _ , re := range res {
indexs = append ( indexs , dbi . Index {
2024-03-21 17:15:52 +08:00
IndexName : cast . ToString ( re [ "indexName" ] ) ,
ColumnName : cast . ToString ( re [ "columnName" ] ) ,
IndexType : cast . ToString ( re [ "indexType" ] ) ,
IndexComment : cast . ToString ( re [ "indexComment" ] ) ,
IsUnique : cast . ToInt ( re [ "isUnique" ] ) == 1 ,
SeqInIndex : cast . ToInt ( re [ "seqInIndex" ] ) ,
2024-03-26 09:05:28 +00:00
IsPrimaryKey : cast . ToInt ( re [ "isPrimaryKey" ] ) == 1 ,
2024-03-11 20:04:20 +08:00
} )
}
// 把查询结果以索引名分组,多个索引字段以逗号连接
result := make ( [ ] dbi . Index , 0 )
key := ""
for _ , v := range indexs {
// 当前的索引名
in := v . IndexName
if key == in {
// 索引字段已根据名称和字段顺序排序,故取最后一个即可
i := len ( result ) - 1
// 同索引字段以逗号连接
result [ i ] . ColumnName = result [ i ] . ColumnName + "," + v . ColumnName
} else {
key = in
result = append ( result , v )
}
}
return indexs , nil
}
// 获取表索引信息
func ( md * MssqlMetaData ) GetTableIndex ( tableName string ) ( [ ] dbi . Index , error ) {
indexs , _ := md . getTableIndexWithPK ( tableName )
result := make ( [ ] dbi . Index , 0 )
2024-03-26 09:05:28 +00:00
// 过滤掉主键索引
2024-03-11 20:04:20 +08:00
for _ , v := range indexs {
2024-03-26 09:05:28 +00:00
if v . IsPrimaryKey {
2024-03-11 20:04:20 +08:00
continue
}
2024-03-21 17:15:52 +08:00
result = append ( result , v )
2024-03-11 20:04:20 +08:00
}
return result , nil
}
2024-03-15 13:31:53 +08:00
func ( md * MssqlMetaData ) CopyTableDDL ( tableName string , newTableName string ) ( string , error ) {
2024-03-11 20:04:20 +08:00
if newTableName == "" {
newTableName = tableName
}
2024-03-15 09:01:51 +00:00
meta := md . dc . GetMetaData ( )
2024-03-11 20:04:20 +08:00
// 查询表名和表注释, 设置表注释
2024-03-21 03:35:18 +00:00
tbs , err := md . GetTables ( tableName )
if err != nil || len ( tbs ) < 1 {
logx . Errorf ( "获取表信息失败, %s" , tableName )
2024-03-11 20:04:20 +08:00
return "" , err
}
2024-03-21 03:35:18 +00:00
tabInfo := & dbi . Table {
2024-03-21 17:15:52 +08:00
TableName : newTableName ,
2024-03-21 03:35:18 +00:00
TableComment : tbs [ 0 ] . TableComment ,
2024-03-11 20:04:20 +08:00
}
// 查询列信息
columns , err := md . GetColumns ( tableName )
if err != nil {
2024-03-21 03:35:18 +00:00
logx . Errorf ( "获取列信息失败, %s" , tableName )
2024-03-11 20:04:20 +08:00
return "" , err
}
2024-03-21 03:35:18 +00:00
sqlArr := meta . GenerateTableDDL ( columns , * tabInfo , true )
2024-03-11 20:04:20 +08:00
2024-03-21 03:35:18 +00:00
// 设置索引
indexs , err := md . GetTableIndex ( tableName )
if err != nil {
logx . Errorf ( "获取索引信息失败, %s" , tableName )
return strings . Join ( sqlArr , ";" ) , err
}
sqlArr = append ( sqlArr , meta . GenerateIndexDDL ( indexs , * tabInfo ) ... )
return strings . Join ( sqlArr , ";" ) , nil
}
// 获取建索引ddl
func ( md * MssqlMetaData ) GenerateIndexDDL ( indexs [ ] dbi . Index , tableInfo dbi . Table ) [ ] string {
tbName := tableInfo . TableName
2024-03-26 09:05:28 +00:00
meta := md . dc . GetMetaData ( )
2024-03-21 03:35:18 +00:00
sqls := make ( [ ] string , 0 )
comments := make ( [ ] string , 0 )
for _ , index := range indexs {
unique := ""
if index . IsUnique {
unique = "unique"
2024-03-11 20:04:20 +08:00
}
2024-03-26 09:05:28 +00:00
// 取出列名,添加引号
cols := strings . Split ( index . ColumnName , "," )
colNames := make ( [ ] string , len ( cols ) )
for i , name := range cols {
colNames [ i ] = meta . QuoteIdentifier ( name )
}
2024-03-21 03:35:18 +00:00
2024-03-26 09:05:28 +00:00
sqls = append ( sqls , fmt . Sprintf ( "create %s NONCLUSTERED index %s on %s.%s(%s)" , unique , index . IndexName , md . dc . Info . CurrentSchema ( ) , tbName , strings . Join ( colNames , "," ) ) )
2024-03-21 03:35:18 +00:00
if index . IndexComment != "" {
2024-03-26 09:05:28 +00:00
comment := meta . QuoteEscape ( index . IndexComment )
comments = append ( comments , fmt . Sprintf ( "EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s', N'INDEX', N'%s'" , comment , md . dc . Info . CurrentSchema ( ) , tbName , index . IndexName ) )
2024-03-11 20:04:20 +08:00
}
2024-03-21 03:35:18 +00:00
}
2024-03-21 17:15:52 +08:00
if len ( comments ) > 0 {
sqls = append ( sqls , comments ... )
}
2024-03-21 03:35:18 +00:00
return sqls
}
func ( md * MssqlMetaData ) genColumnBasicSql ( column dbi . Column ) string {
meta := md . dc . GetMetaData ( )
colName := meta . QuoteIdentifier ( column . ColumnName )
dataType := string ( column . DataType )
incr := ""
if column . IsIdentity {
incr = " IDENTITY(1,1)"
}
nullAble := ""
2024-03-21 20:28:24 +08:00
if ! column . Nullable {
2024-03-21 03:35:18 +00:00
nullAble = " NOT NULL"
}
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
if column . ColumnDefault != "" && ! strings . Contains ( column . ColumnDefault , "(" ) {
// 哪些字段类型默认值需要加引号
mark := false
if collx . ArrayAnyMatches ( [ ] string { "char" , "text" , "date" , "time" , "lob" } , dataType ) {
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
if collx . ArrayAnyMatches ( [ ] string { "date" , "time" } , strings . ToLower ( dataType ) ) &&
collx . ArrayAnyMatches ( [ ] string { "DATE" , "TIME" } , strings . ToUpper ( column . ColumnDefault ) ) {
mark = false
} else {
mark = true
}
2024-03-11 20:04:20 +08:00
}
2024-03-21 03:35:18 +00:00
if mark {
defVal = fmt . Sprintf ( " DEFAULT '%s'" , column . ColumnDefault )
} else {
defVal = fmt . Sprintf ( " DEFAULT %s" , column . ColumnDefault )
2024-03-11 20:04:20 +08:00
}
2024-03-21 03:35:18 +00:00
}
2024-03-26 09:05:28 +00:00
columnSql := fmt . Sprintf ( " %s %s%s%s%s" , colName , column . GetColumnType ( ) , incr , nullAble , defVal )
2024-03-21 03:35:18 +00:00
return columnSql
}
// 获取建表ddl
func ( md * MssqlMetaData ) GenerateTableDDL ( columns [ ] dbi . Column , tableInfo dbi . Table , dropBeforeCreate bool ) [ ] string {
tbName := tableInfo . TableName
meta := md . dc . GetMetaData ( )
sqlArr := make ( [ ] string , 0 )
// 删除表
if dropBeforeCreate {
sqlArr = append ( sqlArr , fmt . Sprintf ( "DROP TABLE IF EXISTS %s" , meta . QuoteIdentifier ( tbName ) ) )
}
// 组装建表语句
createSql := fmt . Sprintf ( "CREATE TABLE %s (\n" , meta . QuoteIdentifier ( tbName ) )
fields := make ( [ ] string , 0 )
pks := make ( [ ] string , 0 )
columnComments := make ( [ ] string , 0 )
for _ , column := range columns {
if column . IsPrimaryKey {
pks = append ( pks , meta . QuoteIdentifier ( column . ColumnName ) )
}
fields = append ( fields , md . genColumnBasicSql ( column ) )
commentTmp := "EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s', N'COLUMN', N'%s'"
// 防止注释内含有特殊字符串导致sql出错
if column . ColumnComment != "" {
2024-03-26 09:05:28 +00:00
comment := meta . QuoteEscape ( column . ColumnComment )
2024-03-21 03:35:18 +00:00
columnComments = append ( columnComments , fmt . Sprintf ( commentTmp , comment , md . dc . Info . CurrentSchema ( ) , tbName , column . ColumnName ) )
2024-03-11 20:04:20 +08:00
}
}
2024-03-21 03:35:18 +00:00
// create
createSql += strings . Join ( fields , ",\n" )
2024-03-11 20:04:20 +08:00
if len ( pks ) > 0 {
2024-03-21 03:35:18 +00:00
createSql += fmt . Sprintf ( ", \n PRIMARY KEY CLUSTERED (%s)" , strings . Join ( pks , "," ) )
2024-03-11 20:04:20 +08:00
}
2024-03-21 03:35:18 +00:00
createSql += "\n)"
2024-03-11 20:04:20 +08:00
2024-03-21 03:35:18 +00:00
// comment
tableCommentSql := ""
if tableInfo . TableComment != "" {
commentTmp := "EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s'"
2024-03-26 09:05:28 +00:00
tableCommentSql = fmt . Sprintf ( commentTmp , meta . QuoteEscape ( tableInfo . TableComment ) , md . dc . Info . CurrentSchema ( ) , tbName )
2024-03-11 20:04:20 +08:00
}
2024-03-21 03:35:18 +00:00
sqlArr = append ( sqlArr , createSql )
if tableCommentSql != "" {
sqlArr = append ( sqlArr , tableCommentSql )
2024-03-11 20:04:20 +08:00
}
2024-03-21 03:35:18 +00:00
if len ( columnComments ) > 0 {
sqlArr = append ( sqlArr , columnComments ... )
2024-03-11 20:04:20 +08:00
}
2024-03-21 03:35:18 +00:00
return sqlArr
2024-03-11 20:04:20 +08:00
}
// 获取建表ddl
2024-03-26 09:05:28 +00:00
func ( md * MssqlMetaData ) GetTableDDL ( tableName string , dropBeforeCreate bool ) ( string , error ) {
2024-03-21 03:35:18 +00:00
// 1.获取表信息
tbs , err := md . GetTables ( tableName )
tableInfo := & dbi . Table { }
2024-03-26 09:05:28 +00:00
if err != nil || tbs == nil || len ( tbs ) <= 0 {
2024-03-21 03:35:18 +00:00
logx . Errorf ( "获取表信息失败, %s" , tableName )
return "" , err
}
tableInfo . TableName = tbs [ 0 ] . TableName
tableInfo . TableComment = tbs [ 0 ] . TableComment
// 2.获取列信息
columns , err := md . GetColumns ( tableName )
if err != nil {
logx . Errorf ( "获取列信息失败, %s" , tableName )
return "" , err
}
2024-03-26 09:05:28 +00:00
tableDDLArr := md . GenerateTableDDL ( columns , * tableInfo , dropBeforeCreate )
2024-03-21 03:35:18 +00:00
// 3.获取索引信息
indexs , err := md . GetTableIndex ( tableName )
if err != nil {
logx . Errorf ( "获取索引信息失败, %s" , tableName )
return "" , err
}
// 组装返回
tableDDLArr = append ( tableDDLArr , md . GenerateIndexDDL ( indexs , * tableInfo ) ... )
return strings . Join ( tableDDLArr , ";\n" ) , nil
2024-03-11 20:04:20 +08:00
}
func ( md * MssqlMetaData ) GetSchemas ( ) ( [ ] string , error ) {
_ , res , err := md . dc . Query ( dbi . GetLocalSql ( MSSQL_META_FILE , MSSQL_DB_SCHEMAS_KEY ) )
if err != nil {
return nil , err
}
schemas := make ( [ ] string , 0 )
for _ , re := range res {
2024-03-21 17:15:52 +08:00
schemas = append ( schemas , cast . ToString ( re [ "SCHEMA_NAME" ] ) )
2024-03-11 20:04:20 +08:00
}
return schemas , nil
}
2024-03-15 13:31:53 +08:00
func ( md * MssqlMetaData ) GetIdentifierQuoteString ( ) string {
return "["
}
2024-03-26 09:05:28 +00:00
func ( md * MssqlMetaData ) BeforeDumpInsertSql ( quoteSchema string , tableName string ) string {
return fmt . Sprintf ( "set identity_insert %s.%s on " , quoteSchema , tableName )
}
2024-03-15 13:31:53 +08:00
func ( md * MssqlMetaData ) GetDataConverter ( ) dbi . DataConverter {
return converter
}
var (
// 数字类型
numberRegexp = regexp . MustCompile ( ` (?i)int|double|float|number|decimal|byte|bit ` )
// 日期时间类型
datetimeRegexp = regexp . MustCompile ( ` (?i)datetime|timestamp ` )
// 日期类型
dateRegexp = regexp . MustCompile ( ` (?i)date ` )
// 时间类型
timeRegexp = regexp . MustCompile ( ` (?i)time ` )
converter = new ( DataConverter )
2024-03-21 17:15:52 +08:00
2024-03-15 09:01:51 +00:00
// mssql数据类型 对应 公共数据类型
2024-03-18 12:25:40 +08:00
commonColumnTypeMap = map [ string ] dbi . ColumnDataType {
2024-03-15 09:01:51 +00:00
"bigint" : dbi . CommonTypeBigint ,
"numeric" : dbi . CommonTypeNumber ,
"bit" : dbi . CommonTypeInt ,
"smallint" : dbi . CommonTypeSmallint ,
"decimal" : dbi . CommonTypeNumber ,
"smallmoney" : dbi . CommonTypeNumber ,
"int" : dbi . CommonTypeInt ,
"tinyint" : dbi . CommonTypeSmallint , // mssql tinyint不支持负数
"money" : dbi . CommonTypeNumber ,
"float" : dbi . CommonTypeNumber , // 近似数字
"real" : dbi . CommonTypeVarchar ,
"date" : dbi . CommonTypeDate , // 日期和时间
"datetimeoffset" : dbi . CommonTypeDatetime ,
"datetime2" : dbi . CommonTypeDatetime ,
"smalldatetime" : dbi . CommonTypeDatetime ,
"datetime" : dbi . CommonTypeDatetime ,
"time" : dbi . CommonTypeTime ,
"char" : dbi . CommonTypeChar , // 字符串
"varchar" : dbi . CommonTypeVarchar ,
"text" : dbi . CommonTypeText ,
"nchar" : dbi . CommonTypeChar ,
"nvarchar" : dbi . CommonTypeVarchar ,
"ntext" : dbi . CommonTypeText ,
"binary" : dbi . CommonTypeBinary ,
"varbinary" : dbi . CommonTypeBinary ,
"cursor" : dbi . CommonTypeVarchar , // 其他
"rowversion" : dbi . CommonTypeVarchar ,
"hierarchyid" : dbi . CommonTypeVarchar ,
"uniqueidentifier" : dbi . CommonTypeVarchar ,
"sql_variant" : dbi . CommonTypeVarchar ,
"xml" : dbi . CommonTypeText ,
"table" : dbi . CommonTypeText ,
"geometry" : dbi . CommonTypeText , // 空间几何类型
"geography" : dbi . CommonTypeText , // 空间地理类型
}
// 公共数据类型 对应 mssql数据类型
2024-03-18 12:25:40 +08:00
mssqlColumnTypeMap = map [ dbi . ColumnDataType ] string {
2024-03-15 09:01:51 +00:00
dbi . CommonTypeVarchar : "nvarchar" ,
dbi . CommonTypeChar : "nchar" ,
dbi . CommonTypeText : "ntext" ,
dbi . CommonTypeBlob : "ntext" ,
dbi . CommonTypeLongblob : "ntext" ,
dbi . CommonTypeLongtext : "ntext" ,
dbi . CommonTypeBinary : "varbinary" ,
dbi . CommonTypeMediumblob : "ntext" ,
dbi . CommonTypeMediumtext : "ntext" ,
dbi . CommonTypeVarbinary : "varbinary" ,
dbi . CommonTypeInt : "int" ,
dbi . CommonTypeSmallint : "smallint" ,
dbi . CommonTypeTinyint : "smallint" ,
dbi . CommonTypeNumber : "decimal" ,
dbi . CommonTypeBigint : "bigint" ,
dbi . CommonTypeDatetime : "datetime2" ,
dbi . CommonTypeDate : "date" ,
dbi . CommonTypeTime : "time" ,
dbi . CommonTypeTimestamp : "timestamp" ,
dbi . CommonTypeEnum : "nvarchar" ,
dbi . CommonTypeJSON : "nvarchar" ,
}
2024-03-15 13:31:53 +08:00
)
type DataConverter struct {
}
func ( dc * DataConverter ) GetDataType ( dbColumnType string ) dbi . DataType {
if numberRegexp . MatchString ( dbColumnType ) {
return dbi . DataTypeNumber
}
// 日期时间类型
if datetimeRegexp . MatchString ( dbColumnType ) {
return dbi . DataTypeDateTime
}
// 日期类型
if dateRegexp . MatchString ( dbColumnType ) {
return dbi . DataTypeDate
}
// 时间类型
if timeRegexp . MatchString ( dbColumnType ) {
return dbi . DataTypeTime
}
return dbi . DataTypeString
}
func ( dc * DataConverter ) FormatData ( dbColumnValue any , dataType dbi . DataType ) string {
2024-03-26 09:05:28 +00:00
// 如果dataType是datetime而dbColumnValue是string类型, 则需要根据类型格式化
str , ok := dbColumnValue . ( string )
if dataType == dbi . DataTypeDateTime && ok {
// 尝试用时间格式解析
res , err := time . Parse ( time . DateTime , str )
if err == nil {
return str
}
res , _ = time . Parse ( time . RFC3339 , str )
return res . Format ( time . DateTime )
}
if dataType == dbi . DataTypeDate && ok {
// 尝试用时间格式解析
res , _ := time . Parse ( time . DateOnly , str )
return res . Format ( time . DateOnly )
}
if dataType == dbi . DataTypeTime && ok {
res , _ := time . Parse ( time . TimeOnly , str )
return res . Format ( time . TimeOnly )
}
2024-03-15 13:31:53 +08:00
return anyx . ToString ( dbColumnValue )
}
func ( dc * DataConverter ) ParseData ( dbColumnValue any , dataType dbi . DataType ) any {
// 如果dataType是datetime而dbColumnValue是string类型, 则需要转换为time.Time类型
_ , ok := dbColumnValue . ( string )
if dataType == dbi . DataTypeDateTime && ok {
res , _ := time . Parse ( time . RFC3339 , anyx . ToString ( dbColumnValue ) )
return res
}
if dataType == dbi . DataTypeDate && ok {
res , _ := time . Parse ( time . DateOnly , anyx . ToString ( dbColumnValue ) )
return res
}
if dataType == dbi . DataTypeTime && ok {
res , _ := time . Parse ( time . TimeOnly , anyx . ToString ( dbColumnValue ) )
return res
}
return dbColumnValue
}
2024-03-26 09:05:28 +00:00
func ( dc * DataConverter ) 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 ( "'%s'" , dc . FormatData ( dbColumnValue , dataType ) )
}
return fmt . Sprintf ( "'%s'" , dbColumnValue )
}