fix(gbase): load object source definitions
This commit is contained in:
1 parent
d3ac9805a4
commit
2bfa4c3234
2 files changed
+126
-1
No files matched your search
@@ -2,10 +2,12 @@ package com.dbx.agent.gbase8a;
|
|||||||
|
|
||||||
import com.dbx.agent.ConfiguredJdbcAgent;
|
import com.dbx.agent.ConfiguredJdbcAgent;
|
||||||
import com.dbx.agent.ExecuteQueryOptions;
|
import com.dbx.agent.ExecuteQueryOptions;
|
||||||
|
import com.dbx.agent.JdbcIdentifiers;
|
||||||
import com.dbx.agent.JdbcAgentProfile;
|
import com.dbx.agent.JdbcAgentProfile;
|
||||||
import com.dbx.agent.JsonRpcServer;
|
import com.dbx.agent.JsonRpcServer;
|
||||||
import com.dbx.agent.MetadataListConstraints;
|
import com.dbx.agent.MetadataListConstraints;
|
||||||
import com.dbx.agent.ObjectInfo;
|
import com.dbx.agent.ObjectInfo;
|
||||||
|
import com.dbx.agent.ObjectSource;
|
||||||
import com.dbx.agent.QueryPageOptions;
|
import com.dbx.agent.QueryPageOptions;
|
||||||
import com.dbx.agent.QueryPageResult;
|
import com.dbx.agent.QueryPageResult;
|
||||||
import com.dbx.agent.QueryResult;
|
import com.dbx.agent.QueryResult;
|
||||||
@@ -14,6 +16,8 @@ import com.dbx.agent.TableInfo;
|
|||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.ResultSetMetaData;
|
||||||
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -31,7 +35,7 @@ public final class Gbase8aAgent extends ConfiguredJdbcAgent {
|
|||||||
"USE",
|
"USE",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
false,
|
true,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -166,6 +170,40 @@ public final class Gbase8aAgent extends ConfiguredJdbcAgent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectSource getObjectSource(String schema, String name, String objectType) {
|
||||||
|
return unchecked(() -> {
|
||||||
|
String normalizedType = objectType.toUpperCase(Locale.ROOT);
|
||||||
|
String sql = switch (normalizedType) {
|
||||||
|
case "VIEW" -> "SHOW CREATE VIEW ";
|
||||||
|
case "PROCEDURE" -> "SHOW CREATE PROCEDURE ";
|
||||||
|
case "FUNCTION" -> "SHOW CREATE FUNCTION ";
|
||||||
|
default -> throw new IllegalArgumentException("Unsupported object type: " + objectType);
|
||||||
|
};
|
||||||
|
String qualifiedName = hasSchema(schema)
|
||||||
|
? JdbcIdentifiers.INSTANCE.backtick(schema) + "." + JdbcIdentifiers.INSTANCE.backtick(name)
|
||||||
|
: JdbcIdentifiers.INSTANCE.backtick(name);
|
||||||
|
|
||||||
|
String source = "";
|
||||||
|
try (Statement stmt = requireConnection().createStatement();
|
||||||
|
ResultSet rs = stmt.executeQuery(sql + qualifiedName)) {
|
||||||
|
if (rs.next()) {
|
||||||
|
// SHOW CREATE result layouts vary by GBase driver version, so locate the definition column by label.
|
||||||
|
ResultSetMetaData metadata = rs.getMetaData();
|
||||||
|
for (int index = 1; index <= metadata.getColumnCount(); index++) {
|
||||||
|
String label = metadata.getColumnLabel(index);
|
||||||
|
if (label != null && label.toUpperCase(Locale.ROOT).startsWith("CREATE ")) {
|
||||||
|
String value = rs.getString(index);
|
||||||
|
source = value == null ? "" : value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ObjectSource(name, normalizedType, schema, source);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static void appendGbase8aTableTypePredicate(
|
private static void appendGbase8aTableTypePredicate(
|
||||||
StringBuilder sql,
|
StringBuilder sql,
|
||||||
List<Object> args,
|
List<Object> args,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.dbx.agent.gbase8a;
|
|||||||
|
|
||||||
import com.dbx.agent.MetadataListConstraints;
|
import com.dbx.agent.MetadataListConstraints;
|
||||||
import com.dbx.agent.ObjectInfo;
|
import com.dbx.agent.ObjectInfo;
|
||||||
|
import com.dbx.agent.ObjectSource;
|
||||||
import com.dbx.agent.TableInfo;
|
import com.dbx.agent.TableInfo;
|
||||||
import com.dbx.agent.test.TestSupport;
|
import com.dbx.agent.test.TestSupport;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
@@ -13,6 +14,8 @@ import java.lang.reflect.Proxy;
|
|||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.ResultSetMetaData;
|
||||||
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -95,6 +98,57 @@ class Gbase8aAgentTest {
|
|||||||
Assertions.assertTrue(sql.get(0).contains("LIMIT ?"), sql.get(0));
|
Assertions.assertTrue(sql.get(0).contains("LIMIT ?"), sql.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getObjectSourceUsesShowCreateForRoutines() {
|
||||||
|
List<String> sql = new ArrayList<>();
|
||||||
|
Gbase8aAgent agent = new Gbase8aAgent();
|
||||||
|
TestSupport.setPrivateConnection(agent, statementConnection(sql, resultSet(
|
||||||
|
new String[]{"Procedure", "sql_mode", "Create Procedure"},
|
||||||
|
new Object[][]{{"refresh_orders", "", "CREATE PROCEDURE `refresh_orders`() SELECT 1"}}
|
||||||
|
)));
|
||||||
|
|
||||||
|
ObjectSource source = agent.getObjectSource("app", "refresh_orders", "procedure");
|
||||||
|
|
||||||
|
Assertions.assertEquals("PROCEDURE", source.getObject_type());
|
||||||
|
Assertions.assertEquals("app", source.getSchema());
|
||||||
|
Assertions.assertEquals("CREATE PROCEDURE `refresh_orders`() SELECT 1", source.getSource());
|
||||||
|
Assertions.assertEquals("SHOW CREATE PROCEDURE `app`.`refresh_orders`", sql.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getObjectSourceFindsDefinitionAcrossDriverResultLayouts() {
|
||||||
|
List<String> sql = new ArrayList<>();
|
||||||
|
Gbase8aAgent agent = new Gbase8aAgent();
|
||||||
|
TestSupport.setPrivateConnection(agent, statementConnection(sql, resultSet(
|
||||||
|
new String[]{"Function", "Create Function", "character_set_client", "Database Collation"},
|
||||||
|
new Object[][]{{"format_order", "CREATE FUNCTION `format_order`() RETURNS INT RETURN 1", "utf8", "utf8_bin"}}
|
||||||
|
)));
|
||||||
|
|
||||||
|
ObjectSource source = agent.getObjectSource("app`prod", "format`order", "FUNCTION");
|
||||||
|
|
||||||
|
Assertions.assertEquals("CREATE FUNCTION `format_order`() RETURNS INT RETURN 1", source.getSource());
|
||||||
|
Assertions.assertEquals("SHOW CREATE FUNCTION `app``prod`.`format``order`", sql.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getObjectSourceSupportsViewsAndRejectsOtherObjectTypes() {
|
||||||
|
List<String> sql = new ArrayList<>();
|
||||||
|
Gbase8aAgent agent = new Gbase8aAgent();
|
||||||
|
TestSupport.setPrivateConnection(agent, statementConnection(sql, resultSet(
|
||||||
|
new String[]{"View", "Create View"},
|
||||||
|
new Object[][]{{"active_orders", "CREATE VIEW `active_orders` AS SELECT 1"}}
|
||||||
|
)));
|
||||||
|
|
||||||
|
ObjectSource source = agent.getObjectSource("app", "active_orders", "VIEW");
|
||||||
|
|
||||||
|
Assertions.assertEquals("CREATE VIEW `active_orders` AS SELECT 1", source.getSource());
|
||||||
|
Assertions.assertEquals("SHOW CREATE VIEW `app`.`active_orders`", sql.get(0));
|
||||||
|
Assertions.assertThrows(
|
||||||
|
IllegalArgumentException.class,
|
||||||
|
() -> agent.getObjectSource("app", "orders", "TABLE")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static Connection preparedConnection(List<String> sql, ResultSet... resultSets) {
|
private static Connection preparedConnection(List<String> sql, ResultSet... resultSets) {
|
||||||
int[] resultSetIndex = {0};
|
int[] resultSetIndex = {0};
|
||||||
PreparedStatement statement = proxy(PreparedStatement.class, (method, args) -> {
|
PreparedStatement statement = proxy(PreparedStatement.class, (method, args) -> {
|
||||||
@@ -120,8 +174,39 @@ class Gbase8aAgentTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Connection statementConnection(List<String> sql, ResultSet resultSet) {
|
||||||
|
Statement statement = proxy(Statement.class, (method, args) -> {
|
||||||
|
if ("executeQuery".equals(method.getName())) {
|
||||||
|
sql.add(String.valueOf(args[0]));
|
||||||
|
return resultSet;
|
||||||
|
}
|
||||||
|
if ("close".equals(method.getName())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return defaultValue(method.getReturnType());
|
||||||
|
});
|
||||||
|
return proxy(Connection.class, (method, args) -> {
|
||||||
|
if ("createStatement".equals(method.getName())) {
|
||||||
|
return statement;
|
||||||
|
}
|
||||||
|
if ("isClosed".equals(method.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return defaultValue(method.getReturnType());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static ResultSet resultSet(String[] columns, Object[][] rows) {
|
private static ResultSet resultSet(String[] columns, Object[][] rows) {
|
||||||
int[] index = {-1};
|
int[] index = {-1};
|
||||||
|
ResultSetMetaData metadata = proxy(ResultSetMetaData.class, (method, args) -> {
|
||||||
|
if ("getColumnCount".equals(method.getName())) {
|
||||||
|
return columns.length;
|
||||||
|
}
|
||||||
|
if ("getColumnLabel".equals(method.getName())) {
|
||||||
|
return columns[((Number) args[0]).intValue() - 1];
|
||||||
|
}
|
||||||
|
return defaultValue(method.getReturnType());
|
||||||
|
});
|
||||||
return proxy(ResultSet.class, (method, args) -> {
|
return proxy(ResultSet.class, (method, args) -> {
|
||||||
switch (method.getName()) {
|
switch (method.getName()) {
|
||||||
case "next":
|
case "next":
|
||||||
@@ -130,6 +215,8 @@ class Gbase8aAgentTest {
|
|||||||
case "getString":
|
case "getString":
|
||||||
Object value = columnValue(columns, rows[index[0]], args[0]);
|
Object value = columnValue(columns, rows[index[0]], args[0]);
|
||||||
return value == null ? null : String.valueOf(value);
|
return value == null ? null : String.valueOf(value);
|
||||||
|
case "getMetaData":
|
||||||
|
return metadata;
|
||||||
case "close":
|
case "close":
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in new issue
Block a user