feat(desktop): add database info and SQL statement markers
This commit is contained in:
60 files changed
+2403
-134
No files matched your search
@@ -9,7 +9,9 @@ import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractJdbcAgent extends BaseDatabaseAgent {
|
||||
private Connection connection;
|
||||
@@ -42,14 +44,33 @@ public abstract class AbstractJdbcAgent extends BaseDatabaseAgent {
|
||||
|
||||
@Override
|
||||
public final boolean testConnection(ConnectParams params) {
|
||||
return Boolean.TRUE.equals(testConnectionWithInfo(params).get("ok"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Map<String, Object> testConnectionWithInfo(ConnectParams params) {
|
||||
return unchecked(() -> {
|
||||
loadDriver(params);
|
||||
try (Connection conn = openConnection(params)) {
|
||||
return conn.isValid(5);
|
||||
boolean valid = conn.isValid(5);
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("ok", valid);
|
||||
if (valid) {
|
||||
Map<String, String> databaseInfo = JdbcDatabaseInfo.from(conn);
|
||||
if (!databaseInfo.isEmpty()) {
|
||||
result.put("databaseInfo", databaseInfo);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Map<String, String> getDatabaseInfo() {
|
||||
return JdbcDatabaseInfo.from(getConnection());
|
||||
}
|
||||
|
||||
private void loadDriver(ConnectParams params) throws Exception {
|
||||
List<String> driverPaths = params.getJdbc_driver_paths();
|
||||
String driverClass = params.getJdbc_driver_class();
|
||||
|
||||
@@ -4,7 +4,9 @@ import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -13,6 +15,16 @@ public interface DatabaseAgent {
|
||||
|
||||
boolean testConnection(ConnectParams params);
|
||||
|
||||
default Map<String, Object> testConnectionWithInfo(ConnectParams params) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("ok", testConnection(params));
|
||||
return result;
|
||||
}
|
||||
|
||||
default Map<String, String> getDatabaseInfo() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
default String getIdentifierQuote() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.dbx.agent;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
final class JdbcDatabaseInfo {
|
||||
private JdbcDatabaseInfo() {
|
||||
}
|
||||
|
||||
static Map<String, String> from(Connection connection) {
|
||||
if (connection == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final DatabaseMetaData metadata;
|
||||
try {
|
||||
metadata = connection.getMetaData();
|
||||
} catch (SQLException | AbstractMethodError | UnsupportedOperationException ignored) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (metadata == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> info = new LinkedHashMap<>();
|
||||
putText(info, "productName", () -> metadata.getDatabaseProductName());
|
||||
putText(info, "productVersion", () -> metadata.getDatabaseProductVersion());
|
||||
putIdentifierCase(
|
||||
info,
|
||||
"unquotedIdentifierCase",
|
||||
() -> metadata.storesLowerCaseIdentifiers(),
|
||||
() -> metadata.storesUpperCaseIdentifiers(),
|
||||
() -> metadata.storesMixedCaseIdentifiers()
|
||||
);
|
||||
putIdentifierCase(
|
||||
info,
|
||||
"quotedIdentifierCase",
|
||||
() -> metadata.storesLowerCaseQuotedIdentifiers(),
|
||||
() -> metadata.storesUpperCaseQuotedIdentifiers(),
|
||||
() -> metadata.storesMixedCaseQuotedIdentifiers()
|
||||
);
|
||||
putText(info, "driverName", () -> metadata.getDriverName());
|
||||
putText(info, "driverVersion", () -> metadata.getDriverVersion());
|
||||
|
||||
Integer jdbcMajor = readInteger(() -> metadata.getJDBCMajorVersion());
|
||||
Integer jdbcMinor = readInteger(() -> metadata.getJDBCMinorVersion());
|
||||
if (jdbcMajor != null && jdbcMinor != null && jdbcMajor >= 0 && jdbcMinor >= 0) {
|
||||
info.put("jdbcVersion", jdbcMajor + "." + jdbcMinor);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private static void putText(Map<String, String> target, String key, SqlSupplier<String> supplier) {
|
||||
String value = read(supplier);
|
||||
if (value != null && !value.trim().isEmpty()) {
|
||||
target.put(key, value.trim());
|
||||
}
|
||||
}
|
||||
|
||||
private static void putIdentifierCase(
|
||||
Map<String, String> target,
|
||||
String key,
|
||||
SqlSupplier<Boolean> lower,
|
||||
SqlSupplier<Boolean> upper,
|
||||
SqlSupplier<Boolean> mixed
|
||||
) {
|
||||
if (Boolean.TRUE.equals(read(lower))) {
|
||||
target.put(key, "lower");
|
||||
} else if (Boolean.TRUE.equals(read(upper))) {
|
||||
target.put(key, "upper");
|
||||
} else if (Boolean.TRUE.equals(read(mixed))) {
|
||||
target.put(key, "mixed");
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer readInteger(SqlSupplier<Integer> supplier) {
|
||||
return read(supplier);
|
||||
}
|
||||
|
||||
private static <T> T read(SqlSupplier<T> supplier) {
|
||||
try {
|
||||
return supplier.get();
|
||||
} catch (SQLException | AbstractMethodError | UnsupportedOperationException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private interface SqlSupplier<T> {
|
||||
T get() throws SQLException;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,9 @@ import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Connection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class JsonRpcServer {
|
||||
private static final long CONNECTION_VALIDATION_INTERVAL_MILLIS = 5_000L;
|
||||
@@ -105,10 +107,11 @@ public final class JsonRpcServer {
|
||||
return Collections.singletonMap("ok", true);
|
||||
}
|
||||
if (AgentProtocol.METHOD_TEST_CONNECTION.equals(method)) {
|
||||
if (!agent.testConnection(gson.fromJson(params, ConnectParams.class))) {
|
||||
Map<String, Object> result = agent.testConnectionWithInfo(gson.fromJson(params, ConnectParams.class));
|
||||
if (!Boolean.TRUE.equals(result.get("ok"))) {
|
||||
throw new RuntimeException("Connection failed");
|
||||
}
|
||||
return Collections.singletonMap("ok", true);
|
||||
return result;
|
||||
}
|
||||
if (AgentProtocol.METHOD_VALIDATE_CONNECTION.equals(method)) {
|
||||
Connection conn = agent.getConnection();
|
||||
@@ -126,7 +129,13 @@ public final class JsonRpcServer {
|
||||
}
|
||||
ensureLiveConnection(method);
|
||||
if (AgentProtocol.METHOD_CONNECTION_INFO.equals(method)) {
|
||||
return Collections.singletonMap("identifierQuote", agent.getIdentifierQuote());
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("identifierQuote", agent.getIdentifierQuote());
|
||||
Map<String, String> databaseInfo = agent.getDatabaseInfo();
|
||||
if (databaseInfo != null && !databaseInfo.isEmpty()) {
|
||||
result.put("databaseInfo", databaseInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (AgentProtocol.METHOD_LIST_DATABASES.equals(method)) {
|
||||
return agent.listDatabases();
|
||||
|
||||
Reference in new issue
Block a user