From 6c41bb4da1a1145db6994348f8753d16614ebbfa Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Sat, 1 Aug 2026 12:34:52 +0800 Subject: [PATCH] fix(dameng): fall back for restricted schema objects --- .../com/dbx/agent/dameng/DamengAgent.java | 77 ++++++++++----- .../agent/dameng/DamengAgentMetadataTest.java | 98 +++++++++++++++++++ 2 files changed, 153 insertions(+), 22 deletions(-) diff --git a/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java b/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java index 65df6982c..79f9aa039 100644 --- a/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java +++ b/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java @@ -576,33 +576,66 @@ public final class DamengAgent extends AbstractJdbcAgent { if (!includesSupportedObjectTypes(constraints)) { return List.of(); } + RuntimeException permissionError; try { return executeConstrainedObjects(schema, buildConstrainedObjectsQuery(schema, constraints), constraints); } catch (RuntimeException e) { - if (needsMaterializedViewClassification(constraints)) { - try { - return executeConstrainedObjects( - schema, - buildAccessibleConstrainedObjectsQuery(schema, constraints), - constraints - ); - } catch (RuntimeException ignored) { - // Fall through to owner-local and raw catalog fallbacks. - } + if (!isDamengMetadataPermissionError(e)) { + throw e; } - if (needsMaterializedViewClassification(constraints) && schemaMatchesConnectedUser(schema)) { - try { - return executeConstrainedObjects( - schema, - buildConstrainedObjectsQuery(schema, constraints, DAMENG_USER_MATERIALIZED_VIEW_JOIN_SQL), - constraints - ); - } catch (RuntimeException ignored) { - // Fall through to the raw catalog path below. - } - } - return executeRawConstrainedObjects(schema, constraints); + permissionError = e; } + if (needsMaterializedViewClassification(constraints)) { + try { + return executeConstrainedObjects( + schema, + buildAccessibleConstrainedObjectsQuery(schema, constraints), + constraints + ); + } catch (RuntimeException e) { + if (!isDamengMetadataPermissionError(e)) { + throw e; + } + permissionError.addSuppressed(e); + } + } + if (needsMaterializedViewClassification(constraints) && schemaMatchesConnectedUser(schema)) { + try { + return executeConstrainedObjects( + schema, + buildConstrainedObjectsQuery(schema, constraints, DAMENG_USER_MATERIALIZED_VIEW_JOIN_SQL), + constraints + ); + } catch (RuntimeException e) { + if (!isDamengMetadataPermissionError(e)) { + throw e; + } + permissionError.addSuppressed(e); + } + } + try { + return executeRawConstrainedObjects(schema, constraints); + } catch (RuntimeException e) { + if (!isDamengMetadataPermissionError(e)) { + throw e; + } + permissionError.addSuppressed(e); + } + try { + return executeJdbcMetadataObjects(schema, constraints); + } catch (RuntimeException e) { + e.addSuppressed(permissionError); + throw e; + } + } + + private List executeJdbcMetadataObjects(String schema, MetadataListConstraints constraints) { + if (!constraints.includesTableLikeTypes()) { + return List.of(); + } + return executeJdbcMetadataTables(schema, constraints).stream() + .map(table -> new ObjectInfo(table.getName(), table.getTable_type(), schema, table.getComment())) + .toList(); } private List executeConstrainedObjects( diff --git a/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentMetadataTest.java b/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentMetadataTest.java index 0fe6c69b1..585481e33 100644 --- a/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentMetadataTest.java +++ b/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentMetadataTest.java @@ -196,6 +196,104 @@ class DamengAgentMetadataTest { Assertions.assertEquals("用户示例表", objects.get(0).getComment()); } + @Test + void fallsBackToJdbcMetadataForRestrictedSchemaObjects() { + DamengAgent agent = new DamengAgent(); + List sqls = new ArrayList<>(); + List jdbcMetadataCalls = new ArrayList<>(); + TestSupport.setPrivateConnection(agent, restrictedTableConnection( + sqls, + jdbcMetadataCalls, + List.of( + List.of("VIEW_B", "VIEW", "view comment"), + List.of("TABLE_A", "TABLE", "table comment"), + List.of("MV_C", "MATERIALIZED VIEW", "mv comment"), + List.of("APP_PROC", "PROCEDURE", "procedure comment"), + List.of("MTAB$_INTERNAL", "TABLE", "internal table") + ), + null, + "没有[SYS.ALL_OBJECTS]对象的查询权限" + )); + setConnectedUsername(agent, "APP_DATA%2026"); + + List objects = agent.listObjects("APP_DATA%2026"); + + Assertions.assertEquals(List.of("MV_C", "TABLE_A", "VIEW_B"), objects.stream().map(ObjectInfo::getName).toList()); + Assertions.assertEquals(List.of("MATERIALIZED_VIEW", "TABLE", "VIEW"), objects.stream().map(ObjectInfo::getObject_type).toList()); + Assertions.assertEquals(List.of("APP_DATA%2026", "APP_DATA%2026", "APP_DATA%2026"), objects.stream().map(ObjectInfo::getSchema).toList()); + Assertions.assertEquals(List.of("mv comment", "table comment", "view comment"), objects.stream().map(ObjectInfo::getComment).toList()); + Assertions.assertEquals(4, sqls.size(), String.join("\n", sqls)); + Assertions.assertTrue(sqls.stream().allMatch(sql -> sql.contains("ALL_OBJECTS")), String.join("\n", sqls)); + Assertions.assertEquals(List.of("catalog=null,schema=APP\\_DATA\\%2026,table=%,types=null"), jdbcMetadataCalls); + } + + @Test + void appliesConstraintsToRestrictedSchemaObjectFallback() { + DamengAgent agent = new DamengAgent(); + TestSupport.setPrivateConnection(agent, restrictedTableConnection( + new ArrayList<>(), + new ArrayList<>(), + List.of( + List.of("VIEW_B", "VIEW", "keep view"), + List.of("TABLE_A", "TABLE", "keep table"), + List.of("TABLE_Z", "TABLE", "other"), + List.of("MV_C", "MATERIALIZED VIEW", "keep materialized view") + ), + null, + "no SYS.ALL_OBJECTS privilege" + )); + MetadataListConstraints constraints = new MetadataListConstraints( + "keep", + 1, + 1, + List.of("TABLE", "VIEW") + ); + + List objects = agent.listObjects("APP", constraints); + + Assertions.assertEquals(1, objects.size()); + Assertions.assertEquals("VIEW_B", objects.get(0).getName()); + Assertions.assertEquals("VIEW", objects.get(0).getObject_type()); + Assertions.assertEquals("keep view", objects.get(0).getComment()); + } + + @Test + void doesNotFallbackForNonPermissionObjectMetadataErrors() { + DamengAgent agent = new DamengAgent(); + List sqls = new ArrayList<>(); + List jdbcMetadataCalls = new ArrayList<>(); + TestSupport.setPrivateConnection(agent, restrictedTableConnection( + sqls, + jdbcMetadataCalls, + List.of(), + null, + "ALL_OBJECTS metadata query timed out" + )); + + RuntimeException error = Assertions.assertThrows(RuntimeException.class, () -> agent.listObjects("APP")); + + Assertions.assertEquals("ALL_OBJECTS metadata query timed out", error.getCause().getMessage()); + Assertions.assertEquals(1, sqls.size(), String.join("\n", sqls)); + Assertions.assertTrue(jdbcMetadataCalls.isEmpty(), jdbcMetadataCalls.toString()); + } + + @Test + void propagatesJdbcMetadataObjectFallbackErrors() { + DamengAgent agent = new DamengAgent(); + TestSupport.setPrivateConnection(agent, restrictedTableConnection( + new ArrayList<>(), + new ArrayList<>(), + List.of(), + new SQLException("JDBC metadata getTables failed"), + "没有[SYS.ALL_OBJECTS]对象的查询权限" + )); + + RuntimeException error = Assertions.assertThrows(RuntimeException.class, () -> agent.listObjects("APP")); + + Assertions.assertEquals("JDBC metadata getTables failed", error.getCause().getMessage()); + Assertions.assertEquals(1, error.getSuppressed().length); + } + @Test void listSchemasIncludesSchemaObjectsWithoutChildren() { DamengAgent agent = new DamengAgent();