use std::ffi::{CStr, CString};
use libduckdb_sys::{
duckdb_config, duckdb_config_count, duckdb_create_config, duckdb_destroy_config,
duckdb_get_config_flag, duckdb_set_config, DuckDBSuccess,
};
use crate::error::ExtensionError;
#[must_use]
pub struct DbConfig {
config: duckdb_config,
}
impl DbConfig {
pub fn new() -> Result<Self, ExtensionError> {
let mut config: duckdb_config = std::ptr::null_mut();
let state = unsafe { duckdb_create_config(&raw mut config) };
if state == DuckDBSuccess {
Ok(Self { config })
} else {
Err(ExtensionError::new("duckdb_create_config failed"))
}
}
pub fn set(self, name: &str, value: &str) -> Result<Self, ExtensionError> {
let c_name = CString::new(name).map_err(|_| {
ExtensionError::new(format!("config name '{name}' contains a null byte"))
})?;
let c_value = CString::new(value).map_err(|_| {
ExtensionError::new(format!("config value '{value}' contains a null byte"))
})?;
let state = unsafe { duckdb_set_config(self.config, c_name.as_ptr(), c_value.as_ptr()) };
if state == DuckDBSuccess {
Ok(self)
} else {
Err(ExtensionError::new(format!(
"duckdb_set_config failed for option '{name}' = '{value}'"
)))
}
}
#[must_use]
pub fn flag_count() -> usize {
unsafe { duckdb_config_count() }
}
pub fn get_flag(index: usize) -> Result<(String, String), ExtensionError> {
let mut name_ptr: *const std::os::raw::c_char = std::ptr::null();
let mut desc_ptr: *const std::os::raw::c_char = std::ptr::null();
let state = unsafe { duckdb_get_config_flag(index, &raw mut name_ptr, &raw mut desc_ptr) };
if state != DuckDBSuccess {
return Err(ExtensionError::new(format!(
"duckdb_get_config_flag({index}) failed"
)));
}
let name = unsafe { CStr::from_ptr(name_ptr) }
.to_string_lossy()
.into_owned();
let desc = unsafe { CStr::from_ptr(desc_ptr) }
.to_string_lossy()
.into_owned();
Ok((name, desc))
}
#[must_use]
#[inline]
pub const fn as_raw(&self) -> duckdb_config {
self.config
}
}
impl Drop for DbConfig {
fn drop(&mut self) {
if !self.config.is_null() {
unsafe {
duckdb_destroy_config(&raw mut self.config);
}
}
}
}