mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 06:00:39 +00:00
feat(oceanbase-oracle): append object grants in table DDL
This commit is contained in:
@@ -219,6 +219,118 @@ public final class DdlBuilder {
|
||||
return ddl.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends trailing SQL (e.g. GRANT statements) after a CREATE TABLE DDL script.
|
||||
* Returns the original DDL unchanged when {@code trailingSql} is blank.
|
||||
*/
|
||||
public static String appendTrailingSql(String ddl, String trailingSql) {
|
||||
if (!notBlank(trailingSql)) {
|
||||
return ddl == null ? "" : ddl;
|
||||
}
|
||||
String base = ddl == null ? "" : ddl.trim();
|
||||
if (base.isEmpty()) {
|
||||
return trailingSql.trim();
|
||||
}
|
||||
if (!base.endsWith(";")) {
|
||||
base = base + ";";
|
||||
}
|
||||
String grants = trailingSql.trim();
|
||||
return base + "\n\n" + grants + (grants.endsWith(";") ? "" : ";");
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds Oracle-style object GRANT statements for table and column privileges.
|
||||
* Privileges are grouped by grantee / grantable / privilege(+columns).
|
||||
*/
|
||||
public static String buildOracleObjectGrantSql(
|
||||
String schema,
|
||||
String table,
|
||||
List<OracleObjectPrivilege> privileges
|
||||
) {
|
||||
if (privileges == null || privileges.isEmpty() || !notBlank(table)) {
|
||||
return "";
|
||||
}
|
||||
String tableRef = qualifiedName(schema, table, false);
|
||||
|
||||
Map<String, List<String>> tablePrivileges = new LinkedHashMap<>();
|
||||
Map<String, List<String>> columnPrivileges = new LinkedHashMap<>();
|
||||
for (OracleObjectPrivilege privilege : privileges) {
|
||||
if (privilege == null || !notBlank(privilege.grantee()) || !notBlank(privilege.privilege())) {
|
||||
continue;
|
||||
}
|
||||
String privilegeName = privilege.privilege().trim().toUpperCase(Locale.ROOT);
|
||||
String grantableKey = privilege.grantable() ? "1" : "0";
|
||||
if (notBlank(privilege.columnName())) {
|
||||
String key = privilege.grantee() + "\u0000" + privilegeName + "\u0000" + grantableKey;
|
||||
columnPrivileges
|
||||
.computeIfAbsent(key, ignored -> new ArrayList<>())
|
||||
.add(privilege.columnName().trim());
|
||||
} else {
|
||||
String key = privilege.grantee() + "\u0000" + grantableKey;
|
||||
List<String> names = tablePrivileges.computeIfAbsent(key, ignored -> new ArrayList<>());
|
||||
if (!names.contains(privilegeName)) {
|
||||
names.add(privilegeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> statements = new ArrayList<>();
|
||||
for (Map.Entry<String, List<String>> entry : tablePrivileges.entrySet()) {
|
||||
String[] parts = entry.getKey().split("\u0000", -1);
|
||||
String grantee = parts[0];
|
||||
boolean grantable = "1".equals(parts[1]);
|
||||
statements.add(formatOracleGrant(
|
||||
join(entry.getValue(), ", "),
|
||||
null,
|
||||
tableRef,
|
||||
grantee,
|
||||
grantable
|
||||
));
|
||||
}
|
||||
for (Map.Entry<String, List<String>> entry : columnPrivileges.entrySet()) {
|
||||
String[] parts = entry.getKey().split("\u0000", -1);
|
||||
String grantee = parts[0];
|
||||
String privilegeName = parts[1];
|
||||
boolean grantable = "1".equals(parts[2]);
|
||||
List<String> columns = new ArrayList<>();
|
||||
for (String column : entry.getValue()) {
|
||||
String quoted = quoteIdent(column, false);
|
||||
if (!columns.contains(quoted)) {
|
||||
columns.add(quoted);
|
||||
}
|
||||
}
|
||||
statements.add(formatOracleGrant(
|
||||
privilegeName,
|
||||
join(columns, ", "),
|
||||
tableRef,
|
||||
grantee,
|
||||
grantable
|
||||
));
|
||||
}
|
||||
return join(statements, "\n");
|
||||
}
|
||||
|
||||
private static String formatOracleGrant(
|
||||
String privilegeList,
|
||||
String columnList,
|
||||
String tableRef,
|
||||
String grantee,
|
||||
boolean grantable
|
||||
) {
|
||||
StringBuilder statement = new StringBuilder("GRANT ");
|
||||
statement.append(privilegeList);
|
||||
if (notBlank(columnList)) {
|
||||
statement.append(" (").append(columnList).append(")");
|
||||
}
|
||||
statement.append(" ON ").append(tableRef);
|
||||
statement.append(" TO ").append(quoteIdent(grantee, false));
|
||||
if (grantable) {
|
||||
statement.append(" WITH GRANT OPTION");
|
||||
}
|
||||
statement.append(";");
|
||||
return statement.toString();
|
||||
}
|
||||
|
||||
private static List<ForeignKeyGroup> groupForeignKeys(List<ForeignKeyInfo> foreignKeys) {
|
||||
List<ForeignKeyGroup> result = new ArrayList<>();
|
||||
Map<String, ForeignKeyGroup> namedGroups = new LinkedHashMap<>();
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.dbx.agent;
|
||||
|
||||
/**
|
||||
* Oracle-compatible object privilege row used when reconstructing GRANT DDL.
|
||||
*/
|
||||
public final class OracleObjectPrivilege {
|
||||
private final String grantee;
|
||||
private final String privilege;
|
||||
private final boolean grantable;
|
||||
private final String columnName;
|
||||
|
||||
public OracleObjectPrivilege(String grantee, String privilege, boolean grantable) {
|
||||
this(grantee, privilege, grantable, null);
|
||||
}
|
||||
|
||||
public OracleObjectPrivilege(String grantee, String privilege, boolean grantable, String columnName) {
|
||||
this.grantee = grantee;
|
||||
this.privilege = privilege;
|
||||
this.grantable = grantable;
|
||||
this.columnName = columnName;
|
||||
}
|
||||
|
||||
public String grantee() {
|
||||
return grantee;
|
||||
}
|
||||
|
||||
public String privilege() {
|
||||
return privilege;
|
||||
}
|
||||
|
||||
public boolean grantable() {
|
||||
return grantable;
|
||||
}
|
||||
|
||||
public String columnName() {
|
||||
return columnName;
|
||||
}
|
||||
}
|
||||
@@ -750,6 +750,36 @@ class CommonJavaCompatibilityTest {
|
||||
assertTrue(ddl.contains("\"NAME\" NVARCHAR(100) NOT NULL"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void appendsOracleObjectGrantSqlAfterTableDdl() {
|
||||
String ddl = DdlBuilder.buildTableDdl(
|
||||
"APP",
|
||||
"USERS",
|
||||
Collections.singletonList(new ColumnInfo("ID", "NUMBER", false, null, true)),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList()
|
||||
);
|
||||
String grants = DdlBuilder.buildOracleObjectGrantSql(
|
||||
"APP",
|
||||
"USERS",
|
||||
Arrays.asList(
|
||||
new OracleObjectPrivilege("READER", "SELECT", false),
|
||||
new OracleObjectPrivilege("READER", "INSERT", false),
|
||||
new OracleObjectPrivilege("ADMIN", "SELECT", true),
|
||||
new OracleObjectPrivilege("ANALYST", "UPDATE", false, "NAME")
|
||||
)
|
||||
);
|
||||
|
||||
String combined = DdlBuilder.appendTrailingSql(ddl, grants);
|
||||
|
||||
assertTrue(combined.contains("CREATE TABLE \"APP\".\"USERS\""));
|
||||
assertTrue(combined.contains("GRANT SELECT, INSERT ON \"APP\".\"USERS\" TO \"READER\";"));
|
||||
assertTrue(combined.contains("GRANT SELECT ON \"APP\".\"USERS\" TO \"ADMIN\" WITH GRANT OPTION;"));
|
||||
assertTrue(combined.contains("GRANT UPDATE (\"NAME\") ON \"APP\".\"USERS\" TO \"ANALYST\";"));
|
||||
assertEquals("", DdlBuilder.buildOracleObjectGrantSql("APP", "USERS", Collections.emptyList()));
|
||||
assertEquals(ddl, DdlBuilder.appendTrailingSql(ddl, " "));
|
||||
}
|
||||
|
||||
private static class MinimalAgent implements DatabaseAgent {
|
||||
@Override
|
||||
public void connect(ConnectParams params) {
|
||||
|
||||
+136
-1
@@ -14,6 +14,7 @@ import com.dbx.agent.MultiSessionJsonRpcServer;
|
||||
import com.dbx.agent.MetadataListConstraints;
|
||||
import com.dbx.agent.ObjectInfo;
|
||||
import com.dbx.agent.ObjectSource;
|
||||
import com.dbx.agent.OracleObjectPrivilege;
|
||||
import com.dbx.agent.TableInfo;
|
||||
import com.dbx.agent.TriggerInfo;
|
||||
|
||||
@@ -556,7 +557,141 @@ public final class OceanBaseOracleAgent extends ConfiguredJdbcAgent {
|
||||
// Table comment is optional; DDL generation should still succeed without it.
|
||||
}
|
||||
|
||||
return DdlBuilder.buildTableDdl(schema, table, getColumns(schema, table), indexes, foreignKeys, java.util.Collections.emptyList(), false, true, tableComment);
|
||||
String ddl = DdlBuilder.buildTableDdl(
|
||||
schema,
|
||||
table,
|
||||
getColumns(schema, table),
|
||||
indexes,
|
||||
foreignKeys,
|
||||
java.util.Collections.emptyList(),
|
||||
false,
|
||||
true,
|
||||
tableComment
|
||||
);
|
||||
try {
|
||||
String owner = normalizeSchema(schema);
|
||||
return DdlBuilder.appendTrailingSql(ddl, queryObjectGrantSql(owner, table));
|
||||
} catch (RuntimeException | SQLException ignored) {
|
||||
// Privilege metadata is optional; CREATE TABLE DDL should still succeed without it.
|
||||
return ddl;
|
||||
}
|
||||
}
|
||||
|
||||
private String queryObjectGrantSql(String owner, String table) throws SQLException {
|
||||
List<OracleObjectPrivilege> privileges = new ArrayList<>();
|
||||
privileges.addAll(queryTablePrivileges(owner, table));
|
||||
try {
|
||||
privileges.addAll(queryColumnPrivileges(owner, table));
|
||||
} catch (SQLException ignored) {
|
||||
// Column privileges are optional when table-level grants are available.
|
||||
}
|
||||
return DdlBuilder.buildOracleObjectGrantSql(owner, table, privileges);
|
||||
}
|
||||
|
||||
private List<OracleObjectPrivilege> queryTablePrivileges(String owner, String table) throws SQLException {
|
||||
// DBA_TAB_PRIVS shows every object grant (OWNER column). ALL_TAB_PRIVS is limited to
|
||||
// grants where the session user is owner/grantor/grantee (or PUBLIC), so admins
|
||||
// browsing another schema often see nothing unless we prefer the DBA view.
|
||||
return queryFirstAvailablePrivileges(tablePrivilegeQueries(), owner, table, null);
|
||||
}
|
||||
|
||||
private List<OracleObjectPrivilege> queryColumnPrivileges(String owner, String table) throws SQLException {
|
||||
return queryFirstAvailablePrivileges(columnPrivilegeQueries(), owner, table, "COLUMN_NAME");
|
||||
}
|
||||
|
||||
private List<OracleObjectPrivilege> queryFirstAvailablePrivileges(
|
||||
List<String> queries,
|
||||
String owner,
|
||||
String table,
|
||||
String columnNameField
|
||||
) throws SQLException {
|
||||
SQLException firstError = null;
|
||||
for (String sql : queries) {
|
||||
try {
|
||||
return queryPrivileges(sql, owner, table, columnNameField);
|
||||
} catch (SQLException error) {
|
||||
if (firstError == null) {
|
||||
firstError = error;
|
||||
} else {
|
||||
firstError.addSuppressed(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw firstError == null ? new SQLException("No privilege views available") : firstError;
|
||||
}
|
||||
|
||||
private static List<String> tablePrivilegeQueries() {
|
||||
return List.of(
|
||||
"""
|
||||
SELECT GRANTEE, PRIVILEGE, GRANTABLE
|
||||
FROM DBA_TAB_PRIVS
|
||||
WHERE OWNER = ? AND TABLE_NAME = ?
|
||||
ORDER BY GRANTEE, PRIVILEGE
|
||||
""".stripIndent().trim(),
|
||||
"""
|
||||
SELECT GRANTEE, PRIVILEGE, GRANTABLE
|
||||
FROM SYS.DBA_TAB_PRIVS
|
||||
WHERE OWNER = ? AND TABLE_NAME = ?
|
||||
ORDER BY GRANTEE, PRIVILEGE
|
||||
""".stripIndent().trim(),
|
||||
"""
|
||||
SELECT GRANTEE, PRIVILEGE, GRANTABLE
|
||||
FROM ALL_TAB_PRIVS
|
||||
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
||||
ORDER BY GRANTEE, PRIVILEGE
|
||||
""".stripIndent().trim()
|
||||
);
|
||||
}
|
||||
|
||||
private static List<String> columnPrivilegeQueries() {
|
||||
return List.of(
|
||||
"""
|
||||
SELECT GRANTEE, PRIVILEGE, GRANTABLE, COLUMN_NAME
|
||||
FROM DBA_COL_PRIVS
|
||||
WHERE OWNER = ? AND TABLE_NAME = ?
|
||||
ORDER BY GRANTEE, COLUMN_NAME, PRIVILEGE
|
||||
""".stripIndent().trim(),
|
||||
"""
|
||||
SELECT GRANTEE, PRIVILEGE, GRANTABLE, COLUMN_NAME
|
||||
FROM SYS.DBA_COL_PRIVS
|
||||
WHERE OWNER = ? AND TABLE_NAME = ?
|
||||
ORDER BY GRANTEE, COLUMN_NAME, PRIVILEGE
|
||||
""".stripIndent().trim(),
|
||||
"""
|
||||
SELECT GRANTEE, PRIVILEGE, GRANTABLE, COLUMN_NAME
|
||||
FROM ALL_COL_PRIVS
|
||||
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
||||
ORDER BY GRANTEE, COLUMN_NAME, PRIVILEGE
|
||||
""".stripIndent().trim()
|
||||
);
|
||||
}
|
||||
|
||||
private List<OracleObjectPrivilege> queryPrivileges(
|
||||
String sql,
|
||||
String owner,
|
||||
String table,
|
||||
String columnNameField
|
||||
) throws SQLException {
|
||||
List<OracleObjectPrivilege> result = new ArrayList<>();
|
||||
try (var stmt = requireConnection().prepareStatement(sql)) {
|
||||
stmt.setString(1, owner);
|
||||
stmt.setString(2, table);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
result.add(new OracleObjectPrivilege(
|
||||
rs.getString("GRANTEE"),
|
||||
rs.getString("PRIVILEGE"),
|
||||
isYes(rs.getString("GRANTABLE")),
|
||||
columnNameField == null ? null : rs.getString(columnNameField)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isYes(String value) {
|
||||
return value != null && "YES".equalsIgnoreCase(value.trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+239
-1
@@ -439,7 +439,15 @@ class OceanBaseOracleAgentTest {
|
||||
columnResultSet(new Object[][]{
|
||||
{"CREATED_AT", "TIMESTAMP", "N", null, null, null, null, "SYSDATE", "Created timestamp", 0},
|
||||
{"INTERNAL_NOTE", "VARCHAR2", "Y", null, null, 100, 100, null, " ", 0}
|
||||
})
|
||||
}),
|
||||
resultSet(
|
||||
new String[]{"GRANTEE", "PRIVILEGE", "GRANTABLE"},
|
||||
new Object[][]{}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"GRANTEE", "COLUMN_NAME", "PRIVILEGE", "GRANTABLE"},
|
||||
new Object[][]{}
|
||||
)
|
||||
));
|
||||
|
||||
String ddl = agent.getTableDdl("APP", "AUDIT_LOG");
|
||||
@@ -451,6 +459,147 @@ class OceanBaseOracleAgentTest {
|
||||
);
|
||||
Assertions.assertTrue(ddl.contains("\"INTERNAL_NOTE\" VARCHAR2(100)"), ddl);
|
||||
Assertions.assertFalse(ddl.contains("\"INTERNAL_NOTE\" IS"), ddl);
|
||||
Assertions.assertFalse(ddl.contains("GRANT "), ddl);
|
||||
}
|
||||
|
||||
@Test
|
||||
void tableDdlAppendsObjectGrantsFromDictionaryViews() {
|
||||
List<String> sql = new ArrayList<>();
|
||||
OceanBaseOracleAgent agent = new OceanBaseOracleAgent();
|
||||
TestSupport.setPrivateConnection(agent, preparedConnection(sql,
|
||||
resultSet(
|
||||
new String[]{"INDEX_NAME", "COLUMN_NAME", "COLUMN_POSITION", "UNIQUENESS", "CONSTRAINT_TYPE", "INDEX_TYPE"},
|
||||
new Object[][]{}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"CONSTRAINT_NAME", "COLUMN_NAME", "TABLE_NAME", "REF_COLUMN_NAME"},
|
||||
new Object[][]{}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"COMMENTS"},
|
||||
new Object[][]{{null}}
|
||||
),
|
||||
columnResultSet(new Object[][]{
|
||||
{"ID", "NUMBER", "N", 19, 0, null, null, null, null, 1},
|
||||
{"NAME", "VARCHAR2", "Y", null, null, 100, 100, null, null, 0}
|
||||
}),
|
||||
resultSet(
|
||||
new String[]{"GRANTEE", "PRIVILEGE", "GRANTABLE"},
|
||||
new Object[][]{
|
||||
{"READER", "SELECT", "NO"},
|
||||
{"READER", "INSERT", "NO"},
|
||||
{"ADMIN", "SELECT", "YES"}
|
||||
}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"GRANTEE", "COLUMN_NAME", "PRIVILEGE", "GRANTABLE"},
|
||||
new Object[][]{
|
||||
{"ANALYST", "NAME", "UPDATE", "NO"}
|
||||
}
|
||||
)
|
||||
));
|
||||
|
||||
String ddl = agent.getTableDdl("APP", "USERS");
|
||||
|
||||
Assertions.assertTrue(ddl.contains("CREATE TABLE \"APP\".\"USERS\""), ddl);
|
||||
Assertions.assertTrue(ddl.contains("GRANT SELECT, INSERT ON \"APP\".\"USERS\" TO \"READER\";"), ddl);
|
||||
Assertions.assertTrue(
|
||||
ddl.contains("GRANT SELECT ON \"APP\".\"USERS\" TO \"ADMIN\" WITH GRANT OPTION;"),
|
||||
ddl
|
||||
);
|
||||
Assertions.assertTrue(
|
||||
ddl.contains("GRANT UPDATE (\"NAME\") ON \"APP\".\"USERS\" TO \"ANALYST\";"),
|
||||
ddl
|
||||
);
|
||||
Assertions.assertTrue(
|
||||
sql.stream().anyMatch(statement -> statement.toUpperCase(Locale.ROOT).contains("FROM DBA_TAB_PRIVS")),
|
||||
String.valueOf(sql)
|
||||
);
|
||||
Assertions.assertTrue(
|
||||
sql.stream().anyMatch(statement -> statement.toUpperCase(Locale.ROOT).contains("FROM DBA_COL_PRIVS")),
|
||||
String.valueOf(sql)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void tableDdlFallsBackToAllTabPrivsWhenDbaViewUnavailable() {
|
||||
List<String> sql = new ArrayList<>();
|
||||
OceanBaseOracleAgent agent = new OceanBaseOracleAgent();
|
||||
TestSupport.setPrivateConnection(agent, dbaFallbackPrivilegeConnection(sql,
|
||||
resultSet(
|
||||
new String[]{"INDEX_NAME", "COLUMN_NAME", "COLUMN_POSITION", "UNIQUENESS", "CONSTRAINT_TYPE", "INDEX_TYPE"},
|
||||
new Object[][]{}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"CONSTRAINT_NAME", "COLUMN_NAME", "TABLE_NAME", "REF_COLUMN_NAME"},
|
||||
new Object[][]{}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"COMMENTS"},
|
||||
new Object[][]{{null}}
|
||||
),
|
||||
columnResultSet(new Object[][]{
|
||||
{"ID", "NUMBER", "N", 19, 0, null, null, null, null, 1}
|
||||
}),
|
||||
resultSet(
|
||||
new String[]{"GRANTEE", "PRIVILEGE", "GRANTABLE"},
|
||||
new Object[][]{
|
||||
{"READER", "SELECT", "NO"}
|
||||
}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"GRANTEE", "COLUMN_NAME", "PRIVILEGE", "GRANTABLE"},
|
||||
new Object[][]{}
|
||||
)
|
||||
));
|
||||
|
||||
String ddl = agent.getTableDdl("APP", "USERS");
|
||||
|
||||
Assertions.assertTrue(ddl.contains("GRANT SELECT ON \"APP\".\"USERS\" TO \"READER\";"), ddl);
|
||||
Assertions.assertTrue(
|
||||
sql.stream().anyMatch(statement -> statement.toUpperCase(Locale.ROOT).contains("FROM DBA_TAB_PRIVS")),
|
||||
String.valueOf(sql)
|
||||
);
|
||||
Assertions.assertTrue(
|
||||
sql.stream().anyMatch(statement -> statement.toUpperCase(Locale.ROOT).contains("FROM ALL_TAB_PRIVS")),
|
||||
String.valueOf(sql)
|
||||
);
|
||||
Assertions.assertTrue(
|
||||
sql.stream().anyMatch(statement -> statement.toUpperCase(Locale.ROOT).contains("FROM SYS.DBA_TAB_PRIVS")),
|
||||
String.valueOf(sql)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void tableDdlKeepsCreateTableWhenPrivilegeQueriesFail() {
|
||||
List<String> sql = new ArrayList<>();
|
||||
OceanBaseOracleAgent agent = new OceanBaseOracleAgent();
|
||||
TestSupport.setPrivateConnection(agent, privilegeFailingDdlConnection(sql,
|
||||
resultSet(
|
||||
new String[]{"INDEX_NAME", "COLUMN_NAME", "COLUMN_POSITION", "UNIQUENESS", "CONSTRAINT_TYPE", "INDEX_TYPE"},
|
||||
new Object[][]{}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"CONSTRAINT_NAME", "COLUMN_NAME", "TABLE_NAME", "REF_COLUMN_NAME"},
|
||||
new Object[][]{}
|
||||
),
|
||||
resultSet(
|
||||
new String[]{"COMMENTS"},
|
||||
new Object[][]{{null}}
|
||||
),
|
||||
columnResultSet(new Object[][]{
|
||||
{"ID", "NUMBER", "N", 19, 0, null, null, null, null, 1}
|
||||
})
|
||||
));
|
||||
|
||||
String ddl = agent.getTableDdl("APP", "USERS");
|
||||
|
||||
Assertions.assertTrue(ddl.contains("CREATE TABLE \"APP\".\"USERS\""), ddl);
|
||||
Assertions.assertFalse(ddl.contains("GRANT "), ddl);
|
||||
Assertions.assertTrue(
|
||||
sql.stream().anyMatch(statement -> statement.toUpperCase(Locale.ROOT).contains("FROM DBA_TAB_PRIVS")),
|
||||
String.valueOf(sql)
|
||||
);
|
||||
}
|
||||
|
||||
private static ResultSet columnResultSet(Object[][] rows) {
|
||||
@@ -496,6 +645,95 @@ class OceanBaseOracleAgentTest {
|
||||
});
|
||||
}
|
||||
|
||||
private static Connection privilegeFailingDdlConnection(List<String> sql, ResultSet... resultSets) {
|
||||
int[] resultSetIndex = {0};
|
||||
return proxy(Connection.class, (method, args) -> {
|
||||
if ("prepareStatement".equals(method.getName())) {
|
||||
String statementSql = String.valueOf(args[0]);
|
||||
sql.add(statementSql);
|
||||
String normalized = statementSql.toUpperCase(Locale.ROOT);
|
||||
if (normalized.contains("DBA_TAB_PRIVS")
|
||||
|| normalized.contains("ALL_TAB_PRIVS")
|
||||
|| normalized.contains("DBA_COL_PRIVS")
|
||||
|| normalized.contains("ALL_COL_PRIVS")) {
|
||||
PreparedStatement failing = proxy(PreparedStatement.class, (statementMethod, statementArgs) -> {
|
||||
if ("executeQuery".equals(statementMethod.getName())) {
|
||||
throw new SQLException("privilege view unavailable");
|
||||
}
|
||||
if ("setString".equals(statementMethod.getName())
|
||||
|| "setInt".equals(statementMethod.getName())
|
||||
|| "close".equals(statementMethod.getName())) {
|
||||
return null;
|
||||
}
|
||||
return defaultValue(statementMethod.getReturnType());
|
||||
});
|
||||
return failing;
|
||||
}
|
||||
PreparedStatement statement = proxy(PreparedStatement.class, (statementMethod, statementArgs) -> {
|
||||
if ("executeQuery".equals(statementMethod.getName())) {
|
||||
int current = Math.min(resultSetIndex[0], resultSets.length - 1);
|
||||
resultSetIndex[0] += 1;
|
||||
return resultSets[current];
|
||||
}
|
||||
if ("setString".equals(statementMethod.getName())
|
||||
|| "setInt".equals(statementMethod.getName())
|
||||
|| "close".equals(statementMethod.getName())) {
|
||||
return null;
|
||||
}
|
||||
return defaultValue(statementMethod.getReturnType());
|
||||
});
|
||||
return statement;
|
||||
}
|
||||
if ("isClosed".equals(method.getName())) {
|
||||
return false;
|
||||
}
|
||||
return defaultValue(method.getReturnType());
|
||||
});
|
||||
}
|
||||
|
||||
private static Connection dbaFallbackPrivilegeConnection(List<String> sql, ResultSet... resultSets) {
|
||||
int[] resultSetIndex = {0};
|
||||
return proxy(Connection.class, (method, args) -> {
|
||||
if ("prepareStatement".equals(method.getName())) {
|
||||
String statementSql = String.valueOf(args[0]);
|
||||
sql.add(statementSql);
|
||||
String normalized = statementSql.toUpperCase(Locale.ROOT);
|
||||
if (normalized.contains("DBA_TAB_PRIVS") || normalized.contains("DBA_COL_PRIVS")) {
|
||||
PreparedStatement failing = proxy(PreparedStatement.class, (statementMethod, statementArgs) -> {
|
||||
if ("executeQuery".equals(statementMethod.getName())) {
|
||||
throw new SQLException("DBA privilege view unavailable");
|
||||
}
|
||||
if ("setString".equals(statementMethod.getName())
|
||||
|| "setInt".equals(statementMethod.getName())
|
||||
|| "close".equals(statementMethod.getName())) {
|
||||
return null;
|
||||
}
|
||||
return defaultValue(statementMethod.getReturnType());
|
||||
});
|
||||
return failing;
|
||||
}
|
||||
PreparedStatement statement = proxy(PreparedStatement.class, (statementMethod, statementArgs) -> {
|
||||
if ("executeQuery".equals(statementMethod.getName())) {
|
||||
int current = Math.min(resultSetIndex[0], resultSets.length - 1);
|
||||
resultSetIndex[0] += 1;
|
||||
return resultSets[current];
|
||||
}
|
||||
if ("setString".equals(statementMethod.getName())
|
||||
|| "setInt".equals(statementMethod.getName())
|
||||
|| "close".equals(statementMethod.getName())) {
|
||||
return null;
|
||||
}
|
||||
return defaultValue(statementMethod.getReturnType());
|
||||
});
|
||||
return statement;
|
||||
}
|
||||
if ("isClosed".equals(method.getName())) {
|
||||
return false;
|
||||
}
|
||||
return defaultValue(method.getReturnType());
|
||||
});
|
||||
}
|
||||
|
||||
private static Connection schemaConnection(List<String> sql, ResultSet resultSet) {
|
||||
Statement statement = proxy(Statement.class, (method, args) -> {
|
||||
if ("executeQuery".equals(method.getName())) {
|
||||
|
||||
Reference in New Issue
Block a user