Fix:修复 SQL 子查询语义诊断误报 (#2184)

* Fix:修复 SQL 子查询语义诊断误报

* Improve:添加 SQL 语义诊断开关

* Improve:优化 SQL 语义诊断开关说明

* Fix:收紧 SQL 语义诊断飘红范围

* Improve:调整 SQL 语义诊断默认策略

---------

Co-authored-by: staff <staff@qimaos-MacBook-Pro.local>
This commit is contained in:
zipgandstaff authored and GitHub committed 2026-06-30 20:15:59 +08:00
1 parent 73a996ebe6
commit c38bc05417
12 files changed
+417 -31

No files matched your search

@@ -34,6 +34,7 @@ import {
type DesktopIconTheme,
type InterfaceLayout,
type DisconnectTabHandlingMode,
type SqlSemanticDiagnosticsMode,
type UpdateDownloadSource,
type CustomThemeColors,
type CustomTheme,
@@ -190,6 +191,8 @@ const editExecuteMode = ref(settingsStore.editorSettings.executeMode);
const editShowExecutionTargetPicker = ref(settingsStore.editorSettings.showExecutionTargetPicker);
const editAutoAliasTables = ref(settingsStore.editorSettings.autoAliasTables);
const editWordWrap = ref(settingsStore.editorSettings.wordWrap);
const editSqlSemanticDiagnosticsMode = ref<SqlSemanticDiagnosticsMode>(settingsStore.editorSettings.sqlSemanticDiagnosticsMode);
const editSqlSemanticDiagnosticsEnabled = ref(settingsStore.editorSettings.sqlSemanticDiagnosticsEnabled);
const editConfirmDangerousSqlExecution = ref(settingsStore.editorSettings.confirmDangerousSqlExecution);
const editAppLayout = ref(settingsStore.editorSettings.appLayout);
const editShowTrayIcon = ref(settingsStore.desktopSettings.show_tray_icon);
@@ -468,6 +471,8 @@ watch(
editShowExecutionTargetPicker.value = settingsStore.editorSettings.showExecutionTargetPicker;
editAutoAliasTables.value = settingsStore.editorSettings.autoAliasTables;
editWordWrap.value = settingsStore.editorSettings.wordWrap;
editSqlSemanticDiagnosticsMode.value = settingsStore.editorSettings.sqlSemanticDiagnosticsMode;
editSqlSemanticDiagnosticsEnabled.value = settingsStore.editorSettings.sqlSemanticDiagnosticsEnabled;
editConfirmDangerousSqlExecution.value = settingsStore.editorSettings.confirmDangerousSqlExecution;
editAppLayout.value = settingsStore.editorSettings.appLayout;
editShowTrayIcon.value = settingsStore.desktopSettings.show_tray_icon;
@@ -532,6 +537,8 @@ function hasChanges(): boolean {
editShowExecutionTargetPicker.value !== settingsStore.editorSettings.showExecutionTargetPicker ||
editAutoAliasTables.value !== settingsStore.editorSettings.autoAliasTables ||
editWordWrap.value !== settingsStore.editorSettings.wordWrap ||
editSqlSemanticDiagnosticsMode.value !== settingsStore.editorSettings.sqlSemanticDiagnosticsMode ||
editSqlSemanticDiagnosticsEnabled.value !== settingsStore.editorSettings.sqlSemanticDiagnosticsEnabled ||
editConfirmDangerousSqlExecution.value !== settingsStore.editorSettings.confirmDangerousSqlExecution ||
editAppLayout.value !== settingsStore.editorSettings.appLayout ||
editShowTrayIcon.value !== settingsStore.desktopSettings.show_tray_icon ||
@@ -582,6 +589,7 @@ async function persistSettings() {
showExecutionTargetPicker: editShowExecutionTargetPicker.value,
autoAliasTables: editAutoAliasTables.value,
wordWrap: editWordWrap.value,
sqlSemanticDiagnosticsMode: editSqlSemanticDiagnosticsMode.value,
confirmDangerousSqlExecution: editConfirmDangerousSqlExecution.value,
appLayout: editAppLayout.value,
showColumnCommentsInHeader: editShowColumnCommentsInHeader.value,
@@ -643,6 +651,8 @@ function resetDefaultsForTab(tab: SettingsCategory) {
editShowExecutionTargetPicker.value = DEFAULT_EDITOR_SETTINGS.showExecutionTargetPicker;
editAutoAliasTables.value = DEFAULT_EDITOR_SETTINGS.autoAliasTables;
editWordWrap.value = DEFAULT_EDITOR_SETTINGS.wordWrap;
editSqlSemanticDiagnosticsMode.value = DEFAULT_EDITOR_SETTINGS.sqlSemanticDiagnosticsMode;
editSqlSemanticDiagnosticsEnabled.value = DEFAULT_EDITOR_SETTINGS.sqlSemanticDiagnosticsEnabled;
editConfirmDangerousSqlExecution.value = DEFAULT_EDITOR_SETTINGS.confirmDangerousSqlExecution;
} else if (tab === "formatter") {
editSqlFormatter.value = normalizeSqlFormatterSettings(DEFAULT_EDITOR_SETTINGS.sqlFormatter);
@@ -702,6 +712,8 @@ function resetAllDefaults() {
editShowExecutionTargetPicker.value = DEFAULT_EDITOR_SETTINGS.showExecutionTargetPicker;
editAutoAliasTables.value = DEFAULT_EDITOR_SETTINGS.autoAliasTables;
editWordWrap.value = DEFAULT_EDITOR_SETTINGS.wordWrap;
editSqlSemanticDiagnosticsMode.value = DEFAULT_EDITOR_SETTINGS.sqlSemanticDiagnosticsMode;
editSqlSemanticDiagnosticsEnabled.value = DEFAULT_EDITOR_SETTINGS.sqlSemanticDiagnosticsEnabled;
editConfirmDangerousSqlExecution.value = DEFAULT_EDITOR_SETTINGS.confirmDangerousSqlExecution;
editAppLayout.value = DEFAULT_EDITOR_SETTINGS.appLayout;
editShowTrayIcon.value = DEFAULT_DESKTOP_SETTINGS.show_tray_icon;
@@ -866,6 +878,11 @@ function onExecuteModeChange(v: any) {
if (v === "all" || v === "current") editExecuteMode.value = v;
}
function onSqlSemanticDiagnosticsEnabledChange(value: boolean) {
editSqlSemanticDiagnosticsEnabled.value = value;
editSqlSemanticDiagnosticsMode.value = value ? "enabled" : "disabled";
}
function onFontFamilyChange(v: any) {
if (typeof v === "string") editFontFamily.value = v;
}
@@ -2005,14 +2022,26 @@ watch(
</div>
</div>
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
<div class="space-y-1">
<Label for="editor-confirm-dangerous-sql">{{ t("settings.confirmDangerousSqlExecution") }}</Label>
<p class="text-xs text-muted-foreground">
{{ t("settings.confirmDangerousSqlExecutionDescription") }}
</p>
<div class="grid gap-3 md:grid-cols-2">
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
<div class="space-y-1">
<Label for="editor-sql-semantic-diagnostics">{{ t("settings.sqlSemanticDiagnosticsEnabled") }}</Label>
<p class="text-xs text-muted-foreground">
{{ t("settings.sqlSemanticDiagnosticsEnabledDescription") }}
</p>
</div>
<Switch id="editor-sql-semantic-diagnostics" :model-value="editSqlSemanticDiagnosticsEnabled" class="mt-0.5" @update:model-value="onSqlSemanticDiagnosticsEnabledChange" />
</div>
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
<div class="space-y-1">
<Label for="editor-confirm-dangerous-sql">{{ t("settings.confirmDangerousSqlExecution") }}</Label>
<p class="text-xs text-muted-foreground">
{{ t("settings.confirmDangerousSqlExecutionDescription") }}
</p>
</div>
<Switch id="editor-confirm-dangerous-sql" v-model="editConfirmDangerousSqlExecution" class="mt-0.5" />
</div>
<Switch id="editor-confirm-dangerous-sql" v-model="editConfirmDangerousSqlExecution" class="mt-0.5" />
</div>
<Separator />
@@ -926,6 +926,17 @@ function setSemanticDiagnostics(next: SqlSemanticDiagnostic[]) {
reconfigureDiagnostics();
}
function clearScheduledSemanticDiagnostics() {
semanticDiagnosticRunId++;
if (semanticDiagnosticTimer) clearTimeout(semanticDiagnosticTimer);
semanticDiagnosticTimer = null;
pendingSemanticDiagnosticPreserveOutsideRanges = false;
}
function shouldSkipSqlSemanticDiagnostics() {
return props.databaseType !== "redis" && !settingsStore.editorSettings.sqlSemanticDiagnosticsEnabled;
}
function rangesOverlap(left: { from: number; to: number }, right: { from: number; to: number }): boolean {
return left.from < right.to && right.from < left.to;
}
@@ -1046,6 +1057,10 @@ async function refreshSemanticDiagnostics(options: { preserveOutsideRanges?: boo
setSemanticDiagnostics(buildRedisSyntaxDiagnostics(sql));
return;
}
if (shouldSkipSqlSemanticDiagnostics()) {
setSemanticDiagnostics([]);
return;
}
if (!shouldRunSqlSemanticDiagnostics(sql, currentView.state.selection.main.head, { databaseType: props.databaseType })) {
scheduleSemanticDiagnostics(1200, { preserveOutsideRanges: options.preserveOutsideRanges });
return;
@@ -1102,6 +1117,11 @@ async function refreshSemanticDiagnostics(options: { preserveOutsideRanges?: boo
function scheduleSemanticDiagnostics(delay = 500, options: { preserveOutsideRanges?: boolean } = {}) {
if (!editorIsActive) return;
if (shouldSkipSqlSemanticDiagnostics()) {
clearScheduledSemanticDiagnostics();
setSemanticDiagnostics([]);
return;
}
pendingSemanticDiagnosticPreserveOutsideRanges = !!options.preserveOutsideRanges;
if (semanticDiagnosticTimer) clearTimeout(semanticDiagnosticTimer);
semanticDiagnosticTimer = setTimeout(() => {
@@ -2512,14 +2532,25 @@ watch(
{ deep: true },
);
watch(
() => settingsStore.editorSettings.sqlSemanticDiagnosticsEnabled,
(enabled) => {
if (props.databaseType === "redis") return;
if (!shouldSkipSqlSemanticDiagnostics() && enabled) {
scheduleSemanticDiagnostics(0);
return;
}
clearScheduledSemanticDiagnostics();
setSemanticDiagnostics([]);
},
);
function pauseQueryEditorBackgroundWork() {
flushEditorViewport();
flushEditorSelection();
clearTableNavigationHover();
editorIsActive = false;
semanticDiagnosticRunId++;
if (semanticDiagnosticTimer) clearTimeout(semanticDiagnosticTimer);
semanticDiagnosticTimer = null;
clearScheduledSemanticDiagnostics();
completionEpoch++;
unregisterTableReferenceDropListener();
}