Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
683 changes: 635 additions & 48 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ http-body-util = "0.1"
hex = "0.4.3"
keyring = { version = "3.6.3", default-features = false }
mysql_async = { version = "=0.37.0", default-features = false, features = ["default-rustls-ring"] }
oracle-rs = "=0.1.7"
prost = "0.14"
quick-xml = "0.37.5"
rand = "0.9.2"
reqwest = { version = "0.12.24", default-features = false, features = ["json", "rustls-tls", "stream"] }
rmcp = { version = "=2.2.0", default-features = false, features = ["server", "macros", "transport-io", "elicitation", "schemars"] }
rusqlite = { version = "0.37", features = ["bundled"] }
russh = { version = "0.62.5", default-features = false, features = ["ring", "rsa"] }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
rustix = { version = "1", features = ["fs", "process"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand All @@ -64,7 +66,10 @@ tauri-plugin-opener = "=2.2.7"
thiserror = "2"
tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
tokio-stream = { version = "0.1", features = ["sync"] }
tokio-util = { version = "0.7.16", features = ["io", "rt"] }
tokio-postgres = { version = "=0.7.18", features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] }
tokio-postgres-rustls = { version = "=0.14.0", features = ["native-certs", "ring"] }
tokio-util = { version = "0.7.16", features = ["compat", "io", "rt"] }
tiberius = { version = "=0.12.3", default-features = false, features = ["chrono", "rustls", "tds73"] }
tower = { version = "0.5", features = ["util"] }
tower-http = { version = "0.7", features = ["fs", "trace"] }
tracing = "0.1"
Expand Down
50 changes: 40 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

Source-available implementation of the Chat2DB Community hybrid runtime.

Chat2DB Rust owns the product runtime in Rust, uses a native Rust path for the
current MySQL browser and Console data plane, and retains the broader public Chat2DB
Community database compatibility layer behind a supervised Java process. The
repository is under active development and is not yet a stable end-user
release.
Chat2DB Rust owns the product runtime in Rust, uses native Rust paths for the
MySQL, PostgreSQL, SQL Server, and Oracle browser and Console data planes, and
uses a Rust-owned DM adapter over the generic JDBC bridge. The broader public
Chat2DB Community database compatibility layer remains behind a supervised Java
process. The repository is under active development and is not yet a stable
end-user release.

## Clone

Expand Down Expand Up @@ -119,7 +120,19 @@ surface reached by the pinned Community frontend:
- complete native MySQL datasource lifecycle, SSH tunneling, portability,
metadata, editable DML and DDL, views and routines, transfer tasks, account
administration, schema diff, pins, ER layout, workspace persistence, and
SQLite-backed Dashboard/Chart CRUD with native read-only chart refresh; and
SQLite-backed Dashboard/Chart CRUD with native read-only chart refresh;
- native PostgreSQL through `tokio-postgres 0.7.18`, with connection and SSH,
retained queries and typed parameters, cancellation and limits, Console,
relational and programmability metadata, table DDL and preview, ER metadata,
and native schema/namespace/DML builders;
- native SQL Server through `tiberius 0.12.3`, with the same relational
workbench slice, TDS-aware result handling, direct-batch Console semantics,
conservative write cancellation, and native schema/namespace/DML builders;
- native Oracle through the pure-Rust `oracle-rs 0.1.7` protocol client, with
connection and SSH, retained queries, Console, metadata, DDL, preview, ER,
and native schema/namespace/DML builders without OCI, ODPI-C, JDBC, or Java;
unsupported lossy Oracle result types fail closed instead of fabricating
values; and
- the pinned Community AI workspace routes plus confirmed Agent, CLI, and MCP
writes, with explicit approval, read-only enforcement, single-statement
validation, and conservative unknown-outcome handling.
Expand Down Expand Up @@ -161,16 +174,33 @@ output, `CHART` operation history, fixture cleanup, and Java dormant.
The complete `rtk make verify` gate then passed with the Dashboard/Chart
increment included.

On 2026-08-07 the added native PostgreSQL, SQL Server, and Oracle paths passed
real product verticals against PostgreSQL 17, Azure SQL Edge's SQL Server TDS
endpoint, and Oracle Free 23 respectively. The verticals cover connection,
metadata, retained query, Console, preview, DDL/dialect behavior, read-only
enforcement, cancellation, bounded values, cleanup, and continuous proof that
Java remained dormant. Core passed `357` all-target tests with `9` ignored plus
strict Clippy under both the default toolchain and the minimum Rust `1.88.0`.
For Oracle, `oracle-rs 0.1.7` has a fixed 100-row initial prefetch whose legacy
decoder cannot safely expose `BINARY_FLOAT`, `BINARY_DOUBLE`, `ROWID`, or
`UROWID`; those result columns return `oracle_result_type_not_supported` when
the driver exposes their type, and the project does not fork or vendor the
upstream crate.

Stage 6 and the Stage 7A-7M foundations are complete. Web and desktop own the
product runtime and publish its owner-only local endpoint; CLI and MCP attach to
that host and never contact Java directly. The pinned Community frontend's
complete MySQL workbench surface is mapped through the shared Axum/Tauri legacy
dispatcher. Native MySQL connections, metadata, Console, mutations, transfer,
class generation, accounts, schema diff, chart refresh, and workspace operations
remain in Rust and do not acquire a Java lease. Dashboard and chart documents
remain in SQLite. Community parser, formatter, completion, SQL-builder, and
exact plugin compatibility operations remain Java-backed and start the
supervised process only on demand.
remain in Rust and do not acquire a Java lease. PostgreSQL, SQL Server, and
Oracle connection, relational workbench, and dialect-builder operations also
remain in Rust when their explicit native driver ids are persisted. Existing
managed JDBC datasources continue through Java; registering a native driver
never silently changes their execution engine. Dashboard and chart documents
remain in SQLite. Community parser, formatter, completion, and exact plugin
compatibility operations remain Java-backed and start the supervised process
only on demand.

The Console compatibility path uses SQLite migrations 3 and 4 for saved
Consoles and durable execution history. Historical `/api/operation/saved/*`,
Expand Down
6 changes: 3 additions & 3 deletions apps/chat2db-desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3154,7 +3154,7 @@ mod tests {
}

#[tokio::test]
async fn table_preview_command_maps_unavailable_engine_errors() {
async fn table_preview_command_maps_unavailable_storage_errors() {
let error = start_community_table_preview_for(
&Application::new(),
StartCommunityTablePreviewRequest {
Expand All @@ -3167,9 +3167,9 @@ mod tests {
},
)
.await
.expect_err("table preview without an engine must fail");
.expect_err("table preview without storage must fail");

assert_eq!(error.code, "database_engine_unavailable");
assert_eq!(error.code, "storage_unavailable");
}

#[tokio::test]
Expand Down
22 changes: 16 additions & 6 deletions apps/chat2db-web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,21 @@ mod tests {

assert_eq!(response.status(), StatusCode::OK);
let inventory: JdbcDriverList = response_json(response).await;
assert_eq!(inventory.items.len(), 1);
let mysql = &inventory.items[0];
assert_eq!(mysql.driver_id, "mysql");
assert_eq!(mysql.driver_class, "rust:mysql_async");
assert_eq!(mysql.artifact_count, 0);
assert_eq!(inventory.items.len(), 4);
for (driver_id, driver_class) in [
("mysql", "rust:mysql_async"),
("postgresql", "rust:tokio-postgres"),
("sqlserver", "rust:tiberius"),
("oracle", "rust:oracle-rs"),
] {
let driver = inventory
.items
.iter()
.find(|driver| driver.driver_id == driver_id)
.expect("every built-in native connection driver must be advertised");
assert_eq!(driver.driver_class, driver_class);
assert_eq!(driver.artifact_count, 0);
}
}

#[tokio::test]
Expand Down Expand Up @@ -959,7 +969,7 @@ mod tests {
"rowLimit": 200
}),
),
"database_engine_unavailable",
"storage_unavailable",
),
(
json_request(
Expand Down
9 changes: 6 additions & 3 deletions crates/chat2db-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ chat2db-storage = { path = "../chat2db-storage" }
chrono.workspace = true
csv.workspace = true
directories.workspace = true
futures-util.workspace = true
hex.workspace = true
mysql_async.workspace = true
oracle-rs.workspace = true
prost.workspace = true
quick-xml.workspace = true
russh.workspace = true
rustls.workspace = true
serde.workspace = true
serde_json.workspace = true
sha1.workspace = true
Expand All @@ -36,16 +39,16 @@ rustix.workspace = true
tempfile = "3"
thiserror.workspace = true
tokio.workspace = true
tokio-postgres.workspace = true
tokio-postgres-rustls.workspace = true
tokio-util.workspace = true
tiberius.workspace = true
tracing.workspace = true
url.workspace = true
uuid.workspace = true
xls.workspace = true
zip.workspace = true

[dev-dependencies]
futures-util.workspace = true

[[test]]
name = "java_h2_product"
path = "tests/java_h2_product.rs"
Expand Down
Loading
Loading