Native Rust database driver for CUBRID — built by reverse-engineering the CAS wire protocol. Pure Rust, no FFI, sync + async.
cubrid-rs was not built from an official protocol specification — none exists. Instead, the entire CAS (Common Application Server) binary wire protocol was decoded by cross-referencing three existing open-source implementations (cubrid-go, cubrid-client, pycubrid), running targeted experiments against live CUBRID servers, and reading server-side C source code when the clients disagreed.
The full reverse engineering story — methodology, discoveries, pitfalls, and protocol details — is documented in PROTOCOL_RESEARCH.md.
Key discoveries include:
- The
FC=41(PrepareAndExecute) function code doesn't support server-side bind parameters — requiring client-side SQL interpolation - Stored procedure results embed actual type codes inside value data (column metadata reports NULL type)
- Two distinct write families (
write_*raw vsadd_*length-prefixed) that cause silent data corruption when confused - A gap in the DataType enum (no type code 20) that's intentional, not a bug
| cubrid-rs | CCI (C interface) | |
|---|---|---|
| FFI Required | No — pure Rust | Yes |
| Cross-compilation | Standard Cargo targets | Requires C toolchain |
| Sync + Async | Native crates for both | Manual wrappers |
| Connection Pooling | Native Rust pool crate | Manual management |
| Deployment | Rust binary + crates only | Shared library dependency |
| Test Coverage | 95.11% (366 tests) | Varies |
cubrid-rs speaks the CUBRID CAS protocol directly over TCP with native Rust crates designed for modern sync and async services.
# Sync client
cargo add cubrid-client
# Async client (tokio)
cargo add cubrid-tokio
# Connection pool
cargo add cubrid-poolRequirements: Rust 1.75+
use cubrid_client::Client;
fn main() -> Result<(), cubrid_client::Error> {
let mut client = Client::connect("cubrid://dba:@localhost:33000/demodb")?;
let rows = client.query("SELECT * FROM athlete WHERE nation_code = ?", &["KOR"])?;
for row in rows {
println!("{:?}", row);
}
Ok(())
}use cubrid_tokio::Client;
#[tokio::main]
async fn main() -> Result<(), cubrid_tokio::Error> {
let mut client = Client::connect("cubrid://dba:@localhost:33000/demodb").await?;
let rows = client.query("SELECT 1 + 1", &[]).await?;
for row in rows {
println!("{:?}", row);
}
Ok(())
}use cubrid_pool::Pool;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = Pool::builder()
.max_size(10)
.build("cubrid://dba:@localhost:33000/demodb")
.await?;
let mut client = pool.get().await?;
let rows = client.query("SELECT 1", &[]).await?;
println!("{:?}", rows);
Ok(())
}cubrid://[user[:password]]@host[:port]/database
| Parameter | Default | Description |
|---|---|---|
host |
localhost |
CUBRID broker host |
port |
33000 |
CUBRID broker port |
database |
(required) | Target database name |
user |
"" |
Database user |
password |
"" |
Database password |
| Crate | Status | Description |
|---|---|---|
cubrid-protocol |
✅ Stable | CAS wire protocol codec — zero I/O dependencies |
cubrid-client |
✅ Stable | Synchronous client with full query/transaction support |
cubrid-tokio |
✅ Stable | Async client built on tokio |
cubrid-pool |
✅ Stable | Async connection pool with configurable limits |
| CUBRID | Rust | Notes |
|---|---|---|
SMALLINT |
i16 |
|
INTEGER |
i32 |
|
BIGINT |
i64 |
|
FLOAT |
f32 |
|
DOUBLE, MONETARY |
f64 |
|
CHAR, VARCHAR, STRING |
String |
|
NCHAR, VARNCHAR |
String |
|
BIT, VARBIT |
Vec<u8> |
|
NUMERIC |
String |
Preserves arbitrary precision |
DATE |
String |
"YYYY-MM-DD" |
TIME |
String |
"HH:MM:SS" |
DATETIME |
String |
"YYYY-MM-DD HH:MM:SS.fff" |
TIMESTAMP |
String |
"YYYY-MM-DD HH:MM:SS" |
BLOB |
Vec<u8> |
|
CLOB |
String |
|
SET, MULTISET, SEQUENCE |
Vec<Value> |
Nested type-tagged arrays |
ENUM |
String |
|
OBJECT |
String |
OID representation |
flowchart TD
A[cubrid-rs/\n4 crates, 1 workspace]
A --> B[crates/]
B --> C[cubrid-protocol/\nPure protocol codec (no I/O)]
C --> C1[constants.rs\nCAS function codes, type codes, flags]
C --> C2[handshake.rs\nBroker handshake + OpenDatabase]
C --> C3[codec.rs\nPacketWriter / PacketReader]
C --> C4[request.rs\nRequest frame builders]
C --> C5[response.rs\nResponse parsers]
C --> C6[value.rs\nValue enum + type conversions]
B --> D[cubrid-client/\nSync TCP client]
B --> E[cubrid-tokio/\nAsync tokio client]
B --> F[cubrid-pool/\nAsync connection pool]
A --> G[docs/]
G --> G1[PROTOCOL_RESEARCH.md\nReverse engineering narrative]
G --> G2[PRD.md\nProduct requirements]
G --> G3[TDD.md\nTechnical design decisions]
G --> G4[ARCHITECTURE.md\nWorkspace + dependency graph]
G --> G5[ROADMAP.md\nRelease plan]
A --> H[examples/]
flowchart LR
cubrid_pool[cubrid-pool] --> cubrid_client[cubrid-client]
cubrid_client --> cubrid_protocol[cubrid-protocol]
cubrid_tokio[cubrid-tokio] --> cubrid_protocol
The CAS connection flow, decoded by reverse engineering:
- Broker handshake — Send
CUBRK+ client metadata (10 bytes), receive CAS port redirect (4 bytes) - Open database — Send 628-byte fixed credential payload, receive session + protocol version
- Framed RPC — All operations use
[DATA_LENGTH][CAS_INFO][FC + args]frames - Function codes — 11 core FCs implemented: PREPARE, EXECUTE, FETCH, END_TRAN, etc.
See PROTOCOL_RESEARCH.md for the complete story.
flowchart LR
A[Handshake] --> B[OpenDatabase]
B --> C[Execute]
C --> D[CloseDatabase]
| Document | Description |
|---|---|
| Protocol Research | ★ Full reverse engineering narrative — methodology, discoveries, pitfalls |
| PRD | Product requirements and phased plan |
| TDD | Technical design decisions |
| Architecture | Workspace and dependency graph |
| Roadmap | Planned releases |
Use the DSN format: cubrid://[user[:password]]@host[:port]/database.
Rust 1.75 or later.
No. All crates enforce #![deny(unsafe_code)].
Yes. cubrid-tokio provides a fully async client built on tokio. cubrid-pool provides async connection pooling on top of it.
No. The project is pure Rust. The CAS protocol was reverse-engineered and implemented from scratch.
By cross-referencing three existing open-source client implementations (Go, TypeScript, Python) and testing against live CUBRID servers. See PROTOCOL_RESEARCH.md.
| Package | Description |
|---|---|
| cubrid-rs | Native Rust CUBRID workspace |
| sea-orm-cubrid | SeaORM backend for CUBRID |
See docs/ROADMAP.md for detailed release plans and protocol implementation progress.
For the ecosystem-wide view, see the CUBRID Labs Ecosystem Roadmap and Project Board.
MIT