fix(oceanbase-oracle): format view DDL preview

This commit is contained in:
jearhe authored and GitHub committed 2026-08-31 09:03:07 +08:00
1 parent 0a239bddb2
commit 8da9905ed5
3 files changed
+66 -4

No files matched your search

@@ -20,7 +20,7 @@ import { executableStatementRangeAtCursor, executableStatementRangeCacheForDoc,
import { currentStatementFrameRangeTo } from "@/lib/sql/currentStatementFrame"; import { currentStatementFrameRangeTo } from "@/lib/sql/currentStatementFrame";
import { expandToSqlStatementWindow } from "@/lib/sql/insertValueHints"; import { expandToSqlStatementWindow } from "@/lib/sql/insertValueHints";
import { insertValueHintColumnNames } from "@/lib/sql/insertValueHintColumns"; import { insertValueHintColumnNames } from "@/lib/sql/insertValueHintColumns";
import { canFormatSqlForDatabaseType, formatSqlForEditing, compressSqlText, type SqlFormatDialect } from "@/lib/sql/sqlFormatter"; import { canFormatSqlForDatabaseType, formatSqlForDisplay, formatSqlForEditing, compressSqlText, sqlFormatDialectForDbType, type SqlFormatDialect } from "@/lib/sql/sqlFormatter";
import { detectAndFormatStructured } from "@/lib/sql/autoFormat"; import { detectAndFormatStructured } from "@/lib/sql/autoFormat";
import { enabledSqlParameterSyntaxes, resolveSqlVariableSyntaxToggles } from "@/lib/sql/sqlVariableSyntax"; import { enabledSqlParameterSyntaxes, resolveSqlVariableSyntaxToggles } from "@/lib/sql/sqlVariableSyntax";
import { blankLineDeletionChanges, replaceSelectedEditorText } from "@/lib/editor/queryEditorTextEdits"; import { blankLineDeletionChanges, replaceSelectedEditorText } from "@/lib/editor/queryEditorTextEdits";
@@ -2825,7 +2825,13 @@ async function resolveSqlHoverTooltip(currentView: EditorViewType, pos: number)
const { ddl } = await loadObjectDdl(objectMetadataRequest); const { ddl } = await loadObjectDdl(objectMetadataRequest);
const rawDdl = ddlForHoverPreview(ddl); const rawDdl = ddlForHoverPreview(ddl);
if (rawDdl && rawDdl.trim()) { if (rawDdl && rawDdl.trim()) {
sqlContent = reformatHoverDdl(rawDdl, quoteQualifiedName(hoverQualifiedName)); // A view's display DDL wraps the raw (often single-line) view source
// in `CREATE ... VIEW ... AS`; the table-oriented reformatter cannot
// lay out a SELECT body, so views reuse the shared display formatter
// (the same one the sidebar/object-source viewers use). Tables keep
// the aligned column layout from reformatHoverDdl.
const isViewObject = objectMetadataRequest.objectType === "VIEW" || objectMetadataRequest.objectType === "MATERIALIZED_VIEW";
sqlContent = isViewObject ? await formatSqlForDisplay(rawDdl, props.formatDialect ?? sqlFormatDialectForDbType(props.databaseType), settingsStore.editorSettings.sqlFormatter) : reformatHoverDdl(rawDdl, quoteQualifiedName(hoverQualifiedName));
} }
} catch (error) { } catch (error) {
console.warn(`[DBX] Failed to load table DDL for ${hoverDatabase}.${hoverSchema}.${table.name}:`, error); console.warn(`[DBX] Failed to load table DDL for ${hoverDatabase}.${hoverSchema}.${table.name}:`, error);
+56 -2
View File
@@ -60,9 +60,63 @@ describe("sqlFormatter", () => {
expect(sqlFormatDialectForDbType("duckdb")).toBe("duckdb"); expect(sqlFormatDialectForDbType("duckdb")).toBe("duckdb");
}); });
it("maps only Oracle to the PL/SQL formatter dialect", () => { it("maps Oracle and OceanBase Oracle mode to the PL/SQL formatter dialect", () => {
expect(sqlFormatDialectForDbType("oracle")).toBe("oracle"); expect(sqlFormatDialectForDbType("oracle")).toBe("oracle");
expect(sqlFormatDialectForDbType("oceanbase-oracle")).toBe("generic"); // OceanBase Oracle mode speaks Oracle SQL — issue #7540: it must reuse the
// Oracle dialect so view DDL previews are formatted instead of one line.
expect(sqlFormatDialectForDbType("oceanbase-oracle")).toBe("oracle");
});
it("formats an OceanBase Oracle single-line view DDL into readable multi-line SQL (issue #7540)", async () => {
const singleLine = `CREATE OR REPLACE VIEW "APP"."ACTIVE_USERS" AS SELECT ID, NAME FROM USERS WHERE STATUS = 'ACTIVE'`;
const formatted = await formatSqlForDisplay(singleLine, sqlFormatDialectForDbType("oceanbase-oracle"));
expect(formatted).not.toBe(singleLine);
expect(formatted.split("\n").length).toBeGreaterThan(1);
expect(formatted).toContain("CREATE OR REPLACE VIEW");
expect(formatted).toMatch(/\bSELECT\b/);
expect(formatted).toMatch(/\bFROM\b/);
expect(formatted).toMatch(/\bWHERE\b/);
// String literals and quoted identifiers must survive formatting untouched.
expect(formatted).toContain("'ACTIVE'");
expect(formatted).toContain('"ACTIVE_USERS"');
});
it("formats a bare OceanBase Oracle view source wrapped as CREATE VIEW (issue #7540)", async () => {
// Mirrors the backend build_view_ddl_sql output for a fallback ALL_VIEWS.TEXT
// body: `CREATE VIEW <name> AS <single-line SELECT>`.
const wrapped = `CREATE VIEW "APP"."ACTIVE_USERS" AS
SELECT ID, NAME FROM USERS WHERE STATUS = 'ACTIVE';`;
const formatted = await formatSqlForDisplay(wrapped, sqlFormatDialectForDbType("oceanbase-oracle"));
expect(formatted.split("\n").length).toBeGreaterThan(2);
expect(formatted).toMatch(/\bSELECT\b/);
expect(formatted).toMatch(/\bFROM\b/);
expect(formatted).toMatch(/\bWHERE\b/);
expect(formatted).toContain("'ACTIVE'");
});
it("does not split string literals when formatting an OceanBase Oracle view (issue #7540)", async () => {
const singleLine = `CREATE OR REPLACE VIEW "APP"."V" AS SELECT 'SELECT X FROM Y' AS TXT FROM DUAL`;
const formatted = await formatSqlForDisplay(singleLine, sqlFormatDialectForDbType("oceanbase-oracle"));
expect(formatted).toContain("'SELECT X FROM Y'");
});
it("leaves an already multi-line OceanBase Oracle view DDL semantically intact (issue #7540)", async () => {
const multiLine = `CREATE OR REPLACE VIEW "APP"."ACTIVE_USERS" AS
SELECT
ID,
NAME
FROM USERS
WHERE STATUS = 'ACTIVE';`;
const formatted = await formatSqlForDisplay(multiLine, sqlFormatDialectForDbType("oceanbase-oracle"));
expect(formatted).toContain('"ACTIVE_USERS"');
expect(formatted).toContain("'ACTIVE'");
expect(formatted).toMatch(/\bID\b/);
expect(formatted).toMatch(/\bNAME\b/);
expect(formatted).toMatch(/\bWHERE\b/);
}); });
it("keeps issue #7138 Oracle hierarchy clauses intact", async () => { it("keeps issue #7138 Oracle hierarchy clauses intact", async () => {
+2
View File
@@ -77,6 +77,8 @@ export function sqlFormatDialectForDbType(dbType: string | null | undefined): Sq
case "sqlserver": case "sqlserver":
return "sqlserver"; return "sqlserver";
case "oracle": case "oracle":
// OceanBase Oracle mode speaks Oracle SQL, so it reuses the PL/SQL grammar.
case "oceanbase-oracle":
return "oracle"; return "oracle";
case "clickhouse": case "clickhouse":
return "clickhouse"; return "clickhouse";