= {
bigquery: "bigquery",
cassandra: "cassandra",
doris: "doris",
+ manticoresearch: "manticoresearch.png",
selectdb: "selectdb",
tdengine: "tdengine",
starrocks: "starrocks",
diff --git a/apps/desktop/src/lib/connectionPresentation.ts b/apps/desktop/src/lib/connectionPresentation.ts
index 6bb3e0149..44aa463c0 100644
--- a/apps/desktop/src/lib/connectionPresentation.ts
+++ b/apps/desktop/src/lib/connectionPresentation.ts
@@ -82,6 +82,7 @@ export function connectionUrlPlaceholder(dbType: DatabaseType): string {
case "mysql":
case "doris":
case "starrocks":
+ case "manticoresearch":
return "mysql://user:password@host:port/database";
case "postgres":
@@ -162,4 +163,4 @@ export function connectionOptionSubtitle(connection?: ConnectionPresentationConf
export function connectionRedactedOptionSubtitle(connection?: ConnectionPresentationConfig): string {
return [connectionDriverLabel(connection), connectionRedactedEndpointLabel(connection)].filter(Boolean).join(" · ");
-}
+}
\ No newline at end of file
diff --git a/apps/desktop/src/lib/databaseFeatureSupport.ts b/apps/desktop/src/lib/databaseFeatureSupport.ts
index fef170e2a..928cbaeb3 100644
--- a/apps/desktop/src/lib/databaseFeatureSupport.ts
+++ b/apps/desktop/src/lib/databaseFeatureSupport.ts
@@ -82,9 +82,9 @@ export function supportsObjectBrowserTreeNode(dbType: DatabaseType | undefined,
}
export function supportsTableTruncate(dbType?: DatabaseType): boolean {
- return !!dbType && dbType !== "sqlite" && dbType !== "rqlite" && dbType !== "turso" && dbType !== "duckdb" && dbType !== "influxdb";
+ return !!dbType && dbType !== "sqlite" && dbType !== "rqlite" && dbType !== "turso" && dbType !== "duckdb" && dbType !== "influxdb" && dbType !== "manticoresearch";
}
export function usesPostgresLikeStructureCopy(dbType?: DatabaseType): boolean {
return !!dbType && PG_LIKE_STRUCTURE_TYPES.has(dbType);
-}
+}
\ No newline at end of file
diff --git a/apps/desktop/src/lib/visibleDatabases.ts b/apps/desktop/src/lib/visibleDatabases.ts
index 1c616b596..fd7eac3d3 100644
--- a/apps/desktop/src/lib/visibleDatabases.ts
+++ b/apps/desktop/src/lib/visibleDatabases.ts
@@ -4,6 +4,7 @@ const SYSTEM_DATABASE_RULES: Partial
>>
mysql: new Set(["information_schema", "mysql", "performance_schema", "sys"]),
doris: new Set(["information_schema", "mysql", "performance_schema", "sys"]),
starrocks: new Set(["information_schema", "mysql", "performance_schema", "sys"]),
+ manticoresearch: new Set(["information_schema", "mysql", "performance_schema", "sys"]),
goldendb: new Set(["information_schema", "mysql", "performance_schema", "sys"]),
gbase: new Set(["information_schema", "mysql", "performance_schema", "sys"]),
postgres: new Set(["template0", "template1"]),
@@ -94,4 +95,4 @@ export function filterDatabaseNamesForConnection(databaseNames: string[], connec
return databaseNames;
}
return databaseNames.filter((name) => !isSystemDatabaseName(connection?.db_type, name));
-}
+}
\ No newline at end of file
diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts
index ed9e27699..b5f41f4eb 100644
--- a/apps/desktop/src/stores/connectionStore.ts
+++ b/apps/desktop/src/stores/connectionStore.ts
@@ -241,6 +241,7 @@ export const useConnectionStore = defineStore("connection", () => {
elasticsearch: "Elasticsearch",
doris: "Doris",
starrocks: "StarRocks",
+ manticoresearch: "Manticore Search",
redshift: "Redshift",
dameng: "DM (Dameng)",
gaussdb: "GaussDB",
@@ -2768,4 +2769,4 @@ export const useConnectionStore = defineStore("connection", () => {
if (changed) updateLayoutAndRebuild(layout);
},
};
-});
+});
\ No newline at end of file
diff --git a/apps/desktop/src/types/database.ts b/apps/desktop/src/types/database.ts
index e96836f06..568229969 100644
--- a/apps/desktop/src/types/database.ts
+++ b/apps/desktop/src/types/database.ts
@@ -13,6 +13,7 @@ export type DatabaseType =
| "elasticsearch"
| "doris"
| "starrocks"
+ | "manticoresearch"
| "databend"
| "redshift"
| "dameng"
@@ -542,4 +543,4 @@ export interface SavedSqlFile {
export interface SavedSqlLibrary {
folders: SavedSqlFolder[];
files: SavedSqlFile[];
-}
+}
\ No newline at end of file
diff --git a/crates/dbx-core/assets/database-drivers.manifest.json b/crates/dbx-core/assets/database-drivers.manifest.json
index a1cd9b1c2..17ef47063 100644
--- a/crates/dbx-core/assets/database-drivers.manifest.json
+++ b/crates/dbx-core/assets/database-drivers.manifest.json
@@ -378,6 +378,35 @@
"driverManagement": false
}
},
+ {
+ "dbType": "manticoresearch",
+ "label": "Manticore Search",
+ "runtimeMode": "native",
+ "mcpMode": "direct",
+ "singleConnectionPool": false,
+ "metadataConnectionScoped": false,
+ "skipTcpProbe": false,
+ "defaultPort": 9306,
+ "supportLevel": "browse",
+ "capabilities": {
+ "queryExecution": true,
+ "metadataBrowse": true,
+ "objectBrowser": false,
+ "objectSource": false,
+ "schemaSearch": false,
+ "diagram": false,
+ "tableDataEdit": false,
+ "tableStructureEdit": false,
+ "tableImport": false,
+ "dataTransfer": false,
+ "sqlFileExecution": true,
+ "databaseCreate": false,
+ "fieldLineage": false,
+ "sqlExplain": false,
+ "userAdmin": false,
+ "driverManagement": false
+ }
+ },
{
"dbType": "redshift",
"label": "Redshift",
diff --git a/crates/dbx-core/src/connection.rs b/crates/dbx-core/src/connection.rs
index e4ac498e2..218479f2e 100644
--- a/crates/dbx-core/src/connection.rs
+++ b/crates/dbx-core/src/connection.rs
@@ -358,7 +358,7 @@ impl AppState {
.await?;
PoolKind::Mysql(pool, mode)
}
- DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => {
+ DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch | DatabaseType::Databend => {
let pool = if database.is_none() {
connect_bare_metadata_pool(&db_config, &host, port, connect_timeout, mysql_pool_max_connections)
.await?
diff --git a/crates/dbx-core/src/db/mysql.rs b/crates/dbx-core/src/db/mysql.rs
index 60cc0ca4c..bdc5b2fb1 100644
--- a/crates/dbx-core/src/db/mysql.rs
+++ b/crates/dbx-core/src/db/mysql.rs
@@ -29,8 +29,12 @@ impl MySqlQueryDialect {
pub fn for_connection(db_type: DatabaseType, driver_profile: Option<&str>) -> Self {
let profile = driver_profile.map(str::to_ascii_lowercase);
Self {
- supports_admin_show_results: matches!(db_type, DatabaseType::Doris | DatabaseType::StarRocks)
- || profile.as_deref().is_some_and(|profile| matches!(profile, "doris" | "selectdb" | "starrocks")),
+ supports_admin_show_results: matches!(
+ db_type,
+ DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch
+ ) || profile
+ .as_deref()
+ .is_some_and(|profile| matches!(profile, "doris" | "selectdb" | "starrocks" | "manticoresearch")),
}
}
}
diff --git a/crates/dbx-core/src/models/connection.rs b/crates/dbx-core/src/models/connection.rs
index 6cf07e66c..23997f38a 100644
--- a/crates/dbx-core/src/models/connection.rs
+++ b/crates/dbx-core/src/models/connection.rs
@@ -240,6 +240,8 @@ pub enum DatabaseType {
Doris,
#[serde(rename = "starrocks")]
StarRocks,
+ #[serde(rename = "manticoresearch")]
+ ManticoreSearch,
Databend,
Redshift,
Dameng,
@@ -593,12 +595,10 @@ impl ConnectionConfig {
}
pub fn needs_bare_mysql(&self) -> bool {
- matches!(self.db_type, DatabaseType::Doris | DatabaseType::StarRocks)
- || self
- .driver_profile
- .as_deref()
- .map(|p| p.to_lowercase())
- .is_some_and(|p| matches!(p.as_str(), "doris" | "starrocks" | "selectdb" | "oceanbase"))
+ matches!(self.db_type, DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch)
+ || self.driver_profile.as_deref().map(|p| p.to_lowercase()).is_some_and(|p| {
+ matches!(p.as_str(), "doris" | "starrocks" | "manticoresearch" | "selectdb" | "oceanbase")
+ })
}
pub fn canonicalized(&self) -> Self {
@@ -656,7 +656,11 @@ impl ConnectionConfig {
let fragment = self.redis_tls_insecure_fragment();
format!("{scheme}://{host}:{port}/{fragment}")
}
- DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => {
+ DatabaseType::Mysql
+ | DatabaseType::Doris
+ | DatabaseType::StarRocks
+ | DatabaseType::ManticoreSearch
+ | DatabaseType::Databend => {
let suffix = if params.is_empty() { String::new() } else { format!("?{params}") };
format!("mysql://{host}:{port}{db_part}{suffix}")
}
@@ -777,7 +781,11 @@ impl ConnectionConfig {
format!("{scheme}://{username}:{password}@{host}:{port}/{fragment}")
}
}
- DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => {
+ DatabaseType::Mysql
+ | DatabaseType::Doris
+ | DatabaseType::StarRocks
+ | DatabaseType::ManticoreSearch
+ | DatabaseType::Databend => {
let suffix = if params.is_empty() { String::new() } else { format!("?{params}") };
format!("mysql://{}:{}@{host}:{port}{db_part}{suffix}", username, password)
}
@@ -958,7 +966,7 @@ impl ConnectionConfig {
DatabaseType::Mysql => {
normalize_mysql_url_params(value, self.mysql_uses_tls(), self.ca_cert_path.trim().is_empty())
}
- DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Databend => {
+ DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch | DatabaseType::Databend => {
normalize_bare_mysql_url_params(value)
}
DatabaseType::Postgres | DatabaseType::Redshift => normalize_postgres_url_params(value, self.ssl),
diff --git a/crates/dbx-core/src/schema.rs b/crates/dbx-core/src/schema.rs
index c3ccf6744..ca6b99e25 100644
--- a/crates/dbx-core/src/schema.rs
+++ b/crates/dbx-core/src/schema.rs
@@ -319,7 +319,9 @@ async fn list_databases_once(state: &AppState, connection_id: &str) -> Result {
- db::mysql::list_databases_show(p).await
+ db::mysql::list_databases_show(p)
+ .await
+ .map(|databases| filter_mysql_system_databases_for_config(databases, db_config.as_ref()))
}
PoolKind::Mysql(p, mode) => dispatch_mysql!(p, mode, db::mysql::list_databases, db::ob_oracle::list_databases),
PoolKind::Postgres(p) => db::postgres::list_databases(p).await,
@@ -599,8 +601,8 @@ fn filter_table_infos(
#[cfg(test)]
mod tests {
use super::{
- clickhouse_metadata_database, deduplicate_column_infos, filter_table_infos,
- is_agent_postgres_metadata_fallback_config,
+ clickhouse_metadata_database, deduplicate_column_infos, filter_mysql_system_databases_for_config,
+ filter_table_infos, is_agent_postgres_metadata_fallback_config,
};
#[cfg(feature = "duckdb-bundled")]
use super::{duckdb_attach_database, duckdb_list_databases, duckdb_query_tables_in_database};
@@ -675,6 +677,39 @@ mod tests {
}
}
+ fn test_database_info(name: &str) -> super::db::DatabaseInfo {
+ super::db::DatabaseInfo { name: name.to_string() }
+ }
+
+ #[test]
+ fn manticoresearch_database_list_filters_mysql_system_databases() {
+ let databases = vec![
+ test_database_info("Manticore"),
+ test_database_info("information_schema"),
+ test_database_info("mysql"),
+ test_database_info("performance_schema"),
+ test_database_info("sys"),
+ ];
+ let config = test_connection_config(DatabaseType::ManticoreSearch);
+
+ let filtered = filter_mysql_system_databases_for_config(databases, Some(&config));
+
+ assert_eq!(filtered.into_iter().map(|database| database.name).collect::>(), vec!["Manticore"]);
+ }
+
+ #[test]
+ fn doris_database_list_keeps_system_databases() {
+ let databases = vec![test_database_info("information_schema"), test_database_info("analytics")];
+ let config = test_connection_config(DatabaseType::Doris);
+
+ let filtered = filter_mysql_system_databases_for_config(databases, Some(&config));
+
+ assert_eq!(
+ filtered.into_iter().map(|database| database.name).collect::>(),
+ vec!["information_schema", "analytics"]
+ );
+ }
+
#[test]
fn filter_table_infos_applies_filter_offset_and_limit() {
let tables = vec![
@@ -1469,8 +1504,28 @@ fn is_opengauss_family_config(config: &ConnectionConfig) -> bool {
}
fn is_doris_family_config(config: &ConnectionConfig) -> bool {
- matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks)
- || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks"))
+ matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch)
+ || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks" | "manticoresearch"))
+}
+
+fn is_manticoresearch_config(config: &ConnectionConfig) -> bool {
+ matches!(config.db_type, DatabaseType::ManticoreSearch)
+ || matches!(config.driver_profile.as_deref(), Some("manticoresearch"))
+}
+
+fn filter_mysql_system_databases_for_config(
+ databases: Vec,
+ config: Option<&ConnectionConfig>,
+) -> Vec {
+ if !config.is_some_and(is_manticoresearch_config) {
+ return databases;
+ }
+
+ databases.into_iter().filter(|database| !is_mysql_system_database(&database.name)).collect()
+}
+
+fn is_mysql_system_database(name: &str) -> bool {
+ matches!(name.to_ascii_lowercase().as_str(), "information_schema" | "mysql" | "performance_schema" | "sys")
}
fn sql_string(value: &str) -> String {
diff --git a/crates/dbx-core/src/schema/providers/native.rs b/crates/dbx-core/src/schema/providers/native.rs
index 013e3a6fa..1d62799d7 100644
--- a/crates/dbx-core/src/schema/providers/native.rs
+++ b/crates/dbx-core/src/schema/providers/native.rs
@@ -7,7 +7,9 @@ pub(in crate::schema) async fn list_databases(
config: Option<&ConnectionConfig>,
) -> Result, String> {
match pool {
- PoolKind::Mysql(p, _) if config.is_some_and(is_doris_family_config) => db::mysql::list_databases_show(p).await,
+ PoolKind::Mysql(p, _) if config.is_some_and(is_doris_family_config) => db::mysql::list_databases_show(p)
+ .await
+ .map(|databases| filter_mysql_system_databases_for_config(databases, config)),
PoolKind::Mysql(p, mode) if *mode == MysqlMode::OceanBaseOracle => db::ob_oracle::list_databases(p).await,
PoolKind::Mysql(p, _) => db::mysql::list_databases(p).await,
PoolKind::Postgres(p) => db::postgres::list_databases(p).await,
@@ -262,6 +264,26 @@ fn is_opengauss_family_config(config: &ConnectionConfig) -> bool {
}
fn is_doris_family_config(config: &ConnectionConfig) -> bool {
- matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks)
- || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks"))
+ matches!(config.db_type, DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch)
+ || matches!(config.driver_profile.as_deref(), Some("doris" | "selectdb" | "starrocks" | "manticoresearch"))
+}
+
+fn is_manticoresearch_config(config: &ConnectionConfig) -> bool {
+ matches!(config.db_type, DatabaseType::ManticoreSearch)
+ || matches!(config.driver_profile.as_deref(), Some("manticoresearch"))
+}
+
+fn filter_mysql_system_databases_for_config(
+ databases: Vec,
+ config: Option<&ConnectionConfig>,
+) -> Vec {
+ if !config.is_some_and(is_manticoresearch_config) {
+ return databases;
+ }
+
+ databases.into_iter().filter(|database| !is_mysql_system_database(&database.name)).collect()
+}
+
+fn is_mysql_system_database(name: &str) -> bool {
+ matches!(name.to_ascii_lowercase().as_str(), "information_schema" | "mysql" | "performance_schema" | "sys")
}
diff --git a/crates/dbx-core/src/sql.rs b/crates/dbx-core/src/sql.rs
index 4d5dcfcea..62753ac9e 100644
--- a/crates/dbx-core/src/sql.rs
+++ b/crates/dbx-core/src/sql.rs
@@ -64,7 +64,11 @@ impl SqlParsingOptions {
Self {
supports_hash_line_comments: matches!(
db_type,
- DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Goldendb
+ DatabaseType::Mysql
+ | DatabaseType::Doris
+ | DatabaseType::StarRocks
+ | DatabaseType::ManticoreSearch
+ | DatabaseType::Goldendb
),
supports_oracle_plsql_blocks: matches!(
db_type,
@@ -1203,13 +1207,27 @@ fn executable_sql_keyword_matches(token: &str, keyword: &str) -> bool {
}
fn is_mysql_compatible_import_target(db_type: &DatabaseType, driver_profile: Option<&str>) -> bool {
- matches!(db_type, DatabaseType::Mysql | DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::Goldendb)
- || driver_profile.map(|profile| profile.to_ascii_lowercase()).is_some_and(|profile| {
- matches!(
- profile.as_str(),
- "mariadb" | "tidb" | "oceanbase" | "custom_mysql" | "doris" | "starrocks" | "selectdb" | "goldendb"
- )
- })
+ matches!(
+ db_type,
+ DatabaseType::Mysql
+ | DatabaseType::Doris
+ | DatabaseType::StarRocks
+ | DatabaseType::ManticoreSearch
+ | DatabaseType::Goldendb
+ ) || driver_profile.map(|profile| profile.to_ascii_lowercase()).is_some_and(|profile| {
+ matches!(
+ profile.as_str(),
+ "mariadb"
+ | "tidb"
+ | "oceanbase"
+ | "custom_mysql"
+ | "doris"
+ | "starrocks"
+ | "manticoresearch"
+ | "selectdb"
+ | "goldendb"
+ )
+ })
}
fn mysql_executable_comment_body(statement: &str) -> Option<&str> {
diff --git a/crates/dbx-core/src/sql_analysis.rs b/crates/dbx-core/src/sql_analysis.rs
index 642b04fcb..15e35b030 100644
--- a/crates/dbx-core/src/sql_analysis.rs
+++ b/crates/dbx-core/src/sql_analysis.rs
@@ -91,7 +91,7 @@ fn starts_with_duckdb_parser_gap_sql(sql: &str) -> bool {
fn normalize_dialect(dialect: Option<&str>) -> String {
match dialect.unwrap_or("generic").to_ascii_lowercase().as_str() {
"postgres" | "postgresql" | "redshift" | "opengauss" | "gaussdb" | "highgo" => "postgres".to_string(),
- "mysql" | "mariadb" | "doris" | "starrocks" | "oceanbase" => "mysql".to_string(),
+ "mysql" | "mariadb" | "doris" | "starrocks" | "manticoresearch" | "oceanbase" => "mysql".to_string(),
"sqlite" => "sqlite".to_string(),
"sqlserver" | "mssql" => "sqlserver".to_string(),
"clickhouse" => "clickhouse".to_string(),
diff --git a/crates/dbx-core/src/sql_dialect/identifiers.rs b/crates/dbx-core/src/sql_dialect/identifiers.rs
index 5d4a11971..f1ffb61fe 100644
--- a/crates/dbx-core/src/sql_dialect/identifiers.rs
+++ b/crates/dbx-core/src/sql_dialect/identifiers.rs
@@ -36,6 +36,7 @@ pub fn quote_table_identifier(database_type: Option, name: &str) -
DatabaseType::Mysql
| DatabaseType::Goldendb
| DatabaseType::StarRocks
+ | DatabaseType::ManticoreSearch
| DatabaseType::Hive
| DatabaseType::Databend
| DatabaseType::Tdengine
diff --git a/crates/dbx-core/src/sql_risk.rs b/crates/dbx-core/src/sql_risk.rs
index c4339374f..9b330b010 100644
--- a/crates/dbx-core/src/sql_risk.rs
+++ b/crates/dbx-core/src/sql_risk.rs
@@ -34,7 +34,7 @@ impl std::fmt::Display for SqlRisk {
fn normalize_dialect(dialect: &str) -> &'static str {
match dialect.to_ascii_lowercase().as_str() {
"postgres" | "postgresql" | "redshift" | "opengauss" | "gaussdb" | "highgo" => "postgres",
- "mysql" | "mariadb" | "doris" | "starrocks" | "oceanbase" => "mysql",
+ "mysql" | "mariadb" | "doris" | "starrocks" | "manticoresearch" | "oceanbase" => "mysql",
"sqlite" => "sqlite",
"sqlserver" | "mssql" => "sqlserver",
"clickhouse" => "clickhouse",
diff --git a/docs/app/[lang]/databases/page.tsx b/docs/app/[lang]/databases/page.tsx
index b1f18cbf5..fc3d4900a 100644
--- a/docs/app/[lang]/databases/page.tsx
+++ b/docs/app/[lang]/databases/page.tsx
@@ -19,6 +19,7 @@ const databaseSupport = [
{ name: "Elasticsearch", icon: "/icons/database/elasticsearch.svg", tone: "#00bfb3" },
{ name: "Doris", icon: "/icons/database/doris.svg", tone: "#5b7cfa" },
{ name: "StarRocks", icon: "/icons/database/starrocks.svg", tone: "#6750ff" },
+ { name: "Manticore Search", icon: "/icons/database/manticoresearch.png", tone: "#b8e646" },
{ name: "Redshift", icon: "/icons/database/redshift.svg", tone: "#8c4fff" },
{ name: "Dameng", icon: "/icons/database/dm.svg", tone: "#3857ff" },
{ name: "GaussDB", icon: "/icons/database/gaussdb.svg", tone: "#ff5a3d" },
diff --git a/docs/app/[lang]/page.tsx b/docs/app/[lang]/page.tsx
index 125df2c2b..cf013304a 100644
--- a/docs/app/[lang]/page.tsx
+++ b/docs/app/[lang]/page.tsx
@@ -71,6 +71,7 @@ const databaseSupport = [
{ name: "Elasticsearch", icon: "/icons/database/elasticsearch.svg", tone: "#00bfb3" },
{ name: "Doris", icon: "/icons/database/doris.svg", tone: "#5b7cfa" },
{ name: "StarRocks", icon: "/icons/database/starrocks.svg", tone: "#6750ff" },
+ { name: "Manticore Search", icon: "/icons/database/manticoresearch.png", tone: "#b8e646" },
{ name: "Redshift", icon: "/icons/database/redshift.svg", tone: "#8c4fff" },
{ name: "Dameng", icon: "/icons/database/dm.svg", tone: "#3857ff" },
{ name: "GaussDB", icon: "/icons/database/gaussdb.svg", tone: "#ff5a3d" },
diff --git a/docs/content/docs/databases.cn.mdx b/docs/content/docs/databases.cn.mdx
index 4c30de776..8ec1855ee 100644
--- a/docs/content/docs/databases.cn.mdx
+++ b/docs/content/docs/databases.cn.mdx
@@ -13,7 +13,7 @@ description: 了解 DBX 可以连接哪些数据库,以及每类高级功能
| ------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| 核心 SQL 数据库 | MySQL、PostgreSQL、SQLite、DuckDB、ClickHouse、SQL Server、Oracle、Redshift、DM、GaussDB、KWDB、Teradata、Vertica、Exasol、Firebird、SAP HANA、崖山 YashanDB、GBase | 直接出现在 DBX 连接选择器中 |
| 文档与键值数据库 | Redis、MongoDB、Elasticsearch、etcd | 根据数据模型使用专门浏览器或查询流程,不完全等同于关系型表格 |
-| MySQL 兼容类型 | MariaDB、TiDB、OceanBase、Doris、SelectDB、StarRocks、GoldenDB、TDSQL、PolarDB、GreatSQL、自定义 MySQL | 复用 MySQL 风格连接能力 |
+| MySQL 兼容类型 | MariaDB、TiDB、OceanBase、Doris、SelectDB、StarRocks、Manticore Search、GoldenDB、TDSQL、PolarDB、GreatSQL、自定义 MySQL | 复用 MySQL 风格连接能力 |
| PostgreSQL 兼容类型 | openGauss、KingBase、HighGo、Vastbase、CockroachDB、自定义 PostgreSQL | 复用 PostgreSQL 风格连接能力 |
| 文件型数据库 | SQLite、DuckDB、Microsoft Access、RQLite、Turso | 选择本地数据库文件或 HTTP 端点,不填写主机和端口 |
| 时序与边缘数据库 | InfluxDB、IoTDB、TDengine、Databend | 面向时序、IoT 或边缘场景优化 |
@@ -34,6 +34,7 @@ description: 了解 DBX 可以连接哪些数据库,以及每类高级功能
| TiDB | 4000 |
| OceanBase | 2881 |
| Doris / SelectDB / StarRocks / Databend | 9030 |
+| Manticore Search | 9306 |
| Redshift | 5439 |
| CockroachDB | 26257 |
| DM | 5236 |
diff --git a/docs/content/docs/databases.mdx b/docs/content/docs/databases.mdx
index 6d0323760..f68cbf0cf 100644
--- a/docs/content/docs/databases.mdx
+++ b/docs/content/docs/databases.mdx
@@ -13,7 +13,7 @@ The connection dialog exposes ready-to-use profiles with default ports and drive
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| Core SQL engines | MySQL, PostgreSQL, SQLite, DuckDB, ClickHouse, SQL Server, Oracle, Redshift, DM, GaussDB, KWDB, Teradata, Vertica, Exasol, Firebird, SAP HANA, YashanDB, GBase | Available directly in the DBX connection picker |
| Document and key-value engines | Redis, MongoDB, Elasticsearch, etcd | Use dedicated browsers or query flows instead of the generic relational grid where appropriate |
-| MySQL-compatible profiles | MariaDB, TiDB, OceanBase, Doris, SelectDB, StarRocks, GoldenDB, TDSQL, PolarDB, GreatSQL, custom MySQL | Reuse MySQL-style connection handling where the engine speaks a compatible protocol |
+| MySQL-compatible profiles | MariaDB, TiDB, OceanBase, Doris, SelectDB, StarRocks, Manticore Search, GoldenDB, TDSQL, PolarDB, GreatSQL, custom MySQL | Reuse MySQL-style connection handling where the engine speaks a compatible protocol |
| PostgreSQL-compatible profiles | openGauss, KingBase, HighGo, Vastbase, CockroachDB, custom PostgreSQL | Reuse PostgreSQL-style connection handling where the engine speaks a compatible protocol |
| File-based engines | SQLite, DuckDB, Microsoft Access, RQLite, Turso | Choose a local database file or HTTP endpoint instead of host and port |
| Time-series and edge | InfluxDB, IoTDB, TDengine, Databend | Optimized for time-series, IoT, or edge workloads |
@@ -34,6 +34,7 @@ The connection dialog exposes ready-to-use profiles with default ports and drive
| TiDB | 4000 |
| OceanBase | 2881 |
| Doris / SelectDB / StarRocks / Databend | 9030 |
+| Manticore Search | 9306 |
| Redshift | 5439 |
| CockroachDB | 26257 |
| DM | 5236 |
diff --git a/docs/public/icons/database/manticoresearch.png b/docs/public/icons/database/manticoresearch.png
new file mode 100644
index 000000000..420cb72a5
Binary files /dev/null and b/docs/public/icons/database/manticoresearch.png differ
diff --git a/packages/app-tests/connectionUrlPlaceholder.test.ts b/packages/app-tests/connectionUrlPlaceholder.test.ts
index 45516eaa0..24b8b8f10 100644
--- a/packages/app-tests/connectionUrlPlaceholder.test.ts
+++ b/packages/app-tests/connectionUrlPlaceholder.test.ts
@@ -6,6 +6,7 @@ const expected: Record = {
mysql: "mysql://user:password@host:port/database",
doris: "mysql://user:password@host:port/database",
starrocks: "mysql://user:password@host:port/database",
+ manticoresearch: "mysql://user:password@host:port/database",
postgres: "postgresql://user:password@host:port/database",
gaussdb: "postgresql://user:password@host:port/database",
kwdb: "postgresql://user:password@host:port/database",
@@ -42,6 +43,7 @@ test("mysql-family types share the same placeholder", () => {
const mysql = connectionUrlPlaceholder("mysql");
assert.equal(connectionUrlPlaceholder("doris"), mysql);
assert.equal(connectionUrlPlaceholder("starrocks"), mysql);
+ assert.equal(connectionUrlPlaceholder("manticoresearch"), mysql);
});
test("postgres-family types share the same placeholder", () => {
diff --git a/packages/app-tests/databaseCapabilities.test.ts b/packages/app-tests/databaseCapabilities.test.ts
index d276b6304..9b6f71612 100644
--- a/packages/app-tests/databaseCapabilities.test.ts
+++ b/packages/app-tests/databaseCapabilities.test.ts
@@ -225,7 +225,9 @@ test("describes feature support through capability helpers", () => {
assert.equal(supportsTableStructureEditing("clickhouse"), true);
assert.equal(supportsTableStructureEditing("rqlite"), true);
assert.equal(supportsTableStructureEditing("mongodb"), false);
+ assert.equal(supportsTableStructureEditing("manticoresearch"), false);
assert.equal(supportsDatabaseCreation("clickhouse"), true);
+ assert.equal(supportsDatabaseCreation("manticoresearch"), false);
assert.equal(supportsDatabaseCreation("sqlite"), false);
assert.equal(supportsFieldLineage("gaussdb"), true);
assert.equal(supportsFieldLineage("kwdb"), true);
@@ -233,15 +235,19 @@ test("describes feature support through capability helpers", () => {
assert.equal(supportsTransfer("duckdb"), true);
assert.equal(supportsTransfer("hive"), true);
assert.equal(supportsTransfer("mongodb"), true);
+ assert.equal(supportsTransfer("manticoresearch"), false);
assert.equal(supportsDriverManagement("oracle"), true);
assert.equal(supportsDriverManagement("mysql"), false);
+ assert.equal(supportsDriverManagement("manticoresearch"), false);
assert.equal(supportsDriverManagement("kwdb"), false);
assert.equal(usesPostgresLikeStructureCopy("gaussdb"), true);
assert.equal(usesPostgresLikeStructureCopy("kwdb"), true);
assert.equal(usesPostgresLikeStructureCopy("mysql"), false);
assert.equal(supportsObjectBrowser("mysql"), true);
+ assert.equal(supportsObjectBrowser("manticoresearch"), false);
assert.equal(supportsObjectBrowser("mongodb"), false);
assert.equal(supportsTableTruncate("mysql"), true);
+ assert.equal(supportsTableTruncate("manticoresearch"), false);
assert.equal(supportsTableTruncate("duckdb"), false);
assert.equal(supportsTableTruncate("rqlite"), false);
});
@@ -249,6 +255,7 @@ test("describes feature support through capability helpers", () => {
test("loads product support levels and capabilities from the driver manifest", () => {
assert.equal(manifestDatabaseTypes().includes("mysql"), true);
assert.equal(databaseSupportLevel("mysql"), "operate");
+ assert.equal(databaseSupportLevel("manticoresearch"), "browse");
assert.equal(databaseSupportLevel("jdbc"), "browse");
assert.equal(databaseSupportLevel("redis"), "connect");
@@ -266,6 +273,27 @@ test("loads product support levels and capabilities from the driver manifest", (
userAdmin: false,
},
);
+
+ assert.deepEqual(
+ {
+ queryExecution: databaseProductCapabilities("manticoresearch").queryExecution,
+ metadataBrowse: databaseProductCapabilities("manticoresearch").metadataBrowse,
+ objectBrowser: databaseProductCapabilities("manticoresearch").objectBrowser,
+ tableDataEdit: databaseProductCapabilities("manticoresearch").tableDataEdit,
+ tableStructureEdit: databaseProductCapabilities("manticoresearch").tableStructureEdit,
+ sqlFileExecution: databaseProductCapabilities("manticoresearch").sqlFileExecution,
+ userAdmin: databaseProductCapabilities("manticoresearch").userAdmin,
+ },
+ {
+ queryExecution: true,
+ metadataBrowse: true,
+ objectBrowser: false,
+ tableDataEdit: false,
+ tableStructureEdit: false,
+ sqlFileExecution: true,
+ userAdmin: false,
+ },
+ );
});
test("object browser entry follows database tree shape", () => {
diff --git a/packages/app-tests/tableStructureCapabilities.test.ts b/packages/app-tests/tableStructureCapabilities.test.ts
index fa70c2af7..275abf782 100644
--- a/packages/app-tests/tableStructureCapabilities.test.ts
+++ b/packages/app-tests/tableStructureCapabilities.test.ts
@@ -94,7 +94,7 @@ test("limited analytic engines can open the editor for supported operations only
});
test("unsupported non-relational databases do not open the structure editor", () => {
- for (const dbType of ["redis", "mongodb", "elasticsearch", "neo4j", undefined] as const) {
+ for (const dbType of ["redis", "mongodb", "elasticsearch", "manticoresearch", "neo4j", undefined] as const) {
const caps = getTableStructureCapabilities(dbType);
assert.equal(caps.dialect, "unsupported");
assert.equal(canEditTableStructure(dbType), false);
diff --git a/packages/app-tests/visibleDatabases.test.ts b/packages/app-tests/visibleDatabases.test.ts
index 8f07d9ebd..4b25f99dd 100644
--- a/packages/app-tests/visibleDatabases.test.ts
+++ b/packages/app-tests/visibleDatabases.test.ts
@@ -29,8 +29,10 @@ test("normalizes selected database names against fresh database names", () => {
test("mysql system databases are hidden by default but can be explicitly selected", () => {
const databases = ["app", "information_schema", "mysql", "performance_schema", "sys"];
assert.deepEqual(filterDatabaseNamesForConnection(databases, { db_type: "mysql" }), ["app"]);
+ assert.deepEqual(filterDatabaseNamesForConnection(databases, { db_type: "manticoresearch" }), ["app"]);
assert.deepEqual(filterDatabaseNamesForConnection(databases, { db_type: "mysql", visible_databases: ["app", "sys"] }), ["app", "sys"]);
assert.equal(isSystemDatabaseName("mysql", "performance_schema"), true);
+ assert.equal(isSystemDatabaseName("manticoresearch", "information_schema"), true);
assert.equal(isSystemDatabaseName("postgres", "information_schema"), false);
});
diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts
index fffe58f99..e51ed0d4b 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, etcd, doris, starrocks, redshift, dameng, kingbase, highgo, vastbase, goldendb, databend, gaussdb, kwdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, influxdb, iris, neo4j, cassandra, bigquery, kylin, sundb, tdengine, iotdb, xugu, jdbc, access";
+ "Database type: postgres, mysql, sqlite, rqlite, redis, duckdb, clickhouse, sqlserver, mongodb, oracle, elasticsearch, etcd, doris, starrocks, manticoresearch, redshift, dameng, kingbase, highgo, vastbase, goldendb, databend, gaussdb, kwdb, yashandb, databricks, saphana, teradata, vertica, firebird, exasol, opengauss, oceanbase-oracle, gbase, h2, snowflake, trino, hive, db2, informix, influxdb, iris, neo4j, cassandra, bigquery, kylin, sundb, tdengine, iotdb, xugu, jdbc, access";
const FILE_CAPABLE_CONNECTION_TYPES = new Set(["sqlite", "duckdb", "access", "h2"]);
export function createDbxMcpServer(backend: Backend, options: { isWebMode?: boolean } = {}): McpServer {
diff --git a/packages/node-core/src/database.ts b/packages/node-core/src/database.ts
index 2d6b2491a..d4859cedf 100644
--- a/packages/node-core/src/database.ts
+++ b/packages/node-core/src/database.ts
@@ -284,7 +284,7 @@ function portBytes(port: number): Buffer {
}
function isMysqlType(dbType: string): boolean {
- return dbType === "mysql" || dbType === "doris" || dbType === "starrocks";
+ return dbType === "mysql" || dbType === "doris" || dbType === "starrocks" || dbType === "manticoresearch";
}
interface BridgeQueryResult {
diff --git a/packages/node-core/src/diagnostics.ts b/packages/node-core/src/diagnostics.ts
index a8f7dff79..859cfa7e7 100644
--- a/packages/node-core/src/diagnostics.ts
+++ b/packages/node-core/src/diagnostics.ts
@@ -2,7 +2,7 @@ import { access, readFile } from "node:fs/promises";
import { bridgePortFilePath, dbPath, appDataDir } from "./paths.js";
import { inspectConnectionStore } from "./connections.js";
-export const DIRECT_QUERY_TYPES = ["postgres", "redshift", "mysql", "doris", "starrocks", "sqlite", "rqlite", "gaussdb", "kwdb", "opengauss"] as const;
+export const DIRECT_QUERY_TYPES = ["postgres", "redshift", "mysql", "doris", "starrocks", "manticoresearch", "sqlite", "rqlite", "gaussdb", "kwdb", "opengauss"] as const;
export type DirectQueryType = (typeof DIRECT_QUERY_TYPES)[number];
diff --git a/packages/node-core/tests/driver-manifest.test.ts b/packages/node-core/tests/driver-manifest.test.ts
index 6ab514223..c76a3d6cf 100644
--- a/packages/node-core/tests/driver-manifest.test.ts
+++ b/packages/node-core/tests/driver-manifest.test.ts
@@ -57,6 +57,11 @@ test("runtime direct query routing matches diagnostic direct query types", () =>
}
});
+test("Manticore Search is direct-query capable", () => {
+ assert.equal(isDirectQueryType("manticoresearch"), true);
+ assert.equal(DIRECT_QUERY_TYPES.includes("manticoresearch" as any), true);
+});
+
test("driver manifest declares support levels and product capabilities", () => {
const manifest = loadManifest();
@@ -72,4 +77,14 @@ test("driver manifest declares support levels and product capabilities", () => {
assert.equal(jdbc?.supportLevel, "browse");
assert.equal(jdbc?.capabilities.metadataBrowse, true);
assert.equal(jdbc?.capabilities.tableStructureEdit, false);
+
+ const manticore = manifest.drivers.find((driver) => driver.dbType === "manticoresearch");
+ assert.equal(manticore?.supportLevel, "browse");
+ assert.equal(manticore?.capabilities.queryExecution, true);
+ assert.equal(manticore?.capabilities.metadataBrowse, true);
+ assert.equal(manticore?.capabilities.objectBrowser, false);
+ assert.equal(manticore?.capabilities.tableDataEdit, false);
+ assert.equal(manticore?.capabilities.tableStructureEdit, false);
+ assert.equal(manticore?.capabilities.databaseCreate, false);
+ assert.equal(manticore?.capabilities.userAdmin, false);
});
diff --git a/src-tauri/src/commands/connection.rs b/src-tauri/src/commands/connection.rs
index f0e2993c8..e1b821a0c 100644
--- a/src-tauri/src/commands/connection.rs
+++ b/src-tauri/src/commands/connection.rs
@@ -273,7 +273,7 @@ pub async fn test_connection(state: State<'_, Arc>, config: Connection
Err(e) => Err(e),
}
}
- DatabaseType::Doris | DatabaseType::StarRocks => {
+ DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch => {
match db::mysql::connect_bare(&url, connect_timeout).await {
Ok(pool) => {
let _ = pool.disconnect().await;
@@ -488,7 +488,7 @@ pub async fn connect_db(state: State<'_, Arc>, config: ConnectionConfi
connect_mysql_metadata_pool(&config, &db_config, &host, port, connect_timeout, 3).await?;
PoolKind::Mysql(pool, mode)
}
- DatabaseType::Doris | DatabaseType::StarRocks => PoolKind::Mysql(
+ DatabaseType::Doris | DatabaseType::StarRocks | DatabaseType::ManticoreSearch => PoolKind::Mysql(
connect_bare_metadata_pool(&db_config, &host, port, connect_timeout, 3).await?,
MysqlMode::Bare,
),