2021-05-08 18:00:33 +08:00
|
|
|
|
package application
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2024-10-20 03:52:23 +00:00
|
|
|
|
"cmp"
|
2023-11-07 21:05:21 +08:00
|
|
|
|
"context"
|
2024-03-26 21:46:03 +08:00
|
|
|
|
"fmt"
|
2024-05-09 21:29:34 +08:00
|
|
|
|
"mayfly-go/internal/db/application/dto"
|
2023-10-27 17:41:45 +08:00
|
|
|
|
"mayfly-go/internal/db/dbm"
|
2024-01-12 13:15:30 +08:00
|
|
|
|
"mayfly-go/internal/db/dbm/dbi"
|
2022-09-09 18:26:08 +08:00
|
|
|
|
"mayfly-go/internal/db/domain/entity"
|
|
|
|
|
|
"mayfly-go/internal/db/domain/repository"
|
2024-11-20 22:43:53 +08:00
|
|
|
|
"mayfly-go/internal/db/imsg"
|
2023-12-05 23:03:51 +08:00
|
|
|
|
tagapp "mayfly-go/internal/tag/application"
|
2024-05-09 21:29:34 +08:00
|
|
|
|
tagdto "mayfly-go/internal/tag/application/dto"
|
2024-04-09 12:55:51 +08:00
|
|
|
|
tagentity "mayfly-go/internal/tag/domain/entity"
|
2023-10-26 17:15:49 +08:00
|
|
|
|
"mayfly-go/pkg/base"
|
2024-03-26 21:46:03 +08:00
|
|
|
|
"mayfly-go/pkg/biz"
|
2023-10-26 17:15:49 +08:00
|
|
|
|
"mayfly-go/pkg/errorx"
|
2022-06-02 17:41:11 +08:00
|
|
|
|
"mayfly-go/pkg/model"
|
2023-07-21 17:07:04 +08:00
|
|
|
|
"mayfly-go/pkg/utils/collx"
|
2024-10-16 17:24:50 +08:00
|
|
|
|
"mayfly-go/pkg/utils/stringx"
|
2024-10-21 22:27:42 +08:00
|
|
|
|
"mayfly-go/pkg/utils/writerx"
|
2024-03-26 21:46:03 +08:00
|
|
|
|
"sort"
|
2021-07-28 18:03:19 +08:00
|
|
|
|
"strings"
|
2024-03-26 21:46:03 +08:00
|
|
|
|
"time"
|
2021-05-08 18:00:33 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
type Db interface {
|
2023-10-26 17:15:49 +08:00
|
|
|
|
base.App[*entity.Db]
|
|
|
|
|
|
|
2022-06-16 15:55:18 +08:00
|
|
|
|
// 分页获取
|
2023-10-26 17:15:49 +08:00
|
|
|
|
GetPageList(condition *entity.DbQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
2021-05-08 18:00:33 +08:00
|
|
|
|
|
2024-04-17 21:28:28 +08:00
|
|
|
|
SaveDb(ctx context.Context, entity *entity.Db) error
|
2021-05-08 18:00:33 +08:00
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
// 删除数据库信息
|
2023-11-07 21:05:21 +08:00
|
|
|
|
Delete(ctx context.Context, id uint64) error
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
|
|
|
|
|
// 获取数据库连接实例
|
2023-10-27 17:41:45 +08:00
|
|
|
|
// @param id 数据库id
|
2023-12-20 17:29:16 +08:00
|
|
|
|
//
|
|
|
|
|
|
// @param dbName 数据库名
|
2024-01-12 13:15:30 +08:00
|
|
|
|
GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error)
|
2023-12-20 17:29:16 +08:00
|
|
|
|
|
|
|
|
|
|
// 根据数据库实例id获取连接,随机返回该instanceId下已连接的conn,若不存在则是使用该instanceId关联的db进行连接并返回。
|
2024-01-12 13:15:30 +08:00
|
|
|
|
GetDbConnByInstanceId(instanceId uint64) (*dbi.DbConn, error)
|
2024-03-26 21:46:03 +08:00
|
|
|
|
|
|
|
|
|
|
// DumpDb dumpDb
|
2024-05-09 21:29:34 +08:00
|
|
|
|
DumpDb(ctx context.Context, reqParam *dto.DumpDb) error
|
2021-05-08 18:00:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
type dbAppImpl struct {
|
2023-10-26 17:15:49 +08:00
|
|
|
|
base.AppImpl[*entity.Db, repository.Db]
|
|
|
|
|
|
|
2024-04-17 21:28:28 +08:00
|
|
|
|
dbSqlRepo repository.DbSql `inject:"DbSqlRepo"`
|
|
|
|
|
|
dbInstanceApp Instance `inject:"DbInstanceApp"`
|
2024-05-05 14:53:30 +08:00
|
|
|
|
dbSqlExecApp DbSqlExec `inject:"DbSqlExecApp"`
|
2024-04-17 21:28:28 +08:00
|
|
|
|
tagApp tagapp.TagTree `inject:"TagTreeApp"`
|
|
|
|
|
|
resourceAuthCertApp tagapp.ResourceAuthCert `inject:"ResourceAuthCertApp"`
|
2024-01-21 22:52:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-09 21:29:34 +08:00
|
|
|
|
var _ (Db) = (*dbAppImpl)(nil)
|
|
|
|
|
|
|
2024-01-21 22:52:20 +08:00
|
|
|
|
// 注入DbRepo
|
|
|
|
|
|
func (d *dbAppImpl) InjectDbRepo(repo repository.Db) {
|
|
|
|
|
|
d.Repo = repo
|
2021-05-08 18:00:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 分页获取数据库信息列表
|
2023-10-26 17:15:49 +08:00
|
|
|
|
func (d *dbAppImpl) GetPageList(condition *entity.DbQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
|
|
|
|
|
return d.GetRepo().GetDbList(condition, pageParam, toEntity, orderBy...)
|
2021-05-08 18:00:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-17 21:28:28 +08:00
|
|
|
|
func (d *dbAppImpl) SaveDb(ctx context.Context, dbEntity *entity.Db) error {
|
2023-09-27 17:19:58 +08:00
|
|
|
|
// 查找是否存在
|
|
|
|
|
|
oldDb := &entity.Db{Name: dbEntity.Name, InstanceId: dbEntity.InstanceId}
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
2024-04-17 21:28:28 +08:00
|
|
|
|
authCert, err := d.resourceAuthCertApp.GetAuthCert(dbEntity.AuthCertName)
|
|
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return errorx.NewBiz("ac not found")
|
2024-04-17 21:28:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-28 23:45:57 +08:00
|
|
|
|
err = d.GetByCond(oldDb)
|
2021-07-28 18:03:19 +08:00
|
|
|
|
if dbEntity.Id == 0 {
|
2023-10-26 17:15:49 +08:00
|
|
|
|
if err == nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return errorx.NewBizI(ctx, imsg.ErrDbNameExist)
|
2023-10-26 17:15:49 +08:00
|
|
|
|
}
|
2024-10-16 17:24:50 +08:00
|
|
|
|
dbEntity.Code = stringx.Rand(10)
|
|
|
|
|
|
|
2023-12-05 23:03:51 +08:00
|
|
|
|
return d.Tx(ctx, func(ctx context.Context) error {
|
|
|
|
|
|
return d.Insert(ctx, dbEntity)
|
|
|
|
|
|
}, func(ctx context.Context) error {
|
2024-04-17 21:28:28 +08:00
|
|
|
|
// 将库关联至指定数据库授权凭证下
|
2024-05-09 21:29:34 +08:00
|
|
|
|
return d.tagApp.RelateTagsByCodeAndType(ctx, &tagdto.RelateTagsByCodeAndType{
|
|
|
|
|
|
Tags: []*tagdto.ResourceTag{{
|
2024-04-17 21:28:28 +08:00
|
|
|
|
Code: dbEntity.Code,
|
|
|
|
|
|
Type: tagentity.TagTypeDbName,
|
|
|
|
|
|
Name: dbEntity.Name,
|
|
|
|
|
|
}},
|
|
|
|
|
|
ParentTagCode: authCert.Name,
|
|
|
|
|
|
ParentTagType: tagentity.TagTypeDbAuthCert,
|
2024-04-06 18:19:17 +08:00
|
|
|
|
})
|
2023-12-05 23:03:51 +08:00
|
|
|
|
})
|
2022-05-08 14:10:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果存在该库,则校验修改的库是否为该库
|
2023-10-26 17:15:49 +08:00
|
|
|
|
if err == nil && oldDb.Id != dbEntity.Id {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return errorx.NewBizI(ctx, imsg.ErrDbNameExist)
|
2022-05-08 14:10:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dbId := dbEntity.Id
|
2024-05-05 14:53:30 +08:00
|
|
|
|
old, err := d.GetById(dbId)
|
2023-10-26 17:15:49 +08:00
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return errorx.NewBiz("db not found")
|
2023-10-26 17:15:49 +08:00
|
|
|
|
}
|
2022-05-08 14:10:57 +08:00
|
|
|
|
|
2023-09-27 17:19:58 +08:00
|
|
|
|
oldDbs := strings.Split(old.Database, " ")
|
|
|
|
|
|
newDbs := strings.Split(dbEntity.Database, " ")
|
2022-05-08 14:10:57 +08:00
|
|
|
|
// 比较新旧数据库列表,需要将移除的数据库相关联的信息删除
|
2024-01-13 13:38:53 +08:00
|
|
|
|
_, delDb, _ := collx.ArrayCompare(newDbs, oldDbs)
|
2023-09-27 17:19:58 +08:00
|
|
|
|
|
2024-01-23 09:27:05 +08:00
|
|
|
|
// 先简单关闭可能存在的旧库连接(可能改了关联标签导致DbConn.Info.TagPath与修改后的标签不一致、导致操作权限校验出错)
|
|
|
|
|
|
for _, v := range oldDbs {
|
2023-09-27 17:19:58 +08:00
|
|
|
|
// 关闭数据库连接
|
2023-10-27 17:41:45 +08:00
|
|
|
|
dbm.CloseDb(dbEntity.Id, v)
|
2024-01-23 09:27:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, v := range delDb {
|
2022-05-08 14:10:57 +08:00
|
|
|
|
// 删除该库关联的所有sql记录
|
2024-01-23 19:30:28 +08:00
|
|
|
|
d.dbSqlRepo.DeleteByCond(ctx, &entity.DbSql{DbId: dbId, Db: v})
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
2022-05-08 14:10:57 +08:00
|
|
|
|
|
2024-04-06 18:19:17 +08:00
|
|
|
|
// 防止误传修改
|
|
|
|
|
|
dbEntity.Code = ""
|
2023-12-05 23:03:51 +08:00
|
|
|
|
return d.Tx(ctx, func(ctx context.Context) error {
|
|
|
|
|
|
return d.UpdateById(ctx, dbEntity)
|
|
|
|
|
|
}, func(ctx context.Context) error {
|
2024-04-17 21:28:28 +08:00
|
|
|
|
if old.Name != dbEntity.Name {
|
|
|
|
|
|
if err := d.tagApp.UpdateTagName(ctx, tagentity.TagTypeDbName, old.Code, dbEntity.Name); err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if authCert.Name != old.AuthCertName {
|
2024-04-18 20:50:14 +08:00
|
|
|
|
return d.tagApp.ChangeParentTag(ctx, tagentity.TagTypeDbName, old.Code, tagentity.TagTypeDbAuthCert, authCert.Name)
|
2024-04-17 21:28:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil
|
2023-12-05 23:03:51 +08:00
|
|
|
|
})
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-07 21:05:21 +08:00
|
|
|
|
func (d *dbAppImpl) Delete(ctx context.Context, id uint64) error {
|
2024-05-05 14:53:30 +08:00
|
|
|
|
db, err := d.GetById(id)
|
2023-10-26 17:15:49 +08:00
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return errorx.NewBiz("db not found")
|
2023-10-26 17:15:49 +08:00
|
|
|
|
}
|
2022-05-08 14:10:57 +08:00
|
|
|
|
dbs := strings.Split(db.Database, " ")
|
|
|
|
|
|
for _, v := range dbs {
|
|
|
|
|
|
// 关闭连接
|
2023-10-27 17:41:45 +08:00
|
|
|
|
dbm.CloseDb(id, v)
|
2022-05-08 14:10:57 +08:00
|
|
|
|
}
|
2023-12-13 14:01:13 +08:00
|
|
|
|
|
|
|
|
|
|
return d.Tx(ctx,
|
|
|
|
|
|
func(ctx context.Context) error {
|
|
|
|
|
|
return d.DeleteById(ctx, id)
|
|
|
|
|
|
},
|
|
|
|
|
|
func(ctx context.Context) error {
|
|
|
|
|
|
// 删除该库下用户保存的所有sql信息
|
2024-01-23 19:30:28 +08:00
|
|
|
|
return d.dbSqlRepo.DeleteByCond(ctx, &entity.DbSql{DbId: id})
|
2024-05-05 14:53:30 +08:00
|
|
|
|
}, func(ctx context.Context) error {
|
|
|
|
|
|
return d.dbSqlExecApp.DeleteBy(ctx, &entity.DbSqlExec{DbId: id})
|
2023-12-13 14:01:13 +08:00
|
|
|
|
}, func(ctx context.Context) error {
|
2024-05-09 21:29:34 +08:00
|
|
|
|
return d.tagApp.DeleteTagByParam(ctx, &tagdto.DelResourceTag{
|
2024-04-17 21:28:28 +08:00
|
|
|
|
ResourceCode: db.Code,
|
|
|
|
|
|
ResourceType: tagentity.TagTypeDbName,
|
2024-04-06 18:19:17 +08:00
|
|
|
|
})
|
2023-12-13 14:01:13 +08:00
|
|
|
|
})
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-12 13:15:30 +08:00
|
|
|
|
func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error) {
|
|
|
|
|
|
return dbm.GetDbConn(dbId, dbName, func() (*dbi.DbInfo, error) {
|
2024-05-05 14:53:30 +08:00
|
|
|
|
db, err := d.GetById(dbId)
|
2023-10-27 17:41:45 +08:00
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return nil, errorx.NewBiz("db not found")
|
2021-07-28 18:03:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-05 14:53:30 +08:00
|
|
|
|
instance, err := d.dbInstanceApp.GetById(db.InstanceId)
|
2023-10-27 17:41:45 +08:00
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return nil, errorx.NewBiz("db instance not found")
|
2022-07-23 16:41:04 +08:00
|
|
|
|
}
|
2023-11-12 20:14:44 +08:00
|
|
|
|
|
2024-04-12 13:24:20 +08:00
|
|
|
|
di, err := d.dbInstanceApp.ToDbInfo(instance, db.AuthCertName, dbName)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
2024-01-05 08:55:34 +08:00
|
|
|
|
}
|
2024-05-08 21:04:25 +08:00
|
|
|
|
di.CodePath = d.tagApp.ListTagPathByTypeAndCode(int8(tagentity.TagTypeDbName), db.Code)
|
2024-04-12 13:24:20 +08:00
|
|
|
|
di.Id = db.Id
|
|
|
|
|
|
|
2024-03-15 13:31:53 +08:00
|
|
|
|
checkDb := di.GetDatabase()
|
2024-05-16 17:26:32 +08:00
|
|
|
|
if db.GetDatabaseMode == entity.DbGetDatabaseModeAssign && !strings.Contains(" "+db.Database+" ", " "+checkDb+" ") {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return nil, errorx.NewBizI(context.Background(), imsg.ErrDbNotAccess, "dbName", dbName)
|
2024-03-15 13:31:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-02-29 22:12:50 +08:00
|
|
|
|
return di, nil
|
2022-07-23 16:41:04 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-12 13:15:30 +08:00
|
|
|
|
func (d *dbAppImpl) GetDbConnByInstanceId(instanceId uint64) (*dbi.DbConn, error) {
|
2023-12-20 17:29:16 +08:00
|
|
|
|
conn := dbm.GetDbConnByInstanceId(instanceId)
|
|
|
|
|
|
if conn != nil {
|
|
|
|
|
|
return conn, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-05 14:53:30 +08:00
|
|
|
|
dbs, err := d.ListByCond(&entity.Db{InstanceId: instanceId}, "id", "database")
|
|
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return nil, errorx.NewBiz("failed to get database list")
|
2024-01-05 17:23:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
if len(dbs) == 0 {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
return nil, errorx.NewBiz("DB instance [%d] Database is not configured, please configure it first", instanceId)
|
2023-12-20 17:29:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用该实例关联的已配置数据库中的第一个库进行连接并返回
|
|
|
|
|
|
firstDb := dbs[0]
|
|
|
|
|
|
return d.GetDbConn(firstDb.Id, strings.Split(firstDb.Database, " ")[0])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-09 21:29:34 +08:00
|
|
|
|
func (d *dbAppImpl) DumpDb(ctx context.Context, reqParam *dto.DumpDb) error {
|
2024-10-20 03:52:23 +00:00
|
|
|
|
log := dto.DefaultDumpLog
|
|
|
|
|
|
if reqParam.Log != nil {
|
|
|
|
|
|
log = reqParam.Log
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-21 22:27:42 +08:00
|
|
|
|
writer := writerx.NewStringWriter(reqParam.Writer)
|
2024-03-26 21:46:03 +08:00
|
|
|
|
defer writer.Close()
|
|
|
|
|
|
dbId := reqParam.DbId
|
|
|
|
|
|
dbName := reqParam.DbName
|
|
|
|
|
|
tables := reqParam.Tables
|
|
|
|
|
|
|
|
|
|
|
|
dbConn, err := d.GetDbConn(dbId, dbName)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2024-10-21 22:27:42 +08:00
|
|
|
|
|
2024-03-26 21:46:03 +08:00
|
|
|
|
writer.WriteString("\n-- ----------------------------")
|
2024-11-20 22:43:53 +08:00
|
|
|
|
writer.WriteString("\n-- Dump Platform: mayfly-go")
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- Dump Time: %s ", time.Now().Format("2006-01-02 15:04:05")))
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- Dump DB: %s ", dbName))
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- DB Dialect: %s ", cmp.Or(reqParam.TargetDbType, dbConn.Info.Type)))
|
2024-03-26 21:46:03 +08:00
|
|
|
|
writer.WriteString("\n-- ----------------------------\n\n")
|
|
|
|
|
|
|
2024-10-20 03:52:23 +00:00
|
|
|
|
// 获取目标元数据,仅生成sql,用于生成建表语句和插入数据,不能用于查询
|
2024-11-01 17:27:22 +08:00
|
|
|
|
targetDialect := dbConn.GetDialect()
|
2024-10-20 03:52:23 +00:00
|
|
|
|
if reqParam.TargetDbType != "" && dbConn.Info.Type != reqParam.TargetDbType {
|
|
|
|
|
|
// 创建一个假连接,仅用于调用方言生成sql,不做数据库连接操作
|
|
|
|
|
|
meta := dbi.GetMeta(reqParam.TargetDbType)
|
|
|
|
|
|
dbConn := &dbi.DbConn{Info: &dbi.DbInfo{
|
|
|
|
|
|
Type: reqParam.TargetDbType,
|
|
|
|
|
|
Meta: meta,
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
2024-11-01 17:27:22 +08:00
|
|
|
|
targetDialect = meta.GetDialect(dbConn)
|
2024-10-20 03:52:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-01 17:27:22 +08:00
|
|
|
|
srcMeta := dbConn.GetMetadata()
|
|
|
|
|
|
srcDialect := dbConn.GetDialect()
|
2024-03-26 21:46:03 +08:00
|
|
|
|
if len(tables) == 0 {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log("Gets the table information that can be export...")
|
2024-10-20 03:52:23 +00:00
|
|
|
|
ti, err := srcMeta.GetTables()
|
|
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Failed to get table info %s", err.Error()))
|
2024-10-20 03:52:23 +00:00
|
|
|
|
}
|
2024-03-26 21:46:03 +08:00
|
|
|
|
biz.ErrIsNil(err)
|
|
|
|
|
|
tables = make([]string, len(ti))
|
|
|
|
|
|
for i, table := range ti {
|
|
|
|
|
|
tables[i] = table.TableName
|
|
|
|
|
|
}
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Get %d tables", len(tables)))
|
2024-03-26 21:46:03 +08:00
|
|
|
|
}
|
2024-03-29 21:40:26 +08:00
|
|
|
|
if len(tables) == 0 {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log("No table to export. End export")
|
|
|
|
|
|
return errorx.NewBiz("there is no table to export")
|
2024-03-29 21:40:26 +08:00
|
|
|
|
}
|
2024-03-26 21:46:03 +08:00
|
|
|
|
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log("Querying column information...")
|
2024-03-26 21:46:03 +08:00
|
|
|
|
// 查询列信息,后面生成建表ddl和insert都需要列信息
|
2024-10-20 03:52:23 +00:00
|
|
|
|
columns, err := srcMeta.GetColumns(tables...)
|
|
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Failed to query column information: %s", err.Error()))
|
2024-10-20 03:52:23 +00:00
|
|
|
|
}
|
2024-03-26 21:46:03 +08:00
|
|
|
|
biz.ErrIsNil(err)
|
|
|
|
|
|
|
|
|
|
|
|
// 以表名分组,存放每个表的列信息
|
|
|
|
|
|
columnMap := make(map[string][]dbi.Column)
|
|
|
|
|
|
for _, column := range columns {
|
|
|
|
|
|
columnMap[column.TableName] = append(columnMap[column.TableName], column)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 按表名排序
|
|
|
|
|
|
sort.Strings(tables)
|
|
|
|
|
|
|
2024-11-01 17:27:22 +08:00
|
|
|
|
quoteSchema := srcDialect.QuoteIdentifier(dbConn.Info.CurrentSchema())
|
|
|
|
|
|
dumpHelper := targetDialect.GetDumpHelper()
|
|
|
|
|
|
dataHelper := targetDialect.GetDataHelper()
|
2024-03-26 21:46:03 +08:00
|
|
|
|
|
|
|
|
|
|
// 遍历获取每个表的信息
|
|
|
|
|
|
for _, tableName := range tables {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Get table [%s] information...", tableName))
|
2024-11-01 17:27:22 +08:00
|
|
|
|
quoteTableName := targetDialect.QuoteIdentifier(tableName)
|
2024-03-26 21:46:03 +08:00
|
|
|
|
|
|
|
|
|
|
// 查询表信息,主要是为了查询表注释
|
2024-10-20 03:52:23 +00:00
|
|
|
|
tbs, err := srcMeta.GetTables(tableName)
|
2024-04-17 21:28:28 +08:00
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Failed to get table [%s] information: %s", tableName, err.Error()))
|
2024-04-17 21:28:28 +08:00
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(tbs) <= 0 {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Failed to get table [%s] information: No table information was retrieved", tableName))
|
|
|
|
|
|
return errorx.NewBiz(fmt.Sprintf("Failed to get table information: %s", tableName))
|
2024-03-26 21:46:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
tabInfo := dbi.Table{
|
|
|
|
|
|
TableName: tableName,
|
|
|
|
|
|
TableComment: tbs[0].TableComment,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成表结构信息
|
|
|
|
|
|
if reqParam.DumpDDL {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Generate table [%s] DDL...", tableName))
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- Table structure: %s \n-- ----------------------------\n", tableName))
|
2024-11-01 17:27:22 +08:00
|
|
|
|
tbDdlArr := targetDialect.GenerateTableDDL(columnMap[tableName], tabInfo, true)
|
2024-03-26 21:46:03 +08:00
|
|
|
|
for _, ddl := range tbDdlArr {
|
|
|
|
|
|
writer.WriteString(ddl + ";\n")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成insert sql,数据在索引前,加速insert
|
|
|
|
|
|
if reqParam.DumpData {
|
2024-11-21 13:20:45 +08:00
|
|
|
|
log(fmt.Sprintf("Generate table [%s] DML...", tableName))
|
2024-11-20 22:43:53 +08:00
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- Data: %s \n-- ----------------------------\n", tableName))
|
2024-03-26 21:46:03 +08:00
|
|
|
|
|
|
|
|
|
|
dumpHelper.BeforeInsert(writer, quoteTableName)
|
|
|
|
|
|
// 获取列信息
|
|
|
|
|
|
quoteColNames := make([]string, 0)
|
|
|
|
|
|
for _, col := range columnMap[tableName] {
|
2024-11-01 17:27:22 +08:00
|
|
|
|
quoteColNames = append(quoteColNames, targetDialect.QuoteIdentifier(col.ColumnName))
|
2024-03-26 21:46:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-20 03:52:23 +00:00
|
|
|
|
_, _ = dbConn.WalkTableRows(ctx, tableName, func(row map[string]any, _ []*dbi.QueryColumn) error {
|
2024-03-26 21:46:03 +08:00
|
|
|
|
rowValues := make([]string, len(columnMap[tableName]))
|
|
|
|
|
|
for i, col := range columnMap[tableName] {
|
|
|
|
|
|
rowValues[i] = dataHelper.WrapValue(row[col.ColumnName], dataHelper.GetDataType(string(col.DataType)))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
beforeInsert := dumpHelper.BeforeInsertSql(quoteSchema, quoteTableName)
|
|
|
|
|
|
insertSQL := fmt.Sprintf("%s INSERT INTO %s (%s) values(%s)", beforeInsert, quoteTableName, strings.Join(quoteColNames, ", "), strings.Join(rowValues, ", "))
|
|
|
|
|
|
writer.WriteString(insertSQL + ";\n")
|
|
|
|
|
|
return nil
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
dumpHelper.AfterInsert(writer, tableName, columnMap[tableName])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Get table [%s] index information...", tableName))
|
2024-10-20 03:52:23 +00:00
|
|
|
|
indexs, err := srcMeta.GetTableIndex(tableName)
|
2024-04-17 21:28:28 +08:00
|
|
|
|
if err != nil {
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Failed to get table [%s] index information: %s", tableName, err.Error()))
|
2024-04-17 21:28:28 +08:00
|
|
|
|
return err
|
|
|
|
|
|
}
|
2024-03-26 21:46:03 +08:00
|
|
|
|
|
2024-03-27 08:22:26 +08:00
|
|
|
|
if len(indexs) > 0 {
|
2024-03-26 21:46:03 +08:00
|
|
|
|
// 最后添加索引
|
2024-11-20 22:43:53 +08:00
|
|
|
|
log(fmt.Sprintf("Generate table [%s] index...", tableName))
|
|
|
|
|
|
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- Table Index: %s \n-- ----------------------------\n", tableName))
|
2024-11-01 17:27:22 +08:00
|
|
|
|
sqlArr := targetDialect.GenerateIndexDDL(indexs, tabInfo)
|
2024-03-26 21:46:03 +08:00
|
|
|
|
for _, sqlStr := range sqlArr {
|
|
|
|
|
|
writer.WriteString(sqlStr + ";\n")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|