fix(sql): format Oracle queries with PL/SQL dialect

Closes #7138
This commit is contained in:
t8y2 committed 2026-08-25 07:17:11 +00:00
1 parent e9fea304ba
commit 88e659833d
2 files changed
+41 -1

No files matched your search

+36
View File
@@ -36,6 +36,42 @@ describe("sqlFormatter", () => {
expect(sqlFormatDialectForDbType("duckdb")).toBe("duckdb");
});
it("maps only Oracle to the PL/SQL formatter dialect", () => {
expect(sqlFormatDialectForDbType("oracle")).toBe("oracle");
expect(sqlFormatDialectForDbType("oceanbase-oracle")).toBe("generic");
});
it("keeps issue #7138 Oracle hierarchy clauses intact", async () => {
const sql = "SELECT ctt.U_DM FROM cte_test ctt START WITH ctt.SU_DM IN ('16','17','18','19') CONNECT BY PRIOR ctt.U_DM = HY.SU_DM;";
await expect(formatSqlForEditing(sql, sqlFormatDialectForDbType("oracle"))).resolves.toBe(`SELECT
ctt.U_DM
FROM
cte_test ctt
START WITH ctt.SU_DM IN ('16', '17', '18', '19')
CONNECT BY PRIOR ctt.U_DM = HY.SU_DM;`);
});
it("formats valid Oracle hierarchy clauses with the same alias", async () => {
const sql = "SELECT ctt.U_DM FROM cte_test ctt START WITH ctt.SU_DM = '16' CONNECT BY PRIOR ctt.U_DM = ctt.SU_DM;";
const formatted = await formatSqlForEditing(sql, sqlFormatDialectForDbType("oracle"));
expect(formatted).toContain("FROM\n cte_test ctt\nSTART WITH ctt.SU_DM = '16'");
expect(formatted).toContain("\nCONNECT BY PRIOR ctt.U_DM = ctt.SU_DM;");
});
it("formats ordinary Oracle SQL and anonymous PL/SQL", async () => {
await expect(formatSqlForEditing("select employee_id from employees where department_id = 10;", sqlFormatDialectForDbType("oracle"))).resolves.toBe("SELECT\n employee_id\nFROM\n employees\nWHERE\n department_id = 10;");
await expect(formatSqlForEditing("declare v_count number := 1; begin v_count := v_count + 1; end;", sqlFormatDialectForDbType("oracle"))).resolves.toBe("DECLARE v_count number := 1;\n\nBEGIN v_count := v_count + 1;\n\nEND;");
});
it("keeps incomplete Oracle editor SQL unchanged", async () => {
const sql = "select *\nfrom dbname.\n;";
await expect(formatSqlForEditing(sql, sqlFormatDialectForDbType("oracle"))).resolves.toBe(sql);
});
it("keeps DuckDB prefix aliases out of formatted named parameters", async () => {
const cases = [
["select 日期:date(订单日期) from 订单;", []],
+5 -1
View File
@@ -1,7 +1,7 @@
import { DEFAULT_SQL_FORMATTER_SETTINGS, normalizeSqlFormatterSettings, sqlFormatterOptions, type SqlFormatterSettings } from "@/lib/sql/sqlFormatterConfig";
import { looksLikeXml } from "@/lib/sql/autoFormat";
export type SqlFormatDialect = "mysql" | "postgres" | "sqlite" | "sqlserver" | "clickhouse" | "dameng" | "duckdb" | "generic";
export type SqlFormatDialect = "mysql" | "postgres" | "sqlite" | "sqlserver" | "oracle" | "clickhouse" | "dameng" | "duckdb" | "generic";
export const MAX_SQL_FORMAT_CHARS = 1_000_000;
@@ -76,6 +76,8 @@ export function sqlFormatDialectForDbType(dbType: string | null | undefined): Sq
return "sqlite";
case "sqlserver":
return "sqlserver";
case "oracle":
return "oracle";
case "clickhouse":
return "clickhouse";
case "dameng":
@@ -97,6 +99,8 @@ function formatterLanguage(dialect: SqlFormatDialect) {
return "sqlite";
case "sqlserver":
return "transactsql";
case "oracle":
return "plsql";
case "clickhouse":
return "clickhouse";
default: