diff --git a/Cargo.toml b/Cargo.toml index a85e722b..44f484ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "cli", "bindings/python", "bindings/nodejs", + "bindings/cpp", "ttc", ] resolver = "2" diff --git a/bindings/cpp/Cargo.toml b/bindings/cpp/Cargo.toml new file mode 100644 index 00000000..c67e31c3 --- /dev/null +++ b/bindings/cpp/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "databend-cpp" +publish = false + +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +authors = { workspace = true } + +[dependencies] +cxx = "1.0" +chrono = { workspace = true } +databend-driver = { workspace = true, features = ["rustls", "flight-sql"] } +tokio-stream = { workspace = true } + +[build-dependencies] +cxx-build = "1.0" diff --git a/bindings/cpp/build.rs b/bindings/cpp/build.rs new file mode 100644 index 00000000..1a53d2b2 --- /dev/null +++ b/bindings/cpp/build.rs @@ -0,0 +1,9 @@ +fn main() { + cxx_build::bridge("src/lib.rs") + .file("src/main.cpp") + .flag_if_supported("-std=c++17") + .compile("bendsql_cpp"); + + println!("cargo:rerun-if-changed=src/lib.rs"); + println!("cargo:rerun-if-changed=src/main.cpp"); +} diff --git a/bindings/cpp/include/lib.rs.h b/bindings/cpp/include/lib.rs.h new file mode 100644 index 00000000..1864384d --- /dev/null +++ b/bindings/cpp/include/lib.rs.h @@ -0,0 +1,13 @@ +#pragma once +#include + +namespace bendsql { + struct DatabendClientWrapper; + struct DatabendConnectionWrapper; + + std::unique_ptr new_client(const std::string& dsn); + std::unique_ptr get_connection(const DatabendClientWrapper& client); + bool execute_query(const DatabendConnectionWrapper& connection, const std::string& query); + std::string get_version(const DatabendClientWrapper& client); + std::string query_row(const DatabendConnectionWrapper& connection, const std::string& query); +} diff --git a/bindings/cpp/src/lib.rs b/bindings/cpp/src/lib.rs new file mode 100644 index 00000000..4b8fe41b --- /dev/null +++ b/bindings/cpp/src/lib.rs @@ -0,0 +1,70 @@ +use databend_driver::{Client as DatabendClient, Connection as DatabendConnection}; +use cxx::CxxString; + +#[cxx::bridge] +mod ffi { + extern "Rust" { + type DatabendClientWrapper; + type DatabendConnectionWrapper; + + fn new_client(dsn: &CxxString) -> Box; + fn get_connection(client: &DatabendClientWrapper) -> Box; + fn execute_query(connection: &DatabendConnectionWrapper, query: &CxxString) -> bool; + fn get_version(client: &DatabendClientWrapper) -> String; + fn query_row(connection: &DatabendConnectionWrapper, query: &CxxString) -> String; + } +} + +pub struct DatabendClientWrapper { + client: DatabendClient, +} + +pub struct DatabendConnectionWrapper { + connection: DatabendConnection, +} + +impl DatabendClientWrapper { + fn new(dsn: &CxxString) -> Box { + Box::new(Self { + client: DatabendClient::new(dsn.to_str().unwrap()), + }) + } + + fn get_connection(&self) -> Box { + let connection = tokio::runtime::Runtime::new() + .unwrap() + .block_on(self.client.get_conn()) + .unwrap(); + Box::new(DatabendConnectionWrapper { connection }) + } + + fn get_version(&self) -> String { + tokio::runtime::Runtime::new() + .unwrap() + .block_on(self.client.version()) + .unwrap_or_else(|_| "unknown".to_string()) + } +} + +impl DatabendConnectionWrapper { + fn execute_query(&self, query: &CxxString) -> bool { + let query_str = query.to_str().unwrap(); + tokio::runtime::Runtime::new() + .unwrap() + .block_on(self.connection.exec(query_str, None)) + .is_ok() + } + + fn query_row(&self, query: &CxxString) -> String { + let query_str = query.to_str().unwrap(); + let result = tokio::runtime::Runtime::new() + .unwrap() + .block_on(self.connection.query_row(query_str, None)); + + match result { + Ok(Some(row)) => format!("{:?}", row.values()), + Ok(None) => "No rows returned".to_string(), + Err(err) => format!("Error: {}", err), + } + } +}