feat(ignite3): add Apache Ignite 3 support

This commit is contained in:
SCSTC
2026-08-20 02:21:55 +08:00
committed by GitHub
parent 34c8afeb58
commit 634bb9a7d0
32 changed files with 555 additions and 6 deletions
+1
View File
@@ -38,6 +38,7 @@ Each agent runs as a standalone process and communicates with DBX via stdin/stdo
| bigquery | Google BigQuery | BigQuery JDBC |
| kylin | Apache Kylin | Kylin JDBC |
| ignite | Apache Ignite | Ignite JDBC thin (ignite-core) |
| ignite3 | Apache Ignite 3 | Ignite 3 JDBC thin (ignite-jdbc) |
| sundb | SunDB | SunDB JDBC |
| tdengine | TDengine 2.4+ | taos-connector-rust native WebSocket agent |
| yashandb | 崖山 YashanDB | YashanDB JDBC |
+1
View File
@@ -38,6 +38,7 @@ DBX 的 Agent 驱动 —— 通过 JDBC 和原生数据库驱动支持各种数
| bigquery | Google BigQuery | BigQuery JDBC |
| kylin | Apache Kylin | Kylin JDBC |
| ignite | Apache Ignite | Ignite JDBC thin(ignite-core) |
| ignite3 | Apache Ignite 3 | Ignite 3 JDBC thin(ignite-jdbc) |
| sundb | SunDB | SunDB JDBC |
| tdengine | TDengine 2.4+ | taos-connector-rust 原生 WebSocket agent |
| yashandb | 崖山 YashanDB | YashanDB JDBC |
+1 -1
View File
@@ -7,7 +7,7 @@ def legacyStandaloneProjects = ['mongodb', 'kafka'] as Set
def pooledJdbcProjects = [
'access', 'bigquery', 'dameng', 'databend', 'databricks', 'db2', 'exasol',
'firebird', 'gbase8a', 'gbase8s', 'goldendb', 'h2', 'h2-legacy', 'highgo',
'ignite', 'informix', 'iris', 'kylin', 'oceanbase-oracle', 'oscar', 'saphana',
'ignite', 'ignite3', 'informix', 'iris', 'kylin', 'oceanbase-oracle', 'oscar', 'saphana',
'snowflake', 'spark', 'sqlserver-legacy', 'sundb', 'teradata', 'trino', 'uxdb',
'vertica', 'yashandb'
] as Set
@@ -14,6 +14,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
public abstract class AbstractJdbcAgent extends BaseDatabaseAgent {
private static final String GAUSSDB_COMPATIBILITY_SQL =
@@ -457,7 +458,18 @@ public abstract class AbstractJdbcAgent extends BaseDatabaseAgent {
protected abstract String buildJdbcUrl(ConnectParams params);
protected Connection openConnection(ConnectParams params) throws Exception {
return DriverManager.getConnection(buildJdbcUrl(params), params.getUsername(), params.getPassword());
return DriverManager.getConnection(buildJdbcUrl(params), buildConnectionProperties(params));
}
protected Properties buildConnectionProperties(ConnectParams params) {
Properties properties = new Properties();
if (params.getUsername() != null) {
properties.setProperty("user", params.getUsername());
}
if (params.getPassword() != null) {
properties.setProperty("password", params.getPassword());
}
return properties;
}
protected Connection openTestConnection(ConnectParams params) throws Exception {
@@ -165,7 +165,7 @@ public class JdbcAgentProfile {
return schemaSwitchPrefix + " " + quote + schema.replace(quote, quote + quote) + quote;
}
private static String appendUrlParams(String url, String urlParams) {
public static String appendUrlParams(String url, String urlParams) {
String params = trimUrlParams(urlParams);
if (params.isEmpty()) {
return url;
@@ -16,6 +16,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.List;
import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -25,6 +26,19 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class AbstractJdbcAgentTest {
@Test
void buildsStandardJdbcCredentialPropertiesByDefault() {
TestAgent agent = new TestAgent(new TrackingConnection());
Properties properties = agent.buildConnectionProperties(
new ConnectParams("localhost", 0, "demo", "user", "secret", "", "", false)
);
assertEquals("user", properties.getProperty("user"));
assertEquals("secret", properties.getProperty("password"));
assertEquals(2, properties.size());
}
@Test
void ownsConnectionLifecycleAndConnectedState() {
TrackingConnection tracking = new TrackingConnection();
+9
View File
@@ -0,0 +1,9 @@
dependencies {
implementation 'org.apache.ignite:ignite-jdbc:3.1.0'
}
tasks.named('shadowJar') {
manifest {
attributes('Agent-Label': 'Apache Ignite 3', 'Main-Class': 'com.dbx.agent.ignite3.Ignite3Agent')
}
}
@@ -0,0 +1,189 @@
package com.dbx.agent.ignite3;
import com.dbx.agent.AbstractJdbcAgent;
import com.dbx.agent.ColumnInfo;
import com.dbx.agent.ConnectParams;
import com.dbx.agent.DatabaseInfo;
import com.dbx.agent.ForeignKeyInfo;
import com.dbx.agent.IndexInfo;
import com.dbx.agent.JdbcAgentProfile;
import com.dbx.agent.MultiSessionJsonRpcServer;
import com.dbx.agent.TableInfo;
import com.dbx.agent.TriggerInfo;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
public final class Ignite3Agent extends AbstractJdbcAgent {
private static final String JDBC_USERNAME_PROPERTY = "ignite.jdbc.username";
private static final String JDBC_PASSWORD_PROPERTY = "ignite.jdbc.password";
private String databaseName = "";
@Override
protected String driverClass() {
return "org.apache.ignite.jdbc.IgniteJdbcDriver";
}
@Override
protected String buildJdbcUrl(ConnectParams params) {
return buildUrl(params);
}
@Override
protected Properties buildConnectionProperties(ConnectParams params) {
Properties properties = new Properties();
String username = params.getUsername();
String password = params.getPassword();
if ((username != null && !username.isEmpty()) || (password != null && !password.isEmpty())) {
properties.setProperty(JDBC_USERNAME_PROPERTY, username == null ? "" : username);
properties.setProperty(JDBC_PASSWORD_PROPERTY, password == null ? "" : password);
}
return properties;
}
@Override
protected void afterConnect(ConnectParams params, Connection connection) {
// Ignite has no catalogs; name the virtual database after the connection's
// real default schema (e.g. PUBLIC) so any database-as-schema context that
// leaks into setSchema targets a schema that actually exists.
try {
String schema = connection.getSchema();
databaseName = schema == null || schema.isBlank() ? params.getDatabase() : schema;
} catch (Exception e) {
databaseName = params.getDatabase();
}
}
@Override
public List<DatabaseInfo> listDatabases() {
// Ignite has no catalogs; expose the connected schema group as a single
// virtual database so the object browser stays schema-oriented like H2.
return List.of(new DatabaseInfo(databaseName.isBlank() ? "default" : databaseName));
}
@Override
public List<String> listSchemas() {
return unchecked(() -> {
List<String> result = new ArrayList<>();
try (ResultSet rs = requireConnected().getMetaData().getSchemas()) {
while (rs.next()) {
result.add(rs.getString("TABLE_SCHEM"));
}
}
result.sort(Comparator.naturalOrder());
return result;
});
}
@Override
public List<TableInfo> listTables(String schema) {
return unchecked(() -> {
List<TableInfo> result = new ArrayList<>();
try (ResultSet rs = requireConnected().getMetaData().getTables(null, schema, null, null)) {
while (rs.next()) {
result.add(new TableInfo(
rs.getString("TABLE_NAME"),
normalizeTableType(rs.getString("TABLE_TYPE")),
null
));
}
}
result.sort(Comparator.comparing(TableInfo::getName));
return result;
});
}
@Override
public List<ColumnInfo> getColumns(String schema, String table) {
return unchecked(() -> {
Set<String> primaryKeys = new LinkedHashSet<>();
try (ResultSet rs = requireConnected().getMetaData().getPrimaryKeys(null, schema, table)) {
while (rs.next()) {
primaryKeys.add(rs.getString("COLUMN_NAME"));
}
}
List<ColumnInfo> result = new ArrayList<>();
try (ResultSet rs = requireConnected().getMetaData().getColumns(null, schema, table, null)) {
while (rs.next()) {
String colName = rs.getString("COLUMN_NAME");
result.add(new ColumnInfo(
colName,
rs.getString("TYPE_NAME"),
"YES".equals(rs.getString("IS_NULLABLE")),
rs.getString("COLUMN_DEF"),
primaryKeys.contains(colName),
null,
emptyToNull(rs.getString("REMARKS")),
intOrNull(rs, "COLUMN_SIZE"),
intOrNull(rs, "DECIMAL_DIGITS"),
null
));
}
}
return result;
});
}
@Override
public List<IndexInfo> listIndexes(String schema, String table) {
return Collections.emptyList();
}
@Override
public List<ForeignKeyInfo> listForeignKeys(String schema, String table) {
return Collections.emptyList();
}
@Override
public List<TriggerInfo> listTriggers(String schema, String table) {
return Collections.emptyList();
}
@Override
public String setSchemaSQL(String schema) {
// JdbcConnection implements Connection.setSchema, so no SQL switch is needed.
return "";
}
static String buildUrl(ConnectParams params) {
String connectionString = params.getConnection_string();
if (connectionString != null && !connectionString.trim().isEmpty()) {
return connectionString.trim();
}
String base = "jdbc:ignite:thin://" + params.getHost() + ":" + params.getPort();
String database = params.getDatabase();
String url = database == null || database.isBlank() ? base : base + "/" + database;
// Reuse the shared JDBC URL parameter mapping so advanced options
// (timeouts, SSL, authentication) configured in the UI reach the driver.
return JdbcAgentProfile.appendUrlParams(url, params.getUrl_params());
}
private static String normalizeTableType(String type) {
if ("BASE TABLE".equals(type)) {
return "TABLE";
}
return type;
}
private static Integer intOrNull(ResultSet rs, String column) throws Exception {
Object value = rs.getObject(column);
return value instanceof Number ? ((Number) value).intValue() : null;
}
private static String emptyToNull(String value) {
return value == null || value.isEmpty() ? null : value;
}
public static void main(String[] args) {
new MultiSessionJsonRpcServer(Ignite3Agent::new).run();
}
}
@@ -0,0 +1,16 @@
package com.dbx.agent.ignite3;
import com.dbx.agent.DatabaseAgent;
import com.dbx.agent.test.JdbcFakeExecutionBehaviorTest;
class Ignite3AgentTest extends JdbcFakeExecutionBehaviorTest {
@Override
protected DatabaseAgent createAgent() {
return new Ignite3Agent();
}
@Override
protected String resultSetSql() {
return "SELECT 1";
}
}
@@ -0,0 +1,245 @@
package com.dbx.agent.ignite3;
import com.dbx.agent.ConnectParams;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class Ignite3AgentUrlTest {
@Test
void buildUrlUsesExplicitConnectionString() {
ConnectParams params = new ConnectParams(
"127.0.0.1", 10800, "PUBLIC", "", "", "",
"jdbc:ignite:thin://10.0.0.1:10800/PUBLIC?connectionTimeout=5000", false
);
Assertions.assertEquals(
"jdbc:ignite:thin://10.0.0.1:10800/PUBLIC?connectionTimeout=5000",
Ignite3Agent.buildUrl(params)
);
}
@Test
void buildUrlWithoutDatabaseOmitsSchemaSegment() {
ConnectParams params = new ConnectParams("127.0.0.1", 10800, "", "", "", "", "", false);
Assertions.assertEquals("jdbc:ignite:thin://127.0.0.1:10800", Ignite3Agent.buildUrl(params));
}
@Test
void buildUrlWithoutUrlParamsStaysUnchanged() {
ConnectParams params = new ConnectParams("127.0.0.1", 10800, "PUBLIC", "", "", null, "", false);
Assertions.assertEquals("jdbc:ignite:thin://127.0.0.1:10800/PUBLIC", Ignite3Agent.buildUrl(params));
}
@Test
void buildUrlAppendsAdvancedUrlParamsAfterSchema() {
ConnectParams params = new ConnectParams(
"127.0.0.1", 10800, "PUBLIC", "", "",
"connectionTimeout=5000&queryTimeout=30", "", false
);
Assertions.assertEquals(
"jdbc:ignite:thin://127.0.0.1:10800/PUBLIC?connectionTimeout=5000&queryTimeout=30",
Ignite3Agent.buildUrl(params)
);
}
@Test
void buildUrlPassesThroughUserParamStringVerbatim() {
ConnectParams params = new ConnectParams(
"127.0.0.1", 10800, "PUBLIC", "", "",
"sslEnabled=true;trustStorePath=/etc/ignite/trust.jks", "", false
);
Assertions.assertEquals(
"jdbc:ignite:thin://127.0.0.1:10800/PUBLIC?sslEnabled=true;trustStorePath=/etc/ignite/trust.jks",
Ignite3Agent.buildUrl(params)
);
}
@Test
void buildUrlStripsLeadingParamSeparators() {
ConnectParams params = new ConnectParams("127.0.0.1", 10800, "", "", "", "?sslEnabled=true", "", false);
Assertions.assertEquals("jdbc:ignite:thin://127.0.0.1:10800?sslEnabled=true", Ignite3Agent.buildUrl(params));
}
@Test
void usesThePinnedIgniteJdbcDependency() throws Exception {
Path driverJar = Path.of(
org.apache.ignite.jdbc.IgniteJdbcDriver.class.getProtectionDomain().getCodeSource().getLocation().toURI()
);
Assertions.assertEquals("ignite-jdbc-3.1.0.jar", driverJar.getFileName().toString());
}
@Test
void separateCredentialsRoundTripThroughJdbcPropertiesAndIgniteParser() throws Exception {
String username = "dbx-user";
String password = "dbx-secret";
String urlParams = "sslEnabled=true&connectionTimeout=5000&queryTimeout=30&connectionTimeZone=UTC";
CapturingDriver capturingDriver = new CapturingDriver();
DriverManager.registerDriver(capturingDriver);
try {
ConnectParams captureParams = new ConnectParams(
"127.0.0.1", 10800, "PUBLIC", username, password, urlParams,
CapturingDriver.URL, false
);
Properties connectionProperties = new Ignite3Agent().buildConnectionProperties(captureParams);
try (Connection ignored = DriverManager.getConnection(CapturingDriver.URL, connectionProperties)) {
Assertions.assertEquals(CapturingDriver.URL, capturingDriver.url);
}
Assertions.assertEquals(username, capturingDriver.properties.getProperty("ignite.jdbc.username"));
Assertions.assertEquals(password, capturingDriver.properties.getProperty("ignite.jdbc.password"));
Assertions.assertNull(capturingDriver.properties.getProperty("user"));
Assertions.assertNull(capturingDriver.properties.getProperty("password"));
ConnectParams igniteParams = new ConnectParams(
"127.0.0.1", 10800, "PUBLIC", username, password, urlParams, "", false
);
String igniteUrl = Ignite3Agent.buildUrl(igniteParams);
Assertions.assertFalse(igniteUrl.contains(username));
Assertions.assertFalse(igniteUrl.contains(password));
Map<String, String> parsed = parsedProperties(
new org.apache.ignite.jdbc.IgniteJdbcDriver(),
igniteUrl,
capturingDriver.properties
);
Assertions.assertEquals(username, parsed.get("ignite.jdbc.username"));
Assertions.assertEquals(password, parsed.get("ignite.jdbc.password"));
Assertions.assertEquals("true", parsed.get("ignite.jdbc.sslEnabled"));
Assertions.assertEquals("5000", parsed.get("ignite.jdbc.connectionTimeout"));
Assertions.assertEquals("30", parsed.get("ignite.jdbc.queryTimeout"));
Assertions.assertEquals("UTC", parsed.get("ignite.jdbc.connectionTimeZone"));
} finally {
DriverManager.deregisterDriver(capturingDriver);
}
}
@Test
void blankCredentialsDoNotEnableIgniteAuthentication() throws Exception {
CapturingDriver capturingDriver = new CapturingDriver();
DriverManager.registerDriver(capturingDriver);
try {
ConnectParams params = new ConnectParams(
"127.0.0.1", 10800, "PUBLIC", "", "", "", CapturingDriver.URL, false
);
Properties connectionProperties = new Ignite3Agent().buildConnectionProperties(params);
try (Connection ignored = DriverManager.getConnection(CapturingDriver.URL, connectionProperties)) {
Assertions.assertTrue(capturingDriver.properties.isEmpty());
}
} finally {
DriverManager.deregisterDriver(capturingDriver);
}
}
@Test
void semicolonAdvancedParamsStayVerbatimAndAreNotSplitInQueryMode() throws Exception {
String url = Ignite3Agent.buildUrl(new ConnectParams(
"127.0.0.1", 10800, "PUBLIC", "", "",
"sslEnabled=true;trustStorePath=/etc/ignite/trust.jks", "", false
));
Assertions.assertEquals(
"jdbc:ignite:thin://127.0.0.1:10800/PUBLIC?sslEnabled=true;trustStorePath=/etc/ignite/trust.jks",
url
);
Map<String, String> parsed = parsedProperties(
new org.apache.ignite.jdbc.IgniteJdbcDriver(),
url,
new Properties()
);
Assertions.assertEquals("false", parsed.get("ignite.jdbc.sslEnabled"));
Assertions.assertNull(parsed.get("ignite.jdbc.trustStorePath"));
}
private static Map<String, String> parsedProperties(
Driver driver,
String url,
Properties properties
) throws SQLException {
Map<String, String> parsed = new LinkedHashMap<>();
for (DriverPropertyInfo property : driver.getPropertyInfo(url, properties)) {
parsed.put(property.name, property.value);
}
return parsed;
}
private static final class CapturingDriver implements Driver {
private static final String URL = "jdbc:dbx-ignite3-test:";
private String url;
private Properties properties;
@Override
public Connection connect(String url, Properties info) {
if (!acceptsURL(url)) {
return null;
}
this.url = url;
properties = new Properties();
properties.putAll(info);
return (Connection) Proxy.newProxyInstance(
Connection.class.getClassLoader(),
new Class<?>[]{Connection.class},
(proxy, method, args) -> {
if ("close".equals(method.getName())) {
return null;
}
if ("isClosed".equals(method.getName())) {
return false;
}
throw new UnsupportedOperationException(method.getName());
}
);
}
@Override
public boolean acceptsURL(String url) {
return URL.equals(url);
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {
return new DriverPropertyInfo[0];
}
@Override
public int getMajorVersion() {
return 1;
}
@Override
public int getMinorVersion() {
return 0;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public Logger getParentLogger() {
return Logger.getGlobal();
}
}
}
+1
View File
@@ -11,6 +11,7 @@ goldendb native-pushdown java-sql Uses information_schema with type, filter, sta
h2 native-pushdown java-sql Uses INFORMATION_SCHEMA with type, filter, stable order, and LIMIT/OFFSET.
hive-go shared-fallback native-go Uses HiveServer2 metadata APIs, then applies stable filtering and paging in the native agent with a SHOW TABLES fallback.
ignite intentional-fallback java-jdbc-metadata Uses JDBC metadata from the Ignite thin driver; no portable server-side paging API, common constraints filter locally.
ignite3 intentional-fallback java-jdbc-metadata Uses JDBC metadata from the Ignite 3 thin driver; no portable server-side paging API, common constraints filter locally.
informix native-pushdown java-sql Uses systables/sysprocedures with type, filter, stable order, and SKIP/FIRST.
iotdb shared-fallback native-go Uses SHOW DEVICES or SHOW TABLES DETAILS for Tree/Table metadata, then applies stable filtering and paging in the native agent.
kingbase-go shared-fallback native-go Uses sys_catalog/information_schema for compatibility-aware metadata, then applies stable filtering and paging in the native agent.
1 driver strategy scope reason
11 h2 native-pushdown java-sql Uses INFORMATION_SCHEMA with type, filter, stable order, and LIMIT/OFFSET.
12 hive-go shared-fallback native-go Uses HiveServer2 metadata APIs, then applies stable filtering and paging in the native agent with a SHOW TABLES fallback.
13 ignite intentional-fallback java-jdbc-metadata Uses JDBC metadata from the Ignite thin driver; no portable server-side paging API, common constraints filter locally.
14 ignite3 intentional-fallback java-jdbc-metadata Uses JDBC metadata from the Ignite 3 thin driver; no portable server-side paging API, common constraints filter locally.
15 informix native-pushdown java-sql Uses systables/sysprocedures with type, filter, stable order, and SKIP/FIRST.
16 iotdb shared-fallback native-go Uses SHOW DEVICES or SHOW TABLES DETAILS for Tree/Table metadata, then applies stable filtering and paging in the native agent.
17 kingbase-go shared-fallback native-go Uses sys_catalog/information_schema for compatibility-aware metadata, then applies stable filtering and paging in the native agent.
+1 -1
View File
@@ -4,7 +4,7 @@ def infrastructureModules = ['common', 'test-support']
def driverModules = [
'access', 'dameng', 'goldendb', 'databend', 'databricks', 'saphana',
'teradata', 'vertica', 'firebird', 'exasol', 'oceanbase-oracle', 'gbase8a', 'gbase8s',
'bigquery', 'kylin', 'ignite', 'sundb', 'h2', 'h2-legacy', 'snowflake', 'trino', 'spark',
'bigquery', 'kylin', 'ignite', 'ignite3', 'sundb', 'h2', 'h2-legacy', 'snowflake', 'trino', 'spark',
'db2', 'informix', 'mongodb', 'highgo', 'uxdb', 'yashandb', 'oscar',
'iris', 'etcd', 'kafka', 'sqlserver-legacy'
]
+1
View File
@@ -16,6 +16,7 @@
"h2-legacy": "0.1.16",
"hive": "0.1.49",
"ignite": "0.1.0",
"ignite3": "0.1.0",
"spark": "0.1.18",
"informix": "0.1.47",
"kingbase": "0.1.49",
@@ -1235,6 +1235,7 @@ const driverProfiles: Record<
},
kylin: { type: "kylin", port: 7070, user: "ADMIN", label: "Apache Kylin", icon: "kylin" },
ignite: { type: "ignite", port: 10800, user: "", label: "Apache Ignite", icon: "ignite" },
ignite3: { type: "ignite3", port: 10800, user: "", label: "Apache Ignite 3", icon: "ignite" },
sundb: { type: "sundb", port: 22000, user: "root", label: "科蓝 SUNDB", icon: "sundb" },
oscar: { type: "oscar", port: 2003, user: "SYSDBA", label: "神通 OSCAR", icon: "oscar" },
jdbc: { type: "jdbc", port: 0, user: "", label: "JDBC", icon: "jdbc" },
@@ -2975,6 +2976,7 @@ const iconTypeMap: Record<string, string> = {
bigquery: "bigquery",
kylin: "kylin",
ignite: "ignite",
ignite3: "ignite",
sundb: "sundb",
oscar: "oscar",
influxdb: "influxdb",
@@ -3057,6 +3059,7 @@ const dbOptions: DbOption[] = [
{ value: "bigquery", label: "BigQuery" },
{ value: "kylin", label: "Kylin" },
{ value: "ignite", label: "Apache Ignite" },
{ value: "ignite3", label: "Apache Ignite 3" },
{ value: "sundb", label: "科蓝 SUNDB" },
{ value: "oscar", label: "神通 OSCAR" },
{ value: "xugu", label: "虚谷 XuguDB" },
@@ -3095,7 +3098,7 @@ const dbCategoryDefinitions: Array<{
{
key: "analytics",
titleKey: "connection.databaseCategoryAnalytics",
optionValues: ["cloudberry", "clickhouse", "doris", "starrocks", "databend", "selectdb", "databricks", "saphana", "teradata", "vertica", "exasol", "redshift", "snowflake", "trino", "prestosql", "hive", "kyuubi", "impala", "spark", "bigquery", "kylin", "ignite", "dremio"],
optionValues: ["cloudberry", "clickhouse", "doris", "starrocks", "databend", "selectdb", "databricks", "saphana", "teradata", "vertica", "exasol", "redshift", "snowflake", "trino", "prestosql", "hive", "kyuubi", "impala", "spark", "bigquery", "kylin", "ignite", "ignite3", "dremio"],
},
{
key: "domestic",
@@ -68,6 +68,7 @@ const assetIcons: Record<string, string> = {
trino: "trino",
kylin: "apache_kylin",
ignite: "apache_ignite",
ignite3: "apache_ignite",
cockroachdb: "cockroachdb",
db2: "db2",
dremio: "dremio",
@@ -89,6 +89,7 @@ describe("AGENT_DRIVER_CATEGORY_MAP integrity", () => {
"exasol",
"hive",
"ignite",
"ignite3",
"kylin",
"phoenix",
"prestosql",
@@ -40,6 +40,7 @@ const DRIVER_STARTUP_FLOOR_TYPES = new Set<DatabaseType>([
"bigquery",
"kylin",
"ignite",
"ignite3",
"sundb",
"oscar",
"tdengine",
@@ -43,6 +43,7 @@ export const AGENT_DRIVER_CATEGORY_MAP: Readonly<Record<string, DriverCategoryKe
kingbase: "domestic",
kylin: "analytics",
ignite: "analytics",
ignite3: "analytics",
mongodb: "document",
neo4j: "graph_ai",
"oceanbase-oracle": "domestic",
@@ -24,6 +24,7 @@ export const SCHEMA_AWARE_TYPES = new Set<DatabaseType>([
"jdbc",
"h2",
"ignite",
"ignite3",
"snowflake",
"trino",
"prestosql",
@@ -77,6 +78,7 @@ export const TREE_SCHEMA_TYPES = new Set<DatabaseType>([
"prestosql",
"h2",
"ignite",
"ignite3",
"informix",
"xugu",
"oscar",
@@ -77,6 +77,7 @@ export const DATABASE_NAMESPACE_CREATION_MATRIX = {
bigquery: { deferred: "dataset creation needs project/location options" },
kylin: { deferred: "project/model lifecycle is not SQL database creation" },
ignite: { deferred: "schema lifecycle is managed through cluster/cache configuration" },
ignite3: { deferred: "schema lifecycle is managed through cluster configuration" },
sundb: { deferred: "creation semantics not verified for first pass" },
oscar: { database: "schema" },
tdengine: { connection: "database" },
@@ -79,6 +79,7 @@ const DATABASE_TYPE_OBJECTS = new Map<DatabaseType, SidebarObjectKind[]>([
["bigquery", TABLE_VIEW_OBJECTS],
["kylin", TABLE_VIEW_OBJECTS],
["ignite", TABLE_VIEW_OBJECTS],
["ignite3", TABLE_VIEW_OBJECTS],
["tdengine", TABLE_VIEW_OBJECTS],
["iotdb", TABLE_VIEW_OBJECTS],
["neo4j", TABLE_VIEW_OBJECTS],
@@ -77,6 +77,7 @@ export const DATABASE_PROPERTY_EDITING_MATRIX = {
bigquery: { deferred: "dataset properties need project/location-specific handling" },
kylin: { deferred: "project/model lifecycle is not SQL database property editing" },
ignite: { deferred: "schema properties need product-specific handling" },
ignite3: { deferred: "schema properties need product-specific handling" },
sundb: { deferred: "property semantics not verified for first pass" },
oscar: { deferred: "schema properties need product-specific handling" },
tdengine: { deferred: "database property editing not verified for first pass" },
@@ -1148,6 +1148,7 @@ export const useConnectionStore = defineStore("connection", () => {
bigquery: "BigQuery",
kylin: "Kylin",
ignite: "Apache Ignite",
ignite3: "Apache Ignite 3",
sundb: "科蓝 SUNDB",
oscar: "神通 OSCAR",
influxdb: "InfluxDB",
+1
View File
@@ -64,6 +64,7 @@ export type DatabaseType =
| "bigquery"
| "kylin"
| "ignite"
| "ignite3"
| "sundb"
| "oscar"
| "tdengine"
+1
View File
@@ -67,6 +67,7 @@ const BRIDGE_REQUIRED_TYPES: &[&str] = &[
"bigquery",
"kylin",
"ignite",
"ignite3",
"sundb",
"oscar",
"xugu",
@@ -1758,6 +1758,36 @@
"driverManagement": true
}
},
{
"dbType": "ignite3",
"label": "Apache Ignite 3",
"runtimeMode": "agent",
"mcpMode": "bridge",
"agentKey": "ignite3",
"singleConnectionPool": false,
"metadataConnectionScoped": false,
"skipTcpProbe": true,
"defaultPort": 10800,
"supportLevel": "understand",
"capabilities": {
"queryExecution": true,
"metadataBrowse": true,
"objectBrowser": true,
"objectSource": false,
"schemaSearch": true,
"diagram": false,
"tableDataEdit": false,
"tableStructureEdit": false,
"tableImport": false,
"dataTransfer": false,
"sqlFileExecution": true,
"databaseCreate": false,
"fieldLineage": false,
"sqlExplain": false,
"userAdmin": false,
"driverManagement": true
}
},
{
"dbType": "sundb",
"label": "科蓝 SUNDB",
+7
View File
@@ -267,6 +267,13 @@ const AGENT_CATALOG: &[AgentCatalogEntry] = &[
store_visible: true,
profiles: &[],
},
AgentCatalogEntry {
db_type: DatabaseType::Ignite3,
key: "ignite3",
label: "Apache Ignite 3",
store_visible: true,
profiles: &[],
},
AgentCatalogEntry {
db_type: DatabaseType::Sundb,
key: "sundb",
+1
View File
@@ -222,6 +222,7 @@ macro_rules! agent_connection_pool_database_type {
| DatabaseType::Bigquery
| DatabaseType::Kylin
| DatabaseType::Ignite
| DatabaseType::Ignite3
| DatabaseType::Sundb
| DatabaseType::Oscar
| DatabaseType::Tdengine
+5
View File
@@ -601,6 +601,7 @@ pub enum DatabaseType {
#[serde(rename = "questdb")]
Questdb,
Ignite,
Ignite3,
Jdbc,
/// Message queue admin connection (Pulsar / Kafka / RocketMQ). The specific
/// system is determined by `external_config.systemKind`.
@@ -1145,6 +1146,7 @@ impl ConnectionConfig {
}
DatabaseType::Questdb => format!("questdb://{host}:{port}{db_part}"),
DatabaseType::Ignite => format!("ignite://{host}:{port}{db_part}"),
DatabaseType::Ignite3 => format!("ignite3://{host}:{port}{db_part}"),
DatabaseType::Gbase => format!("gbase://{host}:{port}{db_part}"),
DatabaseType::H2 => format!("h2://{host}:{port}{db_part}"),
DatabaseType::Snowflake => format!("snowflake://{host}/{db_part}"),
@@ -1352,6 +1354,9 @@ impl ConnectionConfig {
DatabaseType::Ignite => {
format!("ignite://{}:{}@{host}:{port}{db_part}", username, password)
}
DatabaseType::Ignite3 => {
format!("ignite3://{}:{}@{host}:{port}{db_part}", username, password)
}
DatabaseType::Gbase => {
format!("gbase://{}:{}@{host}:{port}{db_part}", username, password)
}
@@ -670,7 +670,7 @@ pub fn profile_for(db_type: DatabaseType) -> DdlDialectProfile {
ClickHouse => clickhouse_profile(),
DuckDb | Questdb | SapHana | Teradata | Snowflake | Trino | PrestoSql | Hive | Kyuubi | Impala | Spark
| Db2 | Informix | Bigquery | Kylin | Ignite | Oscar | Tdengine | Iotdb | Databricks | Jdbc => {
| Db2 | Informix | Bigquery | Kylin | Ignite | Ignite3 | Oscar | Tdengine | Iotdb | Databricks | Jdbc => {
conservative_ansi(db_type)
}
+1
View File
@@ -72,6 +72,7 @@ export const databaseSupport: DatabaseSupportItem[] = [
{ id: "cassandra", name: "Cassandra", icon: "/icons/database/cassandra.svg", tone: "#1287b1" },
{ id: "kylin", name: "Kylin", icon: "/icons/database/apache_kylin.svg", tone: "#fb8c00" },
{ id: "ignite", name: "Ignite", icon: "/icons/database/apache_ignite.svg", tone: "#ef2c2c" },
{ id: "ignite3", name: "Ignite 3", icon: "/icons/database/apache_ignite.svg", tone: "#ef2c2c" },
{ id: "dremio", name: "Dremio", icon: "/icons/database/dremio.svg", tone: "#30bdbe" },
{ id: "oscar", name: "OSCAR", icon: "/icons/database/oscar.png", tone: "#1b8dff" },
{ id: "influxdb", name: "InfluxDB", icon: "/icons/database/influxdb.svg", tone: "#22adf6" },
+1
View File
@@ -120,6 +120,7 @@ const driverLabels: Record<string, string> = {
highgo: "HighGo",
hive: "Apache Hive",
ignite: "Apache Ignite",
ignite3: "Apache Ignite 3",
informix: "Informix",
iotdb: "Apache IoTDB",
iris: "InterSystems IRIS",