fix(structure): keep Oracle case-sensitive identifiers quoted when quoting off

This commit is contained in:
zipg authored and GitHub committed 2026-09-21 12:52:44 +08:00
1 parent f8ee34f937
commit f19d842b8f
8 files changed
+140 -12

No files matched your search

@@ -248,7 +248,7 @@ import TableStructureEditor from "@/components/structure/TableStructureEditor.vu
const mountedApps: App[] = [];
function draft(isPrimaryKey = false, identity?: { seed: number; increment: number }) {
function draft(isPrimaryKey = false, identity?: { seed: number; increment: number }, columnName = "id", foreignKeyRefTable?: string) {
const isNullable = identity ? false : !isPrimaryKey;
return {
initialized: true,
@@ -259,7 +259,7 @@ function draft(isPrimaryKey = false, identity?: { seed: number; increment: numbe
columns: [
{
id: "existing:id",
name: "id",
name: columnName,
dataType: "INT",
isNullable,
defaultValue: "",
@@ -267,7 +267,7 @@ function draft(isPrimaryKey = false, identity?: { seed: number; increment: numbe
isPrimaryKey,
extra: identity ? { autoIncrement: true, identity: { ...identity } } : {},
original: {
name: "id",
name: columnName,
data_type: "INT",
is_nullable: isNullable,
column_default: null,
@@ -280,12 +280,39 @@ function draft(isPrimaryKey = false, identity?: { seed: number; increment: numbe
},
],
indexes: [],
foreignKeys: [],
foreignKeys: foreignKeyRefTable
? [
{
id: "existing:fk",
name: "FK_T_9649",
column: columnName,
refSchema: "",
refTable: foreignKeyRefTable,
refColumn: "ID",
onUpdate: "",
onDelete: "",
original: {
name: "FK_T_9649",
column: columnName,
ref_schema: null,
ref_table: foreignKeyRefTable,
ref_column: "ID",
on_update: null,
on_delete: null,
},
markedForDrop: false,
},
]
: [],
triggers: [],
};
}
async function mountEditor(databaseType: "sqlserver" | "postgres" | "sqlite" | "oracle" | "oceanbase-oracle" | "iris" | "dameng" | "duckdb" | "informix", isPrimaryKey = false, options: { database?: string; dynamicTypes?: string[]; identity?: { seed: number; increment: number } } = {}) {
async function mountEditor(
databaseType: "sqlserver" | "postgres" | "sqlite" | "oracle" | "oceanbase-oracle" | "iris" | "dameng" | "duckdb" | "informix",
isPrimaryKey = false,
options: { database?: string; dynamicTypes?: string[]; identity?: { seed: number; increment: number }; tableName?: string; columnName?: string; foreignKeyRefTable?: string } = {},
) {
mocks.connection.db_type = databaseType;
mocks.connection.name = databaseType;
mocks.connection.driver_label = databaseType;
@@ -299,8 +326,8 @@ async function mountEditor(databaseType: "sqlserver" | "postgres" | "sqlite" | "
connectionId: mocks.connection.id,
database: options.database ?? "test",
schema: "SYSDBA",
tableName: "users",
draft: draft(isPrimaryKey, options.identity),
tableName: options.tableName ?? "users",
draft: draft(isPrimaryKey, options.identity, options.columnName, options.foreignKeyRefTable),
});
mountedApps.push(app);
app.mount(root);
@@ -597,6 +624,58 @@ describe("TableStructureEditor primary key editing", () => {
expect(root.textContent).not.toContain(`"${schema}"."demo_table"`);
});
it("keeps case-sensitive Oracle identifiers quoted when quoting is disabled (#9649)", async () => {
mocks.editorSettings.generateSqlQuoteIdentifiers = false;
const root = await mountEditor("oracle", false, { tableName: "T_9649", columnName: "cName" });
mocks.buildTableStructureChangeSql.mockResolvedValueOnce({
statements: ['ALTER TABLE "DBX_TEST"."T_9649" MODIFY ("cName" VARCHAR2(120 BYTE))', 'ALTER TABLE "DBX_TEST"."T_9649" ADD ("cNabcs" clob)', 'COMMENT ON COLUMN "DBX_TEST"."T_9649"."cName" IS \'中文名\''],
warnings: [],
});
buttonWithText(root, "structureEditor.addColumn").click();
await vi.waitFor(() => expect(root.textContent).toContain('MODIFY ("cName" VARCHAR2(120 BYTE))'));
expect(root.textContent).toContain('ADD ("cNabcs" clob)');
expect(root.textContent).toContain("COMMENT ON COLUMN DBX_TEST.T_9649.\"cName\" IS '中文名'");
expect(root.textContent).not.toContain("CNAME");
});
it("keeps a quoted Oracle table name when quoting is disabled (#9649)", async () => {
mocks.editorSettings.generateSqlQuoteIdentifiers = false;
const root = await mountEditor("oracle", false, { tableName: "t_9649_lower", columnName: "ID" });
mocks.buildTableStructureChangeSql.mockResolvedValueOnce({ statements: ['ALTER TABLE "DBX_TEST"."t_9649_lower" MODIFY ("ID" NUMBER(12))'], warnings: [] });
buttonWithText(root, "structureEditor.addColumn").click();
await vi.waitFor(() => expect(root.textContent).toContain('ALTER TABLE DBX_TEST."t_9649_lower" MODIFY (ID NUMBER(12))'));
expect(root.textContent).not.toContain("T_9649_LOWER");
});
it("keeps case-sensitive foreign key referenced names quoted when quoting is disabled (#9649)", async () => {
mocks.editorSettings.generateSqlQuoteIdentifiers = false;
const root = await mountEditor("oracle", false, { tableName: "T_9649", columnName: "ID", foreignKeyRefTable: "cRefTab" });
mocks.buildTableStructureChangeSql.mockResolvedValueOnce({
statements: ['ALTER TABLE "DBX_TEST"."T_9649" ADD CONSTRAINT "FK_T_9649" FOREIGN KEY ("ID") REFERENCES "DBX_TEST"."cRefTab"("ID")'],
warnings: [],
});
buttonWithText(root, "structureEditor.addColumn").click();
await vi.waitFor(() => expect(root.textContent).toContain('REFERENCES DBX_TEST."cRefTab"(ID)'));
expect(root.textContent).not.toContain("CREFTAB");
});
it("still folds plain Oracle identifiers when quoting is disabled (#8997)", async () => {
mocks.editorSettings.generateSqlQuoteIdentifiers = false;
const root = await mountEditor("oracle", false, { tableName: "TEST", columnName: "ID" });
mocks.buildTableStructureChangeSql.mockResolvedValueOnce({ statements: ['ALTER TABLE "SYSTEM"."TEST" ADD ("NEW_COL" VARCHAR2(20))'], warnings: [] });
buttonWithText(root, "structureEditor.addColumn").click();
await vi.waitFor(() => expect(root.textContent).toContain("ALTER TABLE SYSTEM.TEST ADD (NEW_COL VARCHAR2(20))"));
expect(root.textContent).not.toContain('"NEW_COL"');
});
it("keeps SQLite rebuild SQL aligned with the guarded apply plan", async () => {
mocks.editorSettings.generateSqlQuoteIdentifiers = false;
const root = await mountEditor("sqlite");