feature: 执行 SQL 脚本时显示执行进度

This commit is contained in:
kanzihuang
2023-10-15 10:36:01 +08:00
committed by wanli
parent a64b894b08
commit 361eafedae
5 changed files with 36 additions and 17 deletions

View File

@@ -45,7 +45,7 @@ export default {
notification: undefined, notification: undefined,
} }
} }
progress.props.progress.sqlFileName = content.sqlFileName progress.props.progress.title = content.title
progress.props.progress.executedStatements = content.executedStatements progress.props.progress.executedStatements = content.executedStatements
if (!notifyMap.has(id)) { if (!notifyMap.has(id)) {
const vNodeMessage = createVNode( const vNodeMessage = createVNode(

View File

@@ -1,7 +1,7 @@
export const buildProgressProps = (): any => { export const buildProgressProps = (): any => {
return { return {
progress: { progress: {
sqlFileName: { title: {
type: String, type: String,
}, },
executedStatements: { executedStatements: {

View File

@@ -1,5 +1,5 @@
<template> <template>
<el-descriptions border size="small" :title="`${progress.sqlFileName}`"> <el-descriptions border size="small" :title="`${progress.title}`">
<el-descriptions-item label="时间">{{ state.elapsedTime }}</el-descriptions-item> <el-descriptions-item label="时间">{{ state.elapsedTime }}</el-descriptions-item>
<el-descriptions-item label="已处理">{{ progress.executedStatements }}</el-descriptions-item> <el-descriptions-item label="已处理">{{ progress.executedStatements }}</el-descriptions-item>
</el-descriptions> </el-descriptions>

View File

@@ -125,7 +125,30 @@ func (d *Db) ExecSql(rc *req.Ctx) {
biz.ErrIsNil(err, "SQL解析错误,请检查您的执行SQL") biz.ErrIsNil(err, "SQL解析错误,请检查您的执行SQL")
isMulti := len(sqls) > 1 isMulti := len(sqls) > 1
var execResAll *application.DbSqlExecRes var execResAll *application.DbSqlExecRes
progressId := uniqueid.IncrementID()
executedStatements := 0
progressTitle := fmt.Sprintf("%s/%s", dbConn.Info.Name, dbConn.Info.Database)
defer ws.SendJsonMsg(rc.LoginAccount.Id, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
Id: progressId,
Title: progressTitle,
ExecutedStatements: executedStatements,
Terminated: true,
}).WithCategory(progressCategory))
ticker := time.NewTicker(time.Second * 1)
defer ticker.Stop()
for _, s := range sqls { for _, s := range sqls {
select {
case <-ticker.C:
ws.SendJsonMsg(rc.LoginAccount.Id, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
Id: progressId,
Title: progressTitle,
ExecutedStatements: executedStatements,
Terminated: false,
}).WithCategory(progressCategory))
default:
}
executedStatements++
s = stringx.TrimSpaceAndBr(s) s = stringx.TrimSpaceAndBr(s)
// 多条执行,如果有查询语句,则跳过 // 多条执行,如果有查询语句,则跳过
if isMulti && strings.HasPrefix(strings.ToLower(s), "select") { if isMulti && strings.HasPrefix(strings.ToLower(s), "select") {
@@ -156,7 +179,7 @@ const progressCategory = "execSqlFileProgress"
// progressMsg sql文件执行进度消息 // progressMsg sql文件执行进度消息
type progressMsg struct { type progressMsg struct {
Id uint64 `json:"id"` Id uint64 `json:"id"`
SqlFileName string `json:"sqlFileName"` Title string `json:"title"`
ExecutedStatements int `json:"executedStatements"` ExecutedStatements int `json:"executedStatements"`
Terminated bool `json:"terminated"` Terminated bool `json:"terminated"`
} }
@@ -198,17 +221,17 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
LoginAccount: rc.LoginAccount, LoginAccount: rc.LoginAccount,
} }
var sql string
tokenizer := sqlparser.NewReaderTokenizer(file, sqlparser.WithCacheInBuffer())
progressId := uniqueid.IncrementID() progressId := uniqueid.IncrementID()
executedStatements := 0 executedStatements := 0
defer ws.SendJsonMsg(rc.LoginAccount.Id, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{ defer ws.SendJsonMsg(rc.LoginAccount.Id, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
Id: progressId, Id: progressId,
SqlFileName: filename, Title: filename,
ExecutedStatements: executedStatements, ExecutedStatements: executedStatements,
Terminated: true, Terminated: true,
}).WithCategory(progressCategory)) }).WithCategory(progressCategory))
var sql string
tokenizer := sqlparser.NewReaderTokenizer(file, sqlparser.WithCacheInBuffer())
ticker := time.NewTicker(time.Second * 1) ticker := time.NewTicker(time.Second * 1)
defer ticker.Stop() defer ticker.Stop()
for { for {
@@ -216,12 +239,13 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
case <-ticker.C: case <-ticker.C:
ws.SendJsonMsg(rc.LoginAccount.Id, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{ ws.SendJsonMsg(rc.LoginAccount.Id, msgdto.InfoSysMsg("sql脚本执行进度", &progressMsg{
Id: progressId, Id: progressId,
SqlFileName: filename, Title: filename,
ExecutedStatements: executedStatements, ExecutedStatements: executedStatements,
Terminated: false, Terminated: false,
}).WithCategory(progressCategory)) }).WithCategory(progressCategory))
default: default:
} }
executedStatements++
sql, err = sqlparser.SplitNext(tokenizer) sql, err = sqlparser.SplitNext(tokenizer)
if err == io.EOF { if err == io.EOF {
break break
@@ -259,7 +283,6 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
d.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.ErrSysMsg("sql脚本执行失败", fmt.Sprintf("[%s][%s] -> sql=[%s] 执行失败: [%s]", filename, dbConn.Info.GetLogDesc(), sql, err.Error()))) d.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.ErrSysMsg("sql脚本执行失败", fmt.Sprintf("[%s][%s] -> sql=[%s] 执行失败: [%s]", filename, dbConn.Info.GetLogDesc(), sql, err.Error())))
return return
} }
executedStatements++
} }
d.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.SuccessSysMsg("sql脚本执行成功", fmt.Sprintf("sql脚本执行完成%s", rc.ReqParam))) d.MsgApp.CreateAndSend(rc.LoginAccount, msgdto.SuccessSysMsg("sql脚本执行成功", fmt.Sprintf("sql脚本执行完成%s", rc.ReqParam)))
} }

View File

@@ -1,14 +1,12 @@
package entity package entity
import ( import (
"testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"testing"
) )
func Test_escapeSql(t *testing.T) { func Test_QuoteLiteral(t *testing.T) {
tests := []struct { tests := []struct {
name string
dbType DbType dbType DbType
sql string sql string
want string want string
@@ -24,7 +22,6 @@ func Test_escapeSql(t *testing.T) {
want: "'''a'''", want: "'''a'''",
}, },
{ {
name: "不间断空格",
dbType: DbTypeMysql, dbType: DbTypeMysql,
sql: "a\u00A0b", sql: "a\u00A0b",
want: "'a\u00A0b'", want: "'a\u00A0b'",
@@ -40,14 +37,13 @@ func Test_escapeSql(t *testing.T) {
want: "'''a'''", want: "'''a'''",
}, },
{ {
name: "不间断空格",
dbType: DbTypePostgres, dbType: DbTypePostgres,
sql: "a\u00A0b", sql: "a\u00A0b",
want: "'a\u00A0b'", want: "'a\u00A0b'",
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(string(tt.dbType)+"_"+tt.sql, func(t *testing.T) {
got := tt.dbType.QuoteLiteral(tt.sql) got := tt.dbType.QuoteLiteral(tt.sql)
require.Equal(t, tt.want, got) require.Equal(t, tt.want, got)
}) })