4 releases
| 0.1.3 | Jan 29, 2026 |
|---|---|
| 0.1.2 | Jan 29, 2026 |
| 0.1.1 | Jan 29, 2026 |
| 0.1.0 | Jan 29, 2026 |
#1946 in Database interfaces
60KB
907 lines
Dameng Rust SDK
A comprehensive Rust SDK for Dameng Database (DM8) with ODBC support.
Features
- ✅ Connection Management - Robust connection handling with connection pooling support
- ✅ CRUD Operations - Complete support for Create, Read, Update, Delete operations
- ✅ Transaction Support - Full ACID transaction support with commit and rollback
- ✅ Type-Safe Queries - Type-safe query building with compile-time safety
- ✅ Parameterized Queries - Safe parameterized queries to prevent SQL injection
- ✅ Error Handling - Comprehensive error types with proper error propagation
- ✅ Logging - Built-in logging support using the
logcrate - ✅ Character Encoding - Automatic GBK to UTF-8 conversion for Chinese character support
- ✅ JSON Serialization - Optional JSON serialization/deserialization support
- ✅ TLS Support - Secure database connections with TLS encryption
Installation
Add this to your Cargo.toml:
[dependencies]
dameng_rust_sdk = "0.1.0"
Or install via cargo:
cargo add dameng_rust_sdk
Quick Start
use dameng_rust_sdk::prelude::*;
use dameng_rust_sdk::ConnectionOptions;
fn main() -> Result<()> {
// Create connection options
let options = ConnectionOptions {
server: "localhost".to_string(),
port: 5236,
username: "SYSDBA".to_string(),
password: "your_password".to_string(),
schema: "DMHR".to_string(),
..Default::default()
};
// Connect to database
let mut conn = Connection::with_options(options)?;
// Execute a simple query
let mut result = conn.query("SELECT * FROM EMPLOYEES LIMIT 10")?;
let rows = result.fetch_all()?;
// Process results
for row in rows {
println!("{:?}", row);
}
// Use parameterized queries for safety
use dameng_rust_sdk::prelude::parameter::InputParameter;
let odbc_params: Vec<Box<dyn InputParameter>> = vec![
Box::new("Alice".into_parameter()),
];
let mut result = conn.query_with_param(
"SELECT * FROM EMPLOYEES WHERE NAME = ?",
odbc_params.as_slice()
)?;
let rows = result.fetch_all()?;
for row in rows {
println!("{:?}", row);
}
Ok(())
}
Usage
Basic Connection
use dameng_rust_sdk::{Connection, ConnectionOptions};
// Default connection
let mut conn = Connection::connect()?;
// Connection with custom options
let options = ConnectionOptions {
server: "localhost".to_string(),
port: 5236,
username: "SYSDBA".to_string(),
password: "password".to_string(),
schema: "DMHR".to_string(),
timeout: 30,
use_tls: false,
..Default::default()
};
let mut conn = Connection::with_options(options)?;
Query Operations
Simple SELECT Query
// Execute SELECT query
let mut result = conn.query("SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID = 1")?;
// Get column names
let columns = result.column_names()?;
println!("Columns: {:?}", columns);
// Fetch all rows
let rows = result.fetch_all()?;
// Access specific row
if let Some(row) = result.get_row(0) {
println!("First row: {:?}", row);
}
// Access specific value
if let Some(value) = result.get_value(0, 0) {
println!("First value: {:?}", value);
}
Parameterized SELECT Query
Use parameterized queries to prevent SQL injection and handle special characters safely:
use dameng_rust_sdk::prelude::parameter::InputParameter;
// Create parameters
let odbc_params: Vec<Box<dyn InputParameter>> = vec![
Box::new("红楼梦".into_parameter()), // String parameter
];
// Execute parameterized query with placeholders
let mut result = conn.query_with_param(
"SELECT * FROM PRODUCTION.PRODUCT WHERE NAME = ?",
odbc_params.as_slice()
)?;
let rows = result.fetch_all()?;
for row in rows {
// Process each row
for col in row {
match col {
DamengValue::Null =>print!("Null\t"),
DamengValue::Int(r) => print!("{r}\t"),
DamengValue::BigInt(r) => print!("{r}\t"),
DamengValue::Float(r) => print!("{r}\t"),
DamengValue::String(r) => print!("{r}\t"),
DamengValue::Bool(r) => print!("{r}\t"),
DamengValue::Decimal(a, b, c) => print!("{a}.{b}.{c}\t"),
DamengValue::Date(naive_date) => print!("{}\t",naive_date.to_string()),
DamengValue::DateTime(naive_date_time) => print!("{}\t",naive_date_time.to_string()),
DamengValue::Binary(items) => print!("{:?}\t",items),
}
}
println!();
}
Simple INSERT/UPDATE/DELETE
// INSERT
let sql = "INSERT INTO EMPLOYEES (NAME, DEPARTMENT_ID, SALARY) VALUES ('John Doe', 1, 50000)";
let result = conn.execute(sql)?;
println!("Insert successful: {}", result);
// UPDATE
let sql = "UPDATE EMPLOYEES SET SALARY = 55000 WHERE EMPLOYEE_ID = 1";
let result = conn.execute(sql)?;
println!("Update successful: {}", result);
// DELETE
let sql = "DELETE FROM EMPLOYEES WHERE EMPLOYEE_ID = 100";
let result = conn.execute(sql)?;
println!("Delete successful: {}", result);
Parameterized INSERT/UPDATE/DELETE
Use parameterized queries for dynamic values to prevent SQL injection:
use dameng_rust_sdk::prelude::parameter::InputParameter;
// Single parameter
let odbc_params: Vec<Box<dyn InputParameter>> = vec![
Box::new(500.into_parameter()), // Integer parameter
];
let result = conn.execute_with_param(
"UPDATE PRODUCTION.PRODUCT_VENDOR SET STANDARDPRICE = ? WHERE PRODUCTID = 7",
odbc_params.as_slice()
)?;
println!("Update successful: {}", result);
// Multiple parameters
let odbc_params: Vec<Box<dyn InputParameter>> = vec![
Box::new(500.into_parameter()), // First parameter
Box::new(5.into_parameter()), // Second parameter
];
let result = conn.execute_with_param(
"UPDATE PRODUCTION.PRODUCT_VENDOR SET STANDARDPRICE = ? WHERE PRODUCTID = 7 AND VENDORID = ?",
odbc_params.as_slice()
)?;
println!("Update successful: {}", result);
Transaction Support
// Begin a transaction
conn.begin_transaction()?;
try {
// Execute multiple operations
conn.execute("INSERT INTO EMPLOYEES (NAME) VALUES ('Alice')")?;
conn.execute("INSERT INTO EMPLOYEES (NAME) VALUES ('Bob')")?;
// Commit if all operations succeed
conn.commit()?;
} catch {
// Rollback if any operation fails
conn.rollback()?;
}
Working with Different Data Types
The SDK supports various Dameng data types:
match value {
DamengValue::Null => println!("NULL value"),
DamengValue::Int(i) => println!("Integer: {}", i),
DamengValue::BigInt(b) => println!("Big Integer: {}", b),
DamengValue::Float(f) => println!("Float: {}", f),
DamengValue::String(s) => println!("String: {}", s),
DamengValue::Bool(b) => println!("Boolean: {}", b),
DamengValue::Date(d) => println!("Date: {}", d),
DamengValue::DateTime(dt) => println!("DateTime: {}", dt),
DamengValue::Binary(bytes) => println!("Binary: {:?}", bytes),
_ => println!("Other value"),
}
Database Information
let db_info = conn.database_info()?;
println!("DBMS: {}", db_info.dbms_name);
println!("Database: {}", db_info.db_name);
println!("Driver: {}", db_info.driver_name);
println!("Driver Version: {}", db_info.driver_version);
Using DamengClient
For advanced usage, use the DamengClient which provides additional functionality:
use dameng_rust_sdk::prelude::*;
use dameng_rust_sdk::ConnectionOptions;
use log::info;
use env_logger::Env;
fn main() -> dameng_rust_sdk::Result<()> {
// Initialize logging
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
// Create connection options
let options = ConnectionOptions {
server: "localhost".to_string(),
port: 5236,
username: "SYSDBA".to_string(),
password: "your_password".to_string(),
schema: "PRODUCTION".to_string(),
..Default::default()
};
// Create client
let client = DamengClient::new(options)?;
// Test connection
client.test_connection()?;
info!("✓ Connection test successful");
// Get database information
let db_info = client.database_info()?;
info!("✓ Database Information:");
info!(" DBMS: {}", db_info.dbms_name);
info!(" Database: {}", db_info.db_name);
info!(" Driver: {} {}", db_info.driver_name, db_info.driver_version);
// Connect to database
let mut conn = client.connect()?;
info!("✓ Connected to database");
// Now you can use the connection for queries
use dameng_rust_sdk::prelude::parameter::InputParameter;
let odbc_params: Vec<Box<dyn InputParameter>> = vec![
Box::new("红楼梦".into_parameter()),
];
let mut result = conn.query_with_param(
"SELECT * FROM PRODUCTION.PRODUCT WHERE NAME = ?",
odbc_params.as_slice()
)?;
let rows = result.fetch_all()?;
info!("✓ Query executed successfully");
Ok(())
}
Using Query Builder
let builder = conn.query_builder();
// Query builder functionality (implementation depends on version)
Logging
Enable logging by setting the RUST_LOG environment variable:
RUST_LOG=info cargo run
use env_logger::Env;
fn main() -> Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
// Your code here
}
Configuration
Connection Options
| Option | Type | Default | Description |
|---|---|---|---|
server |
String |
"localhost" |
Database server address |
port |
u16 |
5236 |
Database port |
username |
String |
"SYSDBA" |
Database username |
password |
String |
"" |
Database password |
schema |
String |
"DMHR" |
Database schema |
timeout |
u32 |
30 |
Connection timeout in seconds |
use_tls |
bool |
false |
Enable TLS encryption |
additional_params |
Vec<(String, String)> |
[] |
Additional connection parameters |
Features
default- Includes TLS and JSON supportfull- Includes all features (TLS, JSON, serde, env_logger)tls- TLS encryption supportjson- JSON serialization support
# Use specific features
[dependencies]
dameng_rust_sdk = { version = "0.1.0", features = ["full"] }
Examples
Run Demo
The SDK includes a demo application:
cargo run --bin dameng_demo --features full
Example Projects
See the examples/ directory for more usage examples.
Error Handling
The SDK uses the Result<T> type for error handling:
use dameng_rust_sdk::Error;
match result {
Ok(data) => println!("Success: {:?}", data),
Err(Error::Connection(msg)) => eprintln!("Connection error: {}", msg),
Err(Error::Query(msg)) => eprintln!("Query error: {}", msg),
Err(Error::Transaction(msg)) => eprintln!("Transaction error: {}", msg),
Err(e) => eprintln!("Other error: {}", e),
}
Character Encoding
The SDK automatically handles GBK to UTF-8 conversion for Chinese character support. This is particularly useful when working with Dameng databases containing Chinese data.
Prerequisites
- Rust - Install Rust 1.70 or later from rustup.rs
- Dameng Database - Install and configure Dameng Database (DM8)
- ODBC Driver - Install DM8 ODBC DRIVER
Installing ODBC Driver
- Download DM8 ODBC Driver from the Dameng official website
- Follow the installation instructions for your operating system
- Configure the ODBC Data Source (DSN) if needed
Troubleshooting
Connection Issues
If you encounter connection errors:
- Verify the Dameng database is running
- Check the server address and port
- Ensure the username and password are correct
- Verify the schema exists
- Check ODBC driver installation
Character Encoding Issues
If you see garbled Chinese characters:
- The SDK automatically handles GBK to UTF-8 conversion
- Ensure your database character set is properly configured
Performance Tips
- Use connection pooling for production applications
- Use transactions for multiple related operations
- Optimize your SQL queries with proper indexing
- Use LIMIT clauses to reduce data transfer
API Documentation
Full API documentation is available on docs.rs
Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development
# Clone the repository
git clone https://github.com/your-username/dameng_rust_sdk.git
cd dameng_rust_sdk
# Run tests
cargo test
# Run examples
cargo run --example example_name
# Build documentation
cargo doc --open
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- 📧 Email: andrew@out.com
- 📖 Documentation: docs.rs
- 🐛 Issue Tracker: GitHub Issues
- 💬 Discussions: GitHub Discussions
Acknowledgments
- Built with odbc-api
- Character encoding support via encoding_rs
- Error handling with thiserror
Roadmap
- Connection pooling
- Async support
- Stored procedure support
- Batch operations
- Query builder enhancements
- ORM-like features
- Migration tools
Changelog
See CHANGELOG.md for a list of changes in each version.
Made with ❤️ in Rust
Dependencies
~6–25MB
~382K SLoC