mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	feature: 执行 SQL 脚本时显示执行进度
This commit is contained in:
		@@ -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(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
export const buildProgressProps = (): any => {
 | 
					export const buildProgressProps = (): any => {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        progress: {
 | 
					        progress: {
 | 
				
			||||||
            sqlFileName: {
 | 
					            title: {
 | 
				
			||||||
                type: String,
 | 
					                type: String,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            executedStatements: {
 | 
					            executedStatements: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user