🐛 fix(sidebar): 修复 OceanBase Oracle 只读对象加载

This commit is contained in:
tianqijiuyun-latiao
2026-07-15 13:17:40 +08:00
parent a0bb19b8bb
commit 6f65f9e7cc
2 changed files with 87 additions and 12 deletions

View File

@@ -10,6 +10,7 @@ import {
buildPackagesMetadataQuerySpecs,
buildSchemasMetadataQuerySpecs,
buildSequencesMetadataQuerySpecs,
buildViewsMetadataQuerySpecs,
loadFunctions,
loadPackages,
loadSequences,
@@ -78,8 +79,15 @@ describe("buildSchemasMetadataQuerySpecs", () => {
});
describe("Oracle object metadata loaders", () => {
it("builds owner-scoped sequence and package queries for Oracle", () => {
it("builds owner-scoped object queries for the selected Oracle schema", () => {
expect(buildViewsMetadataQuerySpecs("oracle", "SBDEV").map((spec) => spec.sql)).toEqual([
"SELECT OWNER AS schema_name, VIEW_NAME AS view_name FROM ALL_VIEWS WHERE OWNER = 'SBDEV' ORDER BY VIEW_NAME",
]);
expect(buildFunctionsMetadataQuerySpecs("oracle", "SBDEV").map((spec) => spec.sql)).toEqual([
"SELECT OWNER AS schema_name, OBJECT_NAME AS routine_name, OBJECT_TYPE AS routine_type FROM ALL_OBJECTS WHERE OWNER = 'SBDEV' AND OBJECT_TYPE IN ('FUNCTION','PROCEDURE') ORDER BY OBJECT_TYPE, OBJECT_NAME",
]);
expect(buildSequencesMetadataQuerySpecs("oracle", "MYCIMLED").map((spec) => spec.sql)).toEqual([
"SELECT OWNER AS schema_name, OBJECT_NAME AS sequence_name FROM ALL_OBJECTS WHERE OWNER = 'MYCIMLED' AND OBJECT_TYPE = 'SEQUENCE' ORDER BY OBJECT_NAME",
"SELECT SEQUENCE_OWNER AS schema_name, SEQUENCE_NAME AS sequence_name FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = 'MYCIMLED' ORDER BY SEQUENCE_NAME",
]);
expect(buildPackagesMetadataQuerySpecs("oracle", "MYCIMLED").map((spec) => spec.sql)).toEqual([
@@ -133,6 +141,54 @@ describe("Oracle object metadata loaders", () => {
],
});
});
it("uses the selected owner catalog for OceanBase Oracle read-only connections", async () => {
const executedSql: string[] = [];
mockedDBQuery.mockImplementation(async (_config: unknown, _dbName: string, sql: string) => {
executedSql.push(sql);
if (sql.includes("ALL_VIEWS") && sql.includes("OWNER = 'SBDEV'")) {
return {
success: true,
message: "",
data: [{ OWNER: "SBDEV", VIEW_NAME: "V_RISK" }],
};
}
if (sql.includes("ALL_OBJECTS") && sql.includes("('FUNCTION','PROCEDURE')")) {
return {
success: true,
message: "",
data: [{ OWNER: "SBDEV", OBJECT_NAME: "P_REFRESH", OBJECT_TYPE: "PROCEDURE" }],
};
}
if (sql.includes("ALL_OBJECTS") && sql.includes("OBJECT_TYPE = 'SEQUENCE'")) {
return {
success: true,
message: "",
data: [{ OWNER: "SBDEV", OBJECT_NAME: "SEQ_RISK" }],
};
}
return { success: false, message: "", data: [] };
});
const conn = { config: { type: "oceanbase", oceanBaseProtocol: "oracle" } };
await expect(loadViews(conn, "SBDEV")).resolves.toEqual({
supported: true,
views: [{ schemaName: "SBDEV", viewName: "SBDEV.V_RISK" }],
});
await expect(loadFunctions(conn, "SBDEV")).resolves.toEqual({
supported: true,
routines: [{ displayName: "SBDEV.P_REFRESH [P]", routineName: "SBDEV.P_REFRESH", routineType: "PROCEDURE" }],
});
await expect(loadSequences(conn, "SBDEV")).resolves.toEqual({
supported: true,
sequences: [{ displayName: "SBDEV.SEQ_RISK", schemaName: "SBDEV", sequenceName: "SBDEV.SEQ_RISK" }],
});
expect(executedSql).toHaveLength(3);
expect(executedSql).not.toContain(expect.stringContaining("USER_"));
expect(executedSql).not.toContain(expect.stringContaining("ALL_SEQUENCES"));
});
});
describe("Kingbase/PG routine metadata loaders", () => {

View File

@@ -435,6 +435,17 @@ const buildViewsMetadataQuerySpecs = (
}
case "oracle":
case "dm":
if (safeDbName) {
// CURRENT_SCHEMA does not change USER. When a read-only account selects
// another Oracle schema, USER_VIEWS would successfully return that
// account's (usually empty) catalog and prevent the target schema from
// being queried. Read the explicitly selected owner first instead.
return [
{
sql: `SELECT OWNER AS schema_name, VIEW_NAME AS view_name FROM ALL_VIEWS WHERE OWNER = '${safeDbName.toUpperCase()}' ORDER BY VIEW_NAME`,
},
];
}
return normalizeMetadataQuerySpecs([
{
sql: `SELECT VIEW_NAME AS view_name FROM USER_VIEWS ORDER BY VIEW_NAME`,
@@ -442,11 +453,6 @@ const buildViewsMetadataQuerySpecs = (
{
sql: `SELECT OWNER AS schema_name, VIEW_NAME AS view_name FROM ALL_VIEWS WHERE OWNER = USER ORDER BY VIEW_NAME`,
},
{
sql: safeDbName
? `SELECT OWNER AS schema_name, VIEW_NAME AS view_name FROM ALL_VIEWS WHERE OWNER = '${safeDbName.toUpperCase()}' ORDER BY VIEW_NAME`
: "",
},
]);
case "sqlite":
return [
@@ -589,6 +595,16 @@ const buildFunctionsMetadataQuerySpecs = (
}
case "oracle":
case "dm":
if (safeDbName) {
// See the corresponding view query above. Oracle CURRENT_SCHEMA only
// changes name resolution, so USER_OBJECTS still belongs to the login
// account rather than the schema selected in the sidebar.
return [
{
sql: `SELECT OWNER AS schema_name, OBJECT_NAME AS routine_name, OBJECT_TYPE AS routine_type FROM ALL_OBJECTS WHERE OWNER = '${safeDbName.toUpperCase()}' AND OBJECT_TYPE IN ('FUNCTION','PROCEDURE') ORDER BY OBJECT_TYPE, OBJECT_NAME`,
},
];
}
return normalizeMetadataQuerySpecs([
{
sql: `SELECT OBJECT_NAME AS routine_name, OBJECT_TYPE AS routine_type FROM USER_OBJECTS WHERE OBJECT_TYPE IN ('FUNCTION','PROCEDURE') ORDER BY OBJECT_TYPE, OBJECT_NAME`,
@@ -596,11 +612,6 @@ const buildFunctionsMetadataQuerySpecs = (
{
sql: `SELECT OWNER AS schema_name, OBJECT_NAME AS routine_name, OBJECT_TYPE AS routine_type FROM ALL_OBJECTS WHERE OWNER = USER AND OBJECT_TYPE IN ('FUNCTION','PROCEDURE') ORDER BY OBJECT_TYPE, OBJECT_NAME`,
},
{
sql: safeDbName
? `SELECT OWNER AS schema_name, OBJECT_NAME AS routine_name, OBJECT_TYPE AS routine_type FROM ALL_OBJECTS WHERE OWNER = '${safeDbName.toUpperCase()}' AND OBJECT_TYPE IN ('FUNCTION','PROCEDURE') ORDER BY OBJECT_TYPE, OBJECT_NAME`
: "",
},
]);
case "duckdb":
return [
@@ -625,9 +636,17 @@ const buildSequencesMetadataQuerySpecs = (
return normalizeMetadataQuerySpecs([
{
sql: safeDbName
? `SELECT SEQUENCE_OWNER AS schema_name, SEQUENCE_NAME AS sequence_name FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = '${safeDbName.toUpperCase()}' ORDER BY SEQUENCE_NAME`
? `SELECT OWNER AS schema_name, OBJECT_NAME AS sequence_name FROM ALL_OBJECTS WHERE OWNER = '${safeDbName.toUpperCase()}' AND OBJECT_TYPE = 'SEQUENCE' ORDER BY OBJECT_NAME`
: `SELECT SEQUENCE_NAME AS sequence_name FROM USER_SEQUENCES ORDER BY SEQUENCE_NAME`,
},
{
// Some Oracle-compatible servers expose ALL_SEQUENCES only partially.
// ALL_OBJECTS is also the catalog used by packages and routines, while
// this keeps ALL_SEQUENCES as a fallback for standard Oracle servers.
sql: safeDbName
? `SELECT SEQUENCE_OWNER AS schema_name, SEQUENCE_NAME AS sequence_name FROM ALL_SEQUENCES WHERE SEQUENCE_OWNER = '${safeDbName.toUpperCase()}' ORDER BY SEQUENCE_NAME`
: "",
},
]);
default:
return [];