fix(editor): locate SQL errors after pagination rewriting
This commit is contained in:
4 files changed
+55
-3
No files matched your search
@@ -96,7 +96,7 @@ import {
|
||||
import { buildHoverTableSql, ddlForHoverPreview, hoverTableMatchesScope, normalizeAlignedSqlWhitespace, quoteIdentifier, quoteQualifiedName, reformatHoverDdl, scopeHoverTables, type HoverTableScope } from "@/lib/editor/hoverTableSql";
|
||||
import { constrainSqlHoverLayout } from "@/lib/editor/sqlHoverLayout";
|
||||
import { createHoverSearch, type HoverSearchController } from "@/lib/editor/sqlHoverSearch";
|
||||
import { lineColumnToOffset, sqlErrorDecorationRange as resolveSqlErrorDecorationRange } from "@/lib/sql/sqlDiagnostics";
|
||||
import { lineColumnToOffset, sqlErrorDecorationRange as resolveSqlErrorDecorationRange, sqlErrorSqlMatchesEditor } from "@/lib/sql/sqlDiagnostics";
|
||||
import { analyzeMysqlRoutineSyntax, supportsMysqlRoutineSyntaxDiagnostics } from "@/lib/sql/mysqlRoutineSyntaxDiagnostics";
|
||||
import { buildOracleSyntaxDiagnostics } from "@/lib/sql/oracleSyntaxDiagnostics";
|
||||
import {
|
||||
@@ -3077,7 +3077,7 @@ async function resolveSqlHoverTooltip(currentView: EditorViewType, pos: number)
|
||||
|
||||
function sqlErrorDecorationRange(currentState: import("@codemirror/state").EditorState) {
|
||||
if (!props.executionError) return [];
|
||||
if (!props.executionErrorSql || props.executionErrorSql !== currentState.doc.toString()) return [];
|
||||
if (!props.executionErrorSql || !sqlErrorSqlMatchesEditor(currentState.doc.toString(), props.executionErrorSql)) return [];
|
||||
const range = resolveSqlErrorDecorationRange(currentState.doc.toString(), props.executionError);
|
||||
if (!range) return [];
|
||||
return [
|
||||
|
||||
@@ -8,6 +8,27 @@ export interface SqlErrorRange {
|
||||
to: number;
|
||||
}
|
||||
|
||||
function normalizeSqlForComparison(sql: string): string {
|
||||
return sql.trim().replace(/;\s*$/u, "").replace(/\s+/gu, " ").trim().toLowerCase();
|
||||
}
|
||||
|
||||
function removeDbxPagination(sql: string): string {
|
||||
return sql.replace(/\s+(?:limit\s+\d+(?:\s+offset\s+\d+)?|offset\s+\d+\s+rows?(?:\s+fetch\s+(?:next|first)\s+\d+\s+rows?(?:\s+only)?)?|fetch\s+(?:first|next)\s+\d+\s+rows?\s+only)\s*;?\s*$/iu, "").trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pagination is appended to the SQL sent to the database, so an execution
|
||||
* error can refer to a SQL string that differs from the editor by only that
|
||||
* generated suffix. Keep error highlighting disabled for unrelated stale
|
||||
* errors while allowing this known DBX rewrite.
|
||||
*/
|
||||
export function sqlErrorSqlMatchesEditor(editorSql: string, executedSql: string): boolean {
|
||||
if (editorSql === executedSql) return true;
|
||||
const norm = (sql: string) => normalizeSqlForComparison(sql);
|
||||
if (norm(executedSql) === norm(editorSql)) return true;
|
||||
return norm(removeDbxPagination(executedSql)) === norm(removeDbxPagination(editorSql));
|
||||
}
|
||||
|
||||
function toZeroBased(value: string | undefined): number | null {
|
||||
if (!value) return null;
|
||||
const parsed = Number.parseInt(value, 10);
|
||||
@@ -33,6 +54,14 @@ export function parseSqlErrorLocation(message: string): SqlErrorLocation | null
|
||||
if (line != null && caretIndex >= 0) return { line, column: caretIndex };
|
||||
}
|
||||
|
||||
// MySQL commonly reports only "at line N" for syntax errors. With no
|
||||
// column information available, point at the beginning of that line.
|
||||
const lineOnly = /\bline\s+(\d+)\b/i.exec(message);
|
||||
if (lineOnly) {
|
||||
const line = toZeroBased(lineOnly[1]);
|
||||
if (line != null) return { line, column: 0 };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user