You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
6.3 KiB
234 lines
6.3 KiB
package vService
|
|
|
|
import (
|
|
"context"
|
|
_ "dm" // 达梦数据库驱动
|
|
"fmt"
|
|
"github.com/jmoiron/sqlx"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
// DMDBService 数据库服务实现
|
|
type DMDBService struct {
|
|
db *sqlx.DB
|
|
}
|
|
|
|
func NewDMDBService(dsn string) (*DMDBService, error) {
|
|
db, err := sqlx.Connect("dm", dsn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &DMDBService{db: db}, nil
|
|
}
|
|
|
|
func (s *DMDBService) Close() error {
|
|
return s.db.Close()
|
|
}
|
|
|
|
func (s *DMDBService) FetchData(ctx context.Context, dbName, tableName string, limit int) ([]map[string]interface{}, error) {
|
|
query := fmt.Sprintf("SELECT * FROM %s.%s WHERE ROWNUM <= %d", dbName, tableName, limit)
|
|
|
|
results, err := s.QueryBySQL(ctx, dbName, query, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 转换为map格式以保持兼容性
|
|
var mapResults []map[string]interface{}
|
|
if len(results) > 0 {
|
|
columns := results[0]
|
|
for _, row := range results[1:] {
|
|
rowMap := make(map[string]interface{})
|
|
for i, col := range columns {
|
|
if i < len(row) {
|
|
rowMap[col] = row[i]
|
|
}
|
|
}
|
|
mapResults = append(mapResults, rowMap)
|
|
}
|
|
}
|
|
return mapResults, nil
|
|
}
|
|
|
|
func (s *DMDBService) QueryBySQL(ctx context.Context, dbName string, sql string, limit int) ([][]string, error) {
|
|
// 添加LIMIT子句如果SQL中没有
|
|
if !strings.Contains(strings.ToUpper(sql), "LIMIT") && !strings.Contains(strings.ToUpper(sql), "ROWNUM") {
|
|
sql = fmt.Sprintf("SELECT * FROM (%s) WHERE ROWNUM <= %d", sql, limit)
|
|
}
|
|
|
|
rows, err := s.db.QueryxContext(ctx, sql)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
// 获取列名
|
|
columns, err := rows.Columns()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var results [][]string
|
|
// 添加列名作为第一行
|
|
results = append(results, columns)
|
|
|
|
// 处理数据行
|
|
for rows.Next() {
|
|
// 创建动态接收器
|
|
values := make([]interface{}, len(columns))
|
|
for i := range values {
|
|
var v interface{}
|
|
values[i] = &v
|
|
}
|
|
|
|
if err := rows.Scan(values...); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 转换为字符串数组
|
|
row := make([]string, len(columns))
|
|
for i, val := range values {
|
|
if val == nil {
|
|
row[i] = "NULL"
|
|
} else {
|
|
row[i] = fmt.Sprintf("%v", *val.(*interface{}))
|
|
}
|
|
}
|
|
results = append(results, row)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
func (s *DMDBService) AddColumn(ctx context.Context, dbName, tableName, columnName, columnType string) error {
|
|
query := fmt.Sprintf("ALTER TABLE %s.%s ADD %s %s", dbName, tableName, columnName, columnType)
|
|
if _, err := s.db.ExecContext(ctx, query); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *DMDBService) AddComment(ctx context.Context, dbName, tableName, columnName, comment string) error {
|
|
if comment != "" {
|
|
commentQuery := fmt.Sprintf("COMMENT ON COLUMN %s.%s.%s IS '%s'",
|
|
dbName, tableName, columnName, strings.ReplaceAll(comment, "'", "''"))
|
|
if _, err := s.db.ExecContext(ctx, commentQuery); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *DMDBService) DropColumn(ctx context.Context, dbName, tableName, columnName string) error {
|
|
query := fmt.Sprintf("ALTER TABLE %s.%s DROP COLUMN %s", dbName, tableName, columnName)
|
|
_, err := s.db.ExecContext(ctx, query)
|
|
return err
|
|
}
|
|
|
|
// ColumnInfo 表字段信息(用于表结构查询)
|
|
type ColumnInfo struct {
|
|
ColumnName string `db:"COLUMN_NAME"`
|
|
DataType string `db:"DATA_TYPE"`
|
|
DataLength *int `db:"DATA_LENGTH"`
|
|
Nullable string `db:"NULLABLE"`
|
|
DataDefault *string `db:"DATA_DEFAULT"`
|
|
ColumnComment string `db:"COMMENTS"`
|
|
}
|
|
|
|
// TableStructure 查询表结构(字段名、类型、长度、可空、默认值等)
|
|
func (s *DMDBService) TableStructure(ctx context.Context, dbName, tableName string) ([]ColumnInfo, error) {
|
|
// 达梦 ALL_TAB_COLUMNS / USER_TAB_COLUMNS;部分版本有注释在 ALL_COL_COMMENTS
|
|
query := `SELECT c.COLUMN_NAME, c.DATA_TYPE, c.DATA_LENGTH, c.NULLABLE, c.DATA_DEFAULT, com.COMMENTS
|
|
FROM ALL_TAB_COLUMNS c
|
|
LEFT JOIN ALL_COL_COMMENTS com ON c.OWNER = com.OWNER AND c.TABLE_NAME = com.TABLE_NAME AND c.COLUMN_NAME = com.COLUMN_NAME
|
|
WHERE c.OWNER = ? AND c.TABLE_NAME = ?
|
|
ORDER BY c.COLUMN_ID`
|
|
rows, err := s.db.QueryxContext(ctx, query, strings.ToUpper(dbName), strings.ToUpper(tableName))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var list []ColumnInfo
|
|
for rows.Next() {
|
|
var c ColumnInfo
|
|
if err := rows.StructScan(&c); err != nil {
|
|
return nil, err
|
|
}
|
|
list = append(list, c)
|
|
}
|
|
return list, nil
|
|
}
|
|
|
|
// ExecSQL 执行非查询 SQL(INSERT/UPDATE/DELETE),返回影响行数;args 为参数化占位符对应的值
|
|
func (s *DMDBService) ExecSQL(ctx context.Context, sql string, args ...interface{}) (int64, error) {
|
|
var err error
|
|
var affected int64
|
|
if len(args) > 0 {
|
|
res, e := s.db.ExecContext(ctx, sql, args...)
|
|
err = e
|
|
if e == nil {
|
|
affected, _ = res.RowsAffected()
|
|
}
|
|
} else {
|
|
res, e := s.db.ExecContext(ctx, sql)
|
|
err = e
|
|
if e == nil {
|
|
affected, _ = res.RowsAffected()
|
|
}
|
|
}
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return affected, nil
|
|
}
|
|
|
|
// CreateTable 创建表(columnDefs 如 "id INT PRIMARY KEY, name VARCHAR(100)")
|
|
func (s *DMDBService) CreateTable(ctx context.Context, dbName, tableName, columnDefs string) error {
|
|
query := fmt.Sprintf("CREATE TABLE %s.%s (%s)", dbName, tableName, columnDefs)
|
|
_, err := s.db.ExecContext(ctx, query)
|
|
return err
|
|
}
|
|
|
|
// DropTable 删除表
|
|
func (s *DMDBService) DropTable(ctx context.Context, dbName, tableName string) error {
|
|
query := fmt.Sprintf("DROP TABLE %s.%s", dbName, tableName)
|
|
_, err := s.db.ExecContext(ctx, query)
|
|
return err
|
|
}
|
|
|
|
func (s *DMDBService) AllTable(ctx context.Context, dbName string) (interface{}, error) {
|
|
query := fmt.Sprintf("SELECT TABLE_NAME FROM ALL_TABLES WHERE OWNER = '%s'", dbName)
|
|
rows, err := s.db.QueryxContext(ctx, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func(rows *sqlx.Rows) {
|
|
err := rows.Close()
|
|
if err != nil {
|
|
log.Fatalf("发生异常: %v", err)
|
|
}
|
|
}(rows)
|
|
|
|
results, err := s.QueryBySQL(ctx, dbName, query, 1000) // 默认限制1000条表名
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 转换为map格式以保持兼容性
|
|
var mapResults []map[string]interface{}
|
|
if len(results) > 0 {
|
|
columns := results[0]
|
|
for _, row := range results[1:] {
|
|
rowMap := make(map[string]interface{})
|
|
for i, col := range columns {
|
|
if i < len(row) {
|
|
rowMap[col] = row[i]
|
|
}
|
|
}
|
|
mapResults = append(mapResults, rowMap)
|
|
}
|
|
}
|
|
return mapResults, nil
|
|
}
|
|
|