feat(sql-editor): 增加SQL错误中文语义提示

- 新增 SQL 执行错误语义化规则,覆盖语法、对象、字段、约束和连接类错误

- 执行失败和刷新失败展示中文语义、处理建议与原始错误

- 补充工具函数与 QueryEditor 回归测试,确保英文报错可读化
This commit is contained in:
Syngnat
2026-06-04 10:48:17 +08:00
parent a9d515f160
commit 9acb1c69f7
4 changed files with 258 additions and 6 deletions

View File

@@ -17,6 +17,7 @@ import { isOracleLikeDialect, resolveSqlDialect, resolveSqlFunctions, resolveSql
import { applyQueryAutoLimit } from '../utils/queryAutoLimit';
import { extractQueryResultTableRef, type QueryResultTableRef } from '../utils/queryResultTable';
import { quoteIdentPart } from '../utils/sql';
import { formatSqlExecutionError } from '../utils/sqlErrorSemantics';
import { resolveCurrentSqlStatementRange, resolveExecutableSql } from '../utils/sqlStatementSelection';
import { isMacLikePlatform } from '../utils/appearance';
import { splitSidebarQualifiedName } from '../utils/sidebarLocate';
@@ -4031,7 +4032,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
}
const res = await DBQueryMulti(buildRpcConnectionConfig(config) as any, currentDb, sql, queryId);
if (!res?.success) {
message.error('刷新失败: ' + (res?.message || '未知错误'));
message.error('刷新失败: ' + formatSqlExecutionError(res?.message || '未知错误'));
return;
}
@@ -4073,7 +4074,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
: rs
));
} catch (err: any) {
message.error('刷新失败: ' + (err?.message || '未知错误'));
message.error('刷新失败: ' + formatSqlExecutionError(err?.message || err || '未知错误'));
} finally {
setLoading(false);
}
@@ -4172,7 +4173,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
if (shellConvert.recognized) {
if (shellConvert.error) {
const prefix = statements.length > 1 ? `${idx + 1} 条语句执行失败:` : '';
setExecutionError(prefix + shellConvert.error);
setExecutionError(formatSqlExecutionError(shellConvert.error, { prefix }));
setResultSets([]);
setActiveResultKey('');
return;
@@ -4211,7 +4212,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
});
if (!res.success) {
const prefix = statements.length > 1 ? `${idx + 1} 条语句执行失败:` : '';
setExecutionError(prefix + res.message);
setExecutionError(formatSqlExecutionError(res.message, { prefix }));
setResultSets([]);
setActiveResultKey('');
return;
@@ -4376,7 +4377,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
return;
}
setExecutionError(res.message);
setExecutionError(formatSqlExecutionError(res.message));
setResultSets([]);
setActiveResultKey('');
return;
@@ -4513,7 +4514,8 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
}
} catch (e: any) {
message.error("Error executing query: " + e.message);
const formattedError = formatSqlExecutionError(e?.message || e);
message.error("执行失败: " + formattedError);
addSqlLog({
id: `log-${Date.now()}-error`,
timestamp: Date.now(),
@@ -4523,6 +4525,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
message: e.message,
dbName: currentDb
});
setExecutionError(formattedError);
setResultSets([]);
setActiveResultKey('');
} finally {