use adbc_core::options::{AdbcVersion, OptionDatabase, OptionValue};
use adbc_core::{Connection, Database, Driver, Statement};
use adbc_driver_manager::ManagedDriver;
use arrow::array::{Array, RecordBatchReader, StringArray, UInt32Array};
use std::error::Error;
use std::path::Path;
const HOST: &str = "localhost";
const PORT: u16 = 8563;
const USER: &str = "sys";
const PASSWORD: &str = "exasol";
fn get_library_path() -> &'static str {
if cfg!(target_os = "macos") {
"target/release/libexarrow_rs.dylib"
} else if cfg!(target_os = "windows") {
"target/release/exarrow_rs.dll"
} else {
"target/release/libexarrow_rs.so"
}
}
fn get_connection_uri() -> String {
format!(
"exasol://{}:{}@{}:{}?tls=true&validateservercertificate=0",
USER, PASSWORD, HOST, PORT
)
}
fn load_driver() -> Result<ManagedDriver, Box<dyn Error>> {
let lib_path = get_library_path();
if !Path::new(lib_path).exists() {
return Err(format!(
"Library not found at {}. Build with: cargo build --release --features ffi",
lib_path
)
.into());
}
ManagedDriver::load_dynamic_from_filename(
lib_path,
Some(b"ExarrowDriverInit"),
AdbcVersion::V110,
)
.map_err(Into::into)
}
fn execute_select(conn: &mut impl Connection, sql: &str) -> Result<(usize, usize), Box<dyn Error>> {
let mut stmt = conn.new_statement()?;
stmt.set_sql_query(sql)?;
let mut reader = stmt.execute()?;
let schema = reader.schema();
let mut total_rows = 0;
for batch_result in reader.by_ref() {
let batch = batch_result?;
total_rows += batch.num_rows();
}
Ok((total_rows, schema.fields().len()))
}
fn execute_update(conn: &mut impl Connection, sql: &str) -> Result<Option<i64>, Box<dyn Error>> {
let mut stmt = conn.new_statement()?;
stmt.set_sql_query(sql)?;
stmt.execute_update().map_err(Into::into)
}
fn main() -> Result<(), Box<dyn Error>> {
let mut driver = load_driver()?;
let uri = get_connection_uri();
let opts = vec![(OptionDatabase::Uri, OptionValue::String(uri))];
let db = driver.new_database_with_opts(opts)?;
let mut conn = db.new_connection()?;
let (_rows, _cols) =
execute_select(&mut conn, "SELECT 42 AS answer, 'Hello ADBC!' AS message")?;
let (_rows, _cols) = execute_select(
&mut conn,
"SELECT LEVEL AS id, 'Row ' || LEVEL AS label FROM DUAL CONNECT BY LEVEL <= 5",
)?;
{
let mut reader = conn.get_info(None)?;
for batch_result in reader.by_ref() {
let batch = batch_result?;
if batch.num_rows() > 0 {
let info_name = batch.column(0);
let info_value = batch.column(1);
if let (Some(names), Some(values)) = (
info_name.as_any().downcast_ref::<UInt32Array>(),
info_value.as_any().downcast_ref::<StringArray>(),
) {
for i in 0..names.len() {
if !values.is_null(i) {
println!(" {}: {}", names.value(i), values.value(i));
}
}
}
}
}
}
let schema_name = format!(
"DM_EXAMPLE_{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_millis()
);
execute_update(&mut conn, &format!("CREATE SCHEMA {}", schema_name))?;
execute_update(
&mut conn,
&format!(
"CREATE TABLE {}.users (id INTEGER, name VARCHAR(100), active BOOLEAN)",
schema_name
),
)?;
execute_update(
&mut conn,
&format!(
"INSERT INTO {}.users VALUES (1, 'Alice', TRUE), (2, 'Bob', TRUE), (3, 'Charlie', FALSE)",
schema_name
),
)?;
let (_rows, _cols) = execute_select(
&mut conn,
&format!(
"SELECT * FROM {}.users WHERE active = TRUE ORDER BY id",
schema_name
),
)?;
execute_update(&mut conn, &format!("DROP SCHEMA {} CASCADE", schema_name))?;
Ok(())
}