diff --git a/apps/desktop/public/icons/database/iotdb.svg b/apps/desktop/public/icons/database/iotdb.svg new file mode 100644 index 0000000000..d742630737 --- /dev/null +++ b/apps/desktop/public/icons/database/iotdb.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index e429737d5f..c0d76386eb 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -403,6 +403,7 @@ const driverProfiles: Record< jdbc: { type: "jdbc", port: 0, user: "", label: "JDBC", icon: "jdbc" }, tdengine: { type: "tdengine", port: 6041, user: "root", label: "TDengine", icon: "tdengine" }, xugu: { type: "xugu", port: 5138, user: "", label: "虚谷 XuguDB", icon: "xugu" }, + iotdb: { type: "iotdb", port: 6667, user: "root", label: "Apache IoTDB", icon: "iotdb" }, iris: { type: "iris", port: 1972, user: "_SYSTEM", label: "IRIS", icon: "iris" }, custom_mysql: { type: "mysql", @@ -659,6 +660,7 @@ const iconTypeMap: Record = { cockroachdb: "cockroachdb", tdengine: "tdengine", xugu: "xugu", + iotdb: "iotdb", dm: "dm", h2: "h2", snowflake: "snowflake", @@ -730,6 +732,7 @@ const dbOptions = [ { value: "kylin", label: "Kylin" }, { value: "sundb", label: "SunDB" }, { value: "xugu", label: "虚谷 XuguDB" }, + { value: "iotdb", label: "Apache IoTDB" }, { value: "iris", label: "IRIS" }, { value: "jdbc", label: "JDBC" }, { value: "custom_mysql", label: "Custom (MySQL)" }, diff --git a/apps/desktop/src/components/icons/DatabaseIcon.vue b/apps/desktop/src/components/icons/DatabaseIcon.vue index b460d8502b..fbc90aaf9f 100644 --- a/apps/desktop/src/components/icons/DatabaseIcon.vue +++ b/apps/desktop/src/components/icons/DatabaseIcon.vue @@ -68,6 +68,7 @@ const assetIcons: Record = { polardb: "polardb.webp", greatsql: "greatsql.webp", xugu: "xugu.png", + iotdb: "iotdb", iris: "iris.png", }; diff --git a/apps/desktop/src/lib/connectionPresentation.ts b/apps/desktop/src/lib/connectionPresentation.ts index 1de3c97e77..d6c34091c0 100644 --- a/apps/desktop/src/lib/connectionPresentation.ts +++ b/apps/desktop/src/lib/connectionPresentation.ts @@ -136,6 +136,9 @@ export function connectionUrlPlaceholder(dbType: DatabaseType): string { case "xugu": return "xugu://user:password@host:5138/database"; + case "iotdb": + return "iotdb://user:password@host:6667/root.test"; + case "bigquery": return "bigquery://https://www.googleapis.com/bigquery/v2:443/project-id"; diff --git a/apps/desktop/src/lib/connectionUrl.ts b/apps/desktop/src/lib/connectionUrl.ts index e7921c37f7..9d88a05f47 100644 --- a/apps/desktop/src/lib/connectionUrl.ts +++ b/apps/desktop/src/lib/connectionUrl.ts @@ -49,6 +49,7 @@ const SCHEME_PROFILES: Record = { tdengine: { type: "tdengine", profile: "tdengine", label: "TDengine", defaultPort: 6041 }, "taos-ws": { type: "tdengine", profile: "tdengine", label: "TDengine", defaultPort: 6041 }, xugu: { type: "xugu", profile: "xugu", label: "XuguDB", defaultPort: 5138 }, + iotdb: { type: "iotdb", profile: "iotdb", label: "Apache IoTDB", defaultPort: 6667 }, iris: { type: "iris", profile: "iris", label: "IRIS", defaultPort: 1972 }, }; diff --git a/apps/desktop/src/lib/databaseCapabilitySets.ts b/apps/desktop/src/lib/databaseCapabilitySets.ts index 5cc4232247..27f7de8c67 100644 --- a/apps/desktop/src/lib/databaseCapabilitySets.ts +++ b/apps/desktop/src/lib/databaseCapabilitySets.ts @@ -28,6 +28,7 @@ export const SCHEMA_AWARE_TYPES = new Set([ "db2", "tdengine", "xugu", + "iotdb", "iris", "duckdb", ]); @@ -106,6 +107,7 @@ export const DATABASE_SEARCH_SUPPORTED_TYPES = new Set([ "sundb", "tdengine", "xugu", + "iotdb", "iris", ]); @@ -224,6 +226,7 @@ export const TREE_SCHEMA_TYPES = new Set([ "h2", "tdengine", "xugu", + "iotdb", "iris", "duckdb", ]); @@ -264,6 +267,7 @@ export const AGENT_DRIVER_TYPES = new Set([ "gaussdb", "tdengine", "xugu", + "iotdb", "iris", ]); diff --git a/apps/desktop/src/lib/tableSelectSql.ts b/apps/desktop/src/lib/tableSelectSql.ts index 7a2b699b77..bed3ae0626 100644 --- a/apps/desktop/src/lib/tableSelectSql.ts +++ b/apps/desktop/src/lib/tableSelectSql.ts @@ -17,6 +17,7 @@ export interface BuildTableSelectSqlOptions { } export function quoteTableIdentifier(databaseType: DatabaseType | undefined, name: string): string { + if (databaseType === "iotdb") return name; if (databaseType === "jdbc") return quoteJdbcIdentifier(name); if (databaseType === "mysql" || databaseType === "hive" || databaseType === "tdengine" || databaseType === "access") return `\`${name.replace(/`/g, "``")}\``; @@ -39,6 +40,13 @@ export function qualifiedTableName( options: Pick, ): string { const { databaseType, schema, tableName } = options; + if (databaseType === "iotdb") { + const trimmedSchema = schema?.trim(); + if (trimmedSchema && tableName !== trimmedSchema && !tableName.startsWith(`${trimmedSchema}.`)) { + return `${quoteTableIdentifier(databaseType, trimmedSchema)}.${quoteTableIdentifier(databaseType, tableName)}`; + } + return quoteTableIdentifier(databaseType, tableName); + } if (isSchemaAware(databaseType) && !usesDatabaseObjectTreeMode(databaseType) && schema) { return `${quoteTableIdentifier(databaseType, schema)}.${quoteTableIdentifier(databaseType, tableName)}`; } diff --git a/apps/desktop/src/types/database.ts b/apps/desktop/src/types/database.ts index 9852e40711..962138f0ce 100644 --- a/apps/desktop/src/types/database.ts +++ b/apps/desktop/src/types/database.ts @@ -44,6 +44,7 @@ export type DatabaseType = | "sundb" | "tdengine" | "xugu" + | "iotdb" | "iris" | "jdbc"; diff --git a/crates/dbx-core/assets/database-drivers.manifest.json b/crates/dbx-core/assets/database-drivers.manifest.json index 098691366d..ca14731c8c 100644 --- a/crates/dbx-core/assets/database-drivers.manifest.json +++ b/crates/dbx-core/assets/database-drivers.manifest.json @@ -484,6 +484,17 @@ "skipTcpProbe": true, "defaultPort": 5138 }, + { + "dbType": "iotdb", + "label": "Apache IoTDB", + "runtimeMode": "agent", + "mcpMode": "bridge", + "agentKey": "iotdb", + "singleConnectionPool": false, + "metadataConnectionScoped": false, + "skipTcpProbe": true, + "defaultPort": 6667 + }, { "dbType": "iris", "label": "InterSystems IRIS", diff --git a/crates/dbx-core/src/agent_catalog.rs b/crates/dbx-core/src/agent_catalog.rs index 1eac13bc8c..8cc6b6b8a4 100644 --- a/crates/dbx-core/src/agent_catalog.rs +++ b/crates/dbx-core/src/agent_catalog.rs @@ -217,6 +217,13 @@ const AGENT_CATALOG: &[AgentCatalogEntry] = &[ store_visible: true, profiles: &[], }, + AgentCatalogEntry { + db_type: DatabaseType::Iotdb, + key: "iotdb", + label: "Apache IoTDB", + store_visible: true, + profiles: &[], + }, AgentCatalogEntry { db_type: DatabaseType::MongoDb, key: "mongodb", diff --git a/crates/dbx-core/src/connection.rs b/crates/dbx-core/src/connection.rs index 70b157eece..cf07a4de98 100644 --- a/crates/dbx-core/src/connection.rs +++ b/crates/dbx-core/src/connection.rs @@ -474,6 +474,7 @@ impl AppState { | DatabaseType::Sundb | DatabaseType::Tdengine | DatabaseType::Xugu + | DatabaseType::Iotdb | DatabaseType::Iris | DatabaseType::Access => { let connect_params = diff --git a/crates/dbx-core/src/models/connection.rs b/crates/dbx-core/src/models/connection.rs index 77b2064576..20588c3601 100644 --- a/crates/dbx-core/src/models/connection.rs +++ b/crates/dbx-core/src/models/connection.rs @@ -253,6 +253,7 @@ pub enum DatabaseType { Sundb, Tdengine, Xugu, + Iotdb, #[serde(rename = "iris")] Iris, Jdbc, @@ -681,6 +682,14 @@ impl ConnectionConfig { DatabaseType::Sundb => format!("sundb://{host}:{port}{db_part}"), DatabaseType::Tdengine => format!("tdengine://{host}:{port}{db_part}"), DatabaseType::Xugu => format!("xugu://{host}:{port}{db_part}"), + DatabaseType::Iotdb => { + let base = format!("iotdb://{host}:{port}{db_part}"); + if params.is_empty() { + base + } else { + format!("{base}?{params}") + } + } DatabaseType::Iris => format!("iris://{host}:{port}{db_part}"), DatabaseType::Jdbc => "jdbc:".to_string(), } @@ -853,6 +862,14 @@ impl ConnectionConfig { DatabaseType::Xugu => { format!("xugu://{}:{}@{host}:{port}{db_part}", username, password) } + DatabaseType::Iotdb => { + let base = format!("iotdb://{}:{}@{host}:{port}{db_part}", username, password); + if params.is_empty() { + base + } else { + format!("{base}?{params}") + } + } DatabaseType::Iris => { format!("iris://{}:{}@{host}:{port}{db_part}", username, password) } diff --git a/crates/dbx-core/src/sql_dialect.rs b/crates/dbx-core/src/sql_dialect.rs index b3d2ac0a04..8cc4702de6 100644 --- a/crates/dbx-core/src/sql_dialect.rs +++ b/crates/dbx-core/src/sql_dialect.rs @@ -170,6 +170,17 @@ pub fn build_table_select_sql(options: TableSelectSqlOptions<'_>) -> String { } pub fn qualified_table_name(database_type: Option, schema: Option<&str>, table_name: &str) -> String { + if database_type == Some(DatabaseType::Iotdb) { + let table_name = quote_table_identifier(database_type, table_name); + let schema = schema.map(str::trim).filter(|schema| !schema.is_empty()); + if let Some(schema) = schema { + if table_name == schema || table_name.starts_with(&format!("{schema}.")) { + return table_name; + } + return format!("{}.{}", quote_table_identifier(database_type, schema), table_name); + } + return table_name; + } if database_type.is_some_and(is_schema_aware) && database_type != Some(DatabaseType::Jdbc) && schema.is_some_and(|schema| !schema.trim().is_empty()) @@ -185,6 +196,7 @@ pub fn qualified_table_name(database_type: Option, schema: Option< pub fn quote_table_identifier(database_type: Option, name: &str) -> String { match database_type { + Some(DatabaseType::Iotdb) => name.to_string(), Some(DatabaseType::Jdbc) if is_simple_jdbc_identifier(name) => name.to_string(), Some(DatabaseType::Jdbc) => format!("`{}`", name.replace('`', "``")), Some( @@ -404,6 +416,7 @@ mod tests { assert_eq!(quote_table_identifier(Some(DatabaseType::Informix), "users_1"), "users_1"); assert_eq!(quote_table_identifier(Some(DatabaseType::Jdbc), "users_1"), "users_1"); assert_eq!(quote_table_identifier(Some(DatabaseType::Jdbc), "user name"), "`user name`"); + assert_eq!(quote_table_identifier(Some(DatabaseType::Iotdb), "root.test.device2"), "root.test.device2"); } #[test] @@ -412,6 +425,11 @@ mod tests { assert_eq!(qualified_table_name(Some(DatabaseType::Kwdb), Some("public"), "users"), "\"public\".\"users\""); assert_eq!(qualified_table_name(Some(DatabaseType::Mysql), Some("public"), "users"), "`users`"); assert_eq!(qualified_table_name(Some(DatabaseType::Jdbc), Some("cbsdw_dwd"), "dwd_test_df"), "dwd_test_df"); + assert_eq!(qualified_table_name(Some(DatabaseType::Iotdb), Some("root.test"), "device2"), "root.test.device2"); + assert_eq!( + qualified_table_name(Some(DatabaseType::Iotdb), Some("root.test"), "root.test.device2"), + "root.test.device2" + ); } #[test] @@ -474,6 +492,17 @@ mod tests { }), "SELECT TOP 100 * FROM \"Ens\".\"AlarmResponse\"" ); + assert_eq!( + build_table_select_sql(TableSelectSqlOptions { + database_type: Some(DatabaseType::Iotdb), + schema: Some("root.test"), + table_name: "device2", + columns: &[], + order_columns: &[], + limit: 100, + }), + "SELECT * FROM root.test.device2 LIMIT 100;" + ); } #[test] @@ -526,6 +555,22 @@ mod tests { }), "SELECT TOP 100 * FROM \"Ens\".\"AlarmResponse\"" ); + assert_eq!( + build_table_data_select_sql(TableDataSelectSqlOptions { + database_type: Some(DatabaseType::Iotdb), + schema: Some("root.test".to_string()), + table_name: "device2".to_string(), + primary_keys: Vec::new(), + columns: Vec::new(), + fallback_order_columns: Vec::new(), + order_by: None, + limit: Some(100), + offset: None, + where_input: None, + include_row_id: false, + }), + "SELECT * FROM root.test.device2 LIMIT 100;" + ); } #[test] diff --git a/crates/dbx-core/tests/agent_service.rs b/crates/dbx-core/tests/agent_service.rs index 79db283d58..cda5a574ec 100644 --- a/crates/dbx-core/tests/agent_service.rs +++ b/crates/dbx-core/tests/agent_service.rs @@ -43,6 +43,7 @@ fn built_in_agent_list_includes_expected_driver_labels() { let agents = build_agent_list(&manager, None); assert!(agents.iter().any(|agent| agent.db_type == "tdengine" && agent.label == "TDengine")); + assert!(agents.iter().any(|agent| agent.db_type == "iotdb" && agent.label == "Apache IoTDB")); assert!(agents.iter().any(|agent| agent.db_type == "yashandb" && agent.label == "崖山 YashanDB")); assert!(agents.iter().any(|agent| agent.db_type == "access" && agent.label == "Microsoft Access")); } diff --git a/crates/dbx-core/tests/database_capabilities.rs b/crates/dbx-core/tests/database_capabilities.rs index 9cec252ac4..2d63f6509c 100644 --- a/crates/dbx-core/tests/database_capabilities.rs +++ b/crates/dbx-core/tests/database_capabilities.rs @@ -50,6 +50,7 @@ fn maps_agent_database_types_to_driver_keys() { assert_eq!(agent_key(&DatabaseType::Trino, None), Some("trino")); assert_eq!(agent_key(&DatabaseType::Hive, None), Some("hive")); assert_eq!(agent_key(&DatabaseType::Tdengine, None), Some("tdengine")); + assert_eq!(agent_key(&DatabaseType::Iotdb, None), Some("iotdb")); assert_eq!(agent_key(&DatabaseType::Yashandb, None), Some("yashandb")); assert_eq!(agent_key(&DatabaseType::Databricks, None), Some("databricks")); assert_eq!(agent_key(&DatabaseType::SapHana, None), Some("saphana")); @@ -72,6 +73,7 @@ fn classifies_agent_database_types() { assert!(is_agent_type(&DatabaseType::Trino)); assert!(is_agent_type(&DatabaseType::Hive)); assert!(is_agent_type(&DatabaseType::Tdengine)); + assert!(is_agent_type(&DatabaseType::Iotdb)); assert!(is_agent_type(&DatabaseType::Yashandb)); assert!(is_agent_type(&DatabaseType::Databricks)); assert!(is_agent_type(&DatabaseType::SapHana)); @@ -125,6 +127,7 @@ fn skips_tcp_probe_for_local_file_plugin_and_agent_types() { assert!(skips_tcp_probe(&DatabaseType::Trino)); assert!(skips_tcp_probe(&DatabaseType::Oracle)); assert!(skips_tcp_probe(&DatabaseType::Tdengine)); + assert!(skips_tcp_probe(&DatabaseType::Iotdb)); assert!(skips_tcp_probe(&DatabaseType::Yashandb)); assert!(skips_tcp_probe(&DatabaseType::Databricks)); assert!(skips_tcp_probe(&DatabaseType::OceanbaseOracle)); diff --git a/packages/app-tests/connectionUrl.test.ts b/packages/app-tests/connectionUrl.test.ts index 56d3d8f442..7296125ac4 100644 --- a/packages/app-tests/connectionUrl.test.ts +++ b/packages/app-tests/connectionUrl.test.ts @@ -135,6 +135,20 @@ test("parses XuguDB JDBC URLs", () => { assert.equal(parsed.urlParams, "charset=utf8"); }); +test("parses Apache IoTDB JDBC URLs", () => { + const parsed = parseConnectionUrl("jdbc:iotdb://root:secret@iotdb.example.com:6667?sql_dialect=table"); + + assert.equal(parsed.dbType, "iotdb"); + assert.equal(parsed.driverProfile, "iotdb"); + assert.equal(parsed.driverLabel, "Apache IoTDB"); + assert.equal(parsed.host, "iotdb.example.com"); + assert.equal(parsed.port, 6667); + assert.equal(parsed.username, "root"); + assert.equal(parsed.password, "secret"); + assert.equal(parsed.database, undefined); + assert.equal(parsed.urlParams, "sql_dialect=table"); +}); + test("parses GBase 8s JDBC URLs", () => { const parsed = parseConnectionUrl( "jdbc:gbasedbt-sqli://gbasedbt:secret@gbase.example.com:20013/testdb:GBASEDBTSERVER=gbase01;CLIENT_LOCALE=zh_cn.utf8", diff --git a/packages/app-tests/connectionUrlPlaceholder.test.ts b/packages/app-tests/connectionUrlPlaceholder.test.ts index b7497ac66c..d10f9398ad 100644 --- a/packages/app-tests/connectionUrlPlaceholder.test.ts +++ b/packages/app-tests/connectionUrlPlaceholder.test.ts @@ -23,6 +23,7 @@ const expected: Record = { dameng: "dm://user:password@host:port", tdengine: "tdengine://user:password@host:6041/database", xugu: "xugu://user:password@host:5138/database", + iotdb: "iotdb://user:password@host:6667/root.test", bigquery: "bigquery://https://www.googleapis.com/bigquery/v2:443/project-id", jdbc: "jdbc:mysql://host:3306/database", }; diff --git a/packages/app-tests/databaseCapabilities.test.ts b/packages/app-tests/databaseCapabilities.test.ts index 45b098e8e1..4d89112d9d 100644 --- a/packages/app-tests/databaseCapabilities.test.ts +++ b/packages/app-tests/databaseCapabilities.test.ts @@ -45,6 +45,13 @@ test("treats XuguDB as a schema-aware agent driver database", () => { assert.equal(supportsDriverManagement("xugu"), true); }); +test("treats IoTDB as a schema-aware agent driver database", () => { + assert.equal(TREE_SCHEMA_TYPES.has("iotdb"), true); + assert.equal(SCHEMA_AWARE_TYPES.has("iotdb"), true); + assert.equal(supportsDatabaseSearch("iotdb"), true); + assert.equal(supportsDriverManagement("iotdb"), true); +}); + test("treats Access as a local single-database agent driver", () => { assert.equal(SCHEMA_AWARE_TYPES.has("access"), false); assert.equal(supportsDriverManagement("access"), true); diff --git a/packages/app-tests/tableSelectSql.test.ts b/packages/app-tests/tableSelectSql.test.ts index c098f2ae75..236b7e40fc 100644 --- a/packages/app-tests/tableSelectSql.test.ts +++ b/packages/app-tests/tableSelectSql.test.ts @@ -15,3 +15,15 @@ test("JDBC table identifiers use backticks only when quoting is needed", () => { assert.equal(quoteTableIdentifier("jdbc", "daily orders"), "`daily orders`"); assert.equal(quoteTableIdentifier("jdbc", "daily`orders"), "`daily``orders`"); }); + +test("IoTDB table identifiers use tree paths without SQL quotes", () => { + assert.equal(quoteTableIdentifier("iotdb", "root.test.device2"), "root.test.device2"); + assert.equal( + qualifiedTableName({ databaseType: "iotdb", schema: "root.test", tableName: "device2" }), + "root.test.device2", + ); + assert.equal( + qualifiedTableName({ databaseType: "iotdb", schema: "root.test", tableName: "root.test.device2" }), + "root.test.device2", + ); +}); diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index bb0d2de349..91d17ec2d4 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -46,7 +46,7 @@ function formatQueryToolResult(result: QueryResult, title?: string) { } export const DBX_CONNECTION_TYPE_DESCRIPTION = - "Database type: postgres, mysql, sqlite, rqlite, redis, duckdb, clickhouse, sqlserver, mongodb, oracle, elasticsearch, doris, starrocks, redshift, dameng, kingbase, highgo, vastbase, goldendb, gaussdb, kwdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, iris, neo4j, cassandra, bigquery, kylin, sundb, tdengine, xugu, jdbc, access"; + "Database type: postgres, mysql, sqlite, rqlite, redis, duckdb, clickhouse, sqlserver, mongodb, oracle, elasticsearch, doris, starrocks, redshift, dameng, kingbase, highgo, vastbase, goldendb, gaussdb, kwdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, iris, neo4j, cassandra, bigquery, kylin, sundb, tdengine, iotdb, xugu, jdbc, access"; export function createDbxMcpServer(backend: Backend, options: { isWebMode?: boolean } = {}): McpServer { const isWebMode = options.isWebMode ?? !!process.env.DBX_WEB_URL; @@ -171,7 +171,7 @@ export function createDbxMcpServer(backend: Backend, options: { isWebMode?: bool name: z.string().describe("Connection name"), db_type: z.string().describe(DBX_CONNECTION_TYPE_DESCRIPTION), host: z.string().describe("Database host"), - port: z.number().optional().describe("Database port (TDengine defaults to 6041, XuguDB defaults to 5138)"), + port: z.number().optional().describe("Database port (TDengine defaults to 6041, IoTDB defaults to 6667, XuguDB defaults to 5138)"), username: z.string().default("").describe("Username"), password: z.string().default("").describe("Password"), database: z.string().optional().describe("Default database name"), @@ -181,7 +181,7 @@ export function createDbxMcpServer(backend: Backend, options: { isWebMode?: bool const existing = await backend.findConnection(name); if (existing) return text(`Connection "${name}" already exists.`); const FILE_BASED_TYPES = new Set(["sqlite", "duckdb", "access"]); - const DEFAULT_PORTS: Record = { kwdb: 26257, rqlite: 4001, tdengine: 6041, xugu: 5138 }; + const DEFAULT_PORTS: Record = { kwdb: 26257, rqlite: 4001, tdengine: 6041, iotdb: 6667, xugu: 5138 }; const resolvedPort = port ?? DEFAULT_PORTS[db_type] ?? (FILE_BASED_TYPES.has(db_type) ? 0 : undefined); if (resolvedPort === undefined) return text("Port is required for this database type."); const config = await backend.addConnection({ diff --git a/packages/node-core/src/diagnostics.ts b/packages/node-core/src/diagnostics.ts index 70871f4e6a..dfbbe33af5 100644 --- a/packages/node-core/src/diagnostics.ts +++ b/packages/node-core/src/diagnostics.ts @@ -46,6 +46,7 @@ export const BRIDGE_REQUIRED_TYPES = [ "oceanbase-oracle", "gbase", "tdengine", + "iotdb", "h2", "snowflake", "trino",