mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
fix: sql切割转义等问题处理
This commit is contained in:
@@ -844,11 +844,20 @@ const onDeleteTable = async (data: any) => {
|
||||
let dialect = getDbDialect(state.nowDbInst.type);
|
||||
let schemaStr = schema ? `${dialect.quoteIdentifier(schema)}.` : '';
|
||||
|
||||
dbApi.sqlExec.request({ id, db, sql: `drop table ${schemaStr + dialect.quoteIdentifier(tableName)}` }).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
setTimeout(() => {
|
||||
parentKey && reloadNode(parentKey);
|
||||
}, 1000);
|
||||
dbApi.sqlExec.request({ id, db, sql: `drop table ${schemaStr + dialect.quoteIdentifier(tableName)}` }).then((res) => {
|
||||
let success = true;
|
||||
for (let re of res) {
|
||||
if (re.errorMsg) {
|
||||
success = false;
|
||||
ElMessage.error(`${re.sql} -> 执行失败: ${re.errorMsg}`);
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
ElMessage.success('删除成功');
|
||||
setTimeout(() => {
|
||||
parentKey && reloadNode(parentKey);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -309,18 +309,6 @@ const onRunSql = async (newTab = false) => {
|
||||
sqlPrefix.startsWith('drop') ||
|
||||
sqlPrefix.startsWith('create');
|
||||
|
||||
// 启用工单审批
|
||||
// if (nonQuery && getNowDbInst().flowProcdef) {
|
||||
// try {
|
||||
// getNowDbInst().promptExeSql(props.dbName, sql, null, () => {
|
||||
// ElMessage.success('工单提交成功');
|
||||
// });
|
||||
// } catch (e) {
|
||||
// ElMessage.success('工单提交失败');
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (sqls.length == 1) {
|
||||
let execRemark;
|
||||
if (nonQuery) {
|
||||
@@ -432,28 +420,61 @@ const runSql = async (sql: string, remark = '', newTab = false) => {
|
||||
};
|
||||
|
||||
function splitSql(sql: string) {
|
||||
// 移除注释
|
||||
sql = sql.replace(/\/\*[\s\S]*?\*\//g, '');
|
||||
let state = 'normal';
|
||||
let buffer = '';
|
||||
let result = [];
|
||||
let inString = null; // 用于记录当前字符串的引号类型(' 或 ")
|
||||
|
||||
// 分割SQL语句
|
||||
const statements = sql.split(/;\s*|\/\*[\s\S]*?\*\//g);
|
||||
for (let i = 0; i < sql.length; i++) {
|
||||
const char = sql[i];
|
||||
const nextChar = sql[i + 1];
|
||||
|
||||
// 移除空语句
|
||||
const filteredStatements = statements.filter((statement) => statement.trim() !== '');
|
||||
|
||||
// 处理包含分号的SQL语句
|
||||
const processedStatements = filteredStatements.map((statement) => {
|
||||
const parts = statement.split(/[\s]+/);
|
||||
const newParts = parts.map((part) => {
|
||||
if (part.includes('(') && part.includes(')')) {
|
||||
return part.replace(/\(/g, '[').replace(/\)/g, ']');
|
||||
if (state === 'normal') {
|
||||
if (char === '-' && nextChar === '-') {
|
||||
state = 'singleLineComment';
|
||||
i++; // 跳过下一个字符
|
||||
} else if (char === '/' && nextChar === '*') {
|
||||
state = 'multiLineComment';
|
||||
i++; // 跳过下一个字符
|
||||
} else if (char === "'" || char === '"') {
|
||||
state = 'string';
|
||||
inString = char;
|
||||
buffer += char;
|
||||
} else if (char === ';') {
|
||||
if (buffer.trim()) {
|
||||
result.push(buffer.trim());
|
||||
}
|
||||
buffer = '';
|
||||
} else {
|
||||
buffer += char;
|
||||
}
|
||||
return part;
|
||||
});
|
||||
return newParts.join(' ');
|
||||
});
|
||||
} else if (state === 'string') {
|
||||
buffer += char;
|
||||
if (char === '\\') {
|
||||
// 处理转义字符
|
||||
buffer += nextChar;
|
||||
i++;
|
||||
} else if (char === inString) {
|
||||
state = 'normal';
|
||||
inString = null;
|
||||
}
|
||||
} else if (state === 'singleLineComment') {
|
||||
if (char === '\n') {
|
||||
state = 'normal';
|
||||
}
|
||||
} else if (state === 'multiLineComment') {
|
||||
if (char === '*' && nextChar === '/') {
|
||||
state = 'normal';
|
||||
i++; // 跳过下一个字符
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return processedStatements;
|
||||
if (buffer.trim()) {
|
||||
result.push(buffer.trim());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ export const DbSqlExecTypeEnum = {
|
||||
Delete: EnumValue.of(2, 'DELETE').setTagColor('#F9E2AE'),
|
||||
Insert: EnumValue.of(3, 'INSERT').setTagColor('#A8DEE0'),
|
||||
Query: EnumValue.of(4, 'QUERY').setTagColor('#A8DEE0'),
|
||||
Ddl: EnumValue.of(5, 'DDL').setTagColor('#F9E2AE'),
|
||||
Other: EnumValue.of(-1, 'OTHER').setTagColor('#F9E2AE'),
|
||||
};
|
||||
|
||||
|
||||
@@ -195,6 +195,9 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
|
||||
|
||||
executedStatements++
|
||||
_, err = dbConn.Exec(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
|
||||
@@ -109,6 +109,8 @@ func (d *dbSqlExecAppImpl) Exec(ctx context.Context, execSqlReq *DbSqlExecReq) (
|
||||
execRes, err = d.doInsert(ctx, sqlExec)
|
||||
} else if isOtherQuery(oneSql) {
|
||||
execRes, err = d.doOtherRead(ctx, sqlExec)
|
||||
} else if isDDL(oneSql) {
|
||||
execRes, err = d.doExecDDL(ctx, sqlExec)
|
||||
} else {
|
||||
execRes, err = d.doExec(ctx, dbConn, oneSql)
|
||||
}
|
||||
@@ -149,6 +151,18 @@ func (d *dbSqlExecAppImpl) Exec(ctx context.Context, execSqlReq *DbSqlExecReq) (
|
||||
execRes, err = d.doDelete(ctx, sqlExec)
|
||||
case *sqlstmt.InsertStmt:
|
||||
execRes, err = d.doInsert(ctx, sqlExec)
|
||||
case *sqlstmt.DdlStmt:
|
||||
execRes, err = d.doExecDDL(ctx, sqlExec)
|
||||
case *sqlstmt.CreateDatabase:
|
||||
execRes, err = d.doExecDDL(ctx, sqlExec)
|
||||
case *sqlstmt.CreateTable:
|
||||
execRes, err = d.doExecDDL(ctx, sqlExec)
|
||||
case *sqlstmt.CreateIndex:
|
||||
execRes, err = d.doExecDDL(ctx, sqlExec)
|
||||
case *sqlstmt.AlterDatabase:
|
||||
execRes, err = d.doExecDDL(ctx, sqlExec)
|
||||
case *sqlstmt.AlterTable:
|
||||
execRes, err = d.doExecDDL(ctx, sqlExec)
|
||||
default:
|
||||
execRes, err = d.doExec(ctx, dbConn, sql)
|
||||
}
|
||||
@@ -310,6 +324,19 @@ func (d *dbSqlExecAppImpl) doOtherRead(ctx context.Context, sqlExecParam *sqlExe
|
||||
return d.doQuery(ctx, sqlExecParam.DbConn, selectSql)
|
||||
}
|
||||
|
||||
func (d *dbSqlExecAppImpl) doExecDDL(ctx context.Context, sqlExecParam *sqlExecParam) (*DbSqlExecRes, error) {
|
||||
selectSql := sqlExecParam.Sql
|
||||
sqlExecParam.SqlExecRecord.Type = entity.DbSqlExecTypeDDL
|
||||
|
||||
if procdef := sqlExecParam.Procdef; procdef != nil {
|
||||
if needStartProc := procdef.MatchCondition(DbSqlExecFlowBizType, collx.Kvs("stmtType", "ddl")); needStartProc {
|
||||
return nil, errorx.NewBiz("该操作需要提交工单审批执行")
|
||||
}
|
||||
}
|
||||
|
||||
return d.doExec(ctx, sqlExecParam.DbConn, selectSql)
|
||||
}
|
||||
|
||||
func (d *dbSqlExecAppImpl) doUpdate(ctx context.Context, sqlExecParam *sqlExecParam) (*DbSqlExecRes, error) {
|
||||
dbConn := sqlExecParam.DbConn
|
||||
|
||||
@@ -533,3 +560,9 @@ func isOtherQuery(sql string) bool {
|
||||
sqlPrefix := strings.ToLower(sql[:10])
|
||||
return strings.Contains(sqlPrefix, "explain") || strings.Contains(sqlPrefix, "show")
|
||||
}
|
||||
|
||||
func isDDL(sql string) bool {
|
||||
sqlPrefix := strings.ToLower(sql[:10])
|
||||
return strings.Contains(sqlPrefix, "create") || strings.Contains(sqlPrefix, "alter") ||
|
||||
strings.Contains(sqlPrefix, "drop") || strings.Contains(sqlPrefix, "truncate") || strings.Contains(sqlPrefix, "rename")
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func (v *MysqlVisitor) VisitEmptyStatement_(ctx *mysqlparser.EmptyStatement_Cont
|
||||
}
|
||||
|
||||
func (v *MysqlVisitor) VisitDdlStatement(ctx *mysqlparser.DdlStatementContext) interface{} {
|
||||
ddlStmt := sqlstmt.DdlStmt{}
|
||||
ddlStmt := &sqlstmt.DdlStmt{}
|
||||
ddlStmt.Node = sqlstmt.NewNode(ctx.GetParser(), ctx)
|
||||
return ddlStmt
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ func SQLSplit(r io.Reader, callback SQLCallback) error {
|
||||
// SQLCallback 是解析出一条 SQL 语句后的回调函数
|
||||
type SQLCallback func(sql string) error
|
||||
|
||||
// parseSQL 主要由阿里通义灵码提供
|
||||
func parseSQL(r io.Reader, callback SQLCallback) error {
|
||||
reader := bufio.NewReaderSize(r, 512*1024)
|
||||
buffer := new(bytes.Buffer) // 使用 bytes.Buffer 来处理数据
|
||||
@@ -34,6 +35,7 @@ func parseSQL(r io.Reader, callback SQLCallback) error {
|
||||
var inMultiLineComment bool
|
||||
var inSingleLineComment bool
|
||||
var stringDelimiter rune
|
||||
var escapeNextChar bool // 用于处理转义符
|
||||
|
||||
for {
|
||||
// 读取数据到缓冲区
|
||||
@@ -68,10 +70,18 @@ func parseSQL(r io.Reader, callback SQLCallback) error {
|
||||
}
|
||||
buffer.Next(size)
|
||||
case inString:
|
||||
if r == stringDelimiter {
|
||||
if escapeNextChar {
|
||||
currentStatement.WriteRune(r)
|
||||
escapeNextChar = false
|
||||
} else if r == '\\' {
|
||||
escapeNextChar = true
|
||||
currentStatement.WriteRune(r)
|
||||
} else if r == stringDelimiter {
|
||||
inString = false
|
||||
currentStatement.WriteRune(r)
|
||||
} else {
|
||||
currentStatement.WriteRune(r)
|
||||
}
|
||||
currentStatement.WriteRune(r)
|
||||
buffer.Next(size)
|
||||
case r == '/' && buffer.Len() >= 2 && buffer.Bytes()[1] == '*':
|
||||
inMultiLineComment = true
|
||||
|
||||
@@ -12,7 +12,7 @@ func TestSQLSplit(t *testing.T) {
|
||||
/*删除*/
|
||||
DELETE FROM t_sys_log
|
||||
WHERE
|
||||
id IN (59) and name='哈哈哈';delete form tsyslog;
|
||||
id IN (59) and name='哈哈哈' and name2="hahah;呵呵呵;";delete form tsyslog;
|
||||
-- alter sql语句
|
||||
ALTER TABLE mayfly_go.t_sys_log
|
||||
DROP COLUMN delete_time;
|
||||
@@ -22,8 +22,7 @@ DROP COLUMN delete_time;
|
||||
INSERT INTO t_sys_log VALUES(15, 2, '用户登录', NULL, '⑴ 成孔;⑵ 砼浇筑;⑶ 桩头掏渣;⑷ 桩基检测配合;
|
||||
⑸ 其他工作;⑹ 甲方现场要求乙方完成的其它临时工作。', '{"ip":"::1 ","username":"test_user"}', 'errCode: 401, errMsg: 您的密码安全等级较低,请修改后重新登录;\n信息嘻嘻嘻', '-', 0, '2024-04-23 20:00:35', 0, NULL, '');
|
||||
`
|
||||
// fmt.Println(allsql)
|
||||
// allsql2 := "select * from t_sys_log"
|
||||
|
||||
err := SQLSplit(strings.NewReader(allsql), func(sql string) error {
|
||||
// if strings.Contains(sql, "INSERT") {
|
||||
// return fmt.Errorf("不能存在INSERT语句")
|
||||
|
||||
@@ -27,6 +27,7 @@ const (
|
||||
DbSqlExecTypeDelete int8 = 2 // 删除类型
|
||||
DbSqlExecTypeInsert int8 = 3 // 插入类型
|
||||
DbSqlExecTypeQuery int8 = 4 // 查询类型,如select、show等
|
||||
DbSqlExecTypeDDL int8 = 5 // DDL
|
||||
|
||||
DbSqlExecStatusWait = 1
|
||||
DbSqlExecStatusSuccess = 2
|
||||
|
||||
@@ -41,6 +41,7 @@ func (p *Procinst) ProcinstStart(rc *req.Ctx) {
|
||||
_, err := p.ProcinstApp.StartProc(rc.MetaCtx, startForm.ProcdefId, &dto.StarProc{
|
||||
BizType: startForm.BizType,
|
||||
BizForm: jsonx.ToStr(startForm.BizForm),
|
||||
Remark: startForm.Remark,
|
||||
})
|
||||
biz.ErrIsNil(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user