use duckdb::{
Connection, Result,
core::{DataChunkHandle, Inserter, LogicalTypeHandle, LogicalTypeId},
duckdb_entrypoint_c_api,
vtab::{BindInfo, InitInfo, TableFunctionInfo, VTab},
};
use std::{
error::Error,
ffi::CString,
sync::atomic::{AtomicBool, Ordering},
};
#[repr(C)]
struct HelloBindData {
name: String,
}
#[repr(C)]
struct HelloInitData {
done: AtomicBool,
}
struct HelloVTab;
impl VTab for HelloVTab {
type InitData = HelloInitData;
type BindData = HelloBindData;
fn bind(bind: &BindInfo) -> Result<Self::BindData, Box<dyn std::error::Error>> {
bind.add_result_column("column0", LogicalTypeHandle::from(LogicalTypeId::Varchar));
let name = bind.get_parameter(0).to_string();
Ok(HelloBindData { name })
}
fn init(_: &InitInfo) -> Result<Self::InitData, Box<dyn std::error::Error>> {
Ok(HelloInitData {
done: AtomicBool::new(false),
})
}
fn func(func: &TableFunctionInfo<Self>, output: &mut DataChunkHandle) -> Result<(), Box<dyn std::error::Error>> {
let init_data = func.get_init_data();
let bind_data = func.get_bind_data();
if init_data.done.swap(true, Ordering::Relaxed) {
output.set_len(0);
} else {
let vector = output.flat_vector(0);
let result = CString::new(format!("Hello {}", bind_data.name))?;
vector.insert(0, result);
output.set_len(1);
}
Ok(())
}
fn parameters() -> Option<Vec<LogicalTypeHandle>> {
Some(vec![LogicalTypeHandle::from(LogicalTypeId::Varchar)])
}
}
#[duckdb_entrypoint_c_api(ext_name = "rusty_quack", min_duckdb_version = "v0.0.1")]
pub fn extension_entrypoint(con: Connection) -> Result<(), Box<dyn Error>> {
con.register_table_function::<HelloVTab>("hello")
.expect("Failed to register hello table function");
Ok(())
}