use std::ffi::{c_void, CStr};
use crate::{
error::{Error, Result},
ffi::{
duckdb_add_scalar_function_to_set, duckdb_connection, duckdb_create_scalar_function,
duckdb_create_scalar_function_set, duckdb_destroy_scalar_function,
duckdb_destroy_scalar_function_set, duckdb_function_info,
duckdb_register_scalar_function_set, duckdb_scalar_function,
duckdb_scalar_function_add_parameter, duckdb_scalar_function_get_extra_info,
duckdb_scalar_function_set, duckdb_scalar_function_set_error,
duckdb_scalar_function_set_extra_info, duckdb_scalar_function_set_function,
duckdb_scalar_function_set_name, duckdb_scalar_function_set_return_type,
duckdb_scalar_function_set_special_handling, duckdb_scalar_function_set_varargs,
duckdb_scalar_function_set_volatile, duckdb_scalar_function_t,
},
};
use super::super::{
callback::{drop_boxed, CallbackErrorSink},
LogicalType,
};
pub(crate) struct ScalarFunction {
ptr: duckdb_scalar_function,
}
impl ScalarFunction {
pub(crate) fn new(name: &CStr) -> Self {
let ptr = unsafe { duckdb_create_scalar_function() };
unsafe { duckdb_scalar_function_set_name(ptr, name.as_ptr()) };
Self { ptr }
}
pub(crate) fn add_parameter(
&self,
ty: &LogicalType,
) {
unsafe { duckdb_scalar_function_add_parameter(self.ptr, ty.as_raw()) };
}
pub(crate) fn set_varargs(
&self,
ty: &LogicalType,
) {
unsafe { duckdb_scalar_function_set_varargs(self.ptr, ty.as_raw()) };
}
pub(crate) fn set_return_type(
&self,
ty: &LogicalType,
) {
unsafe { duckdb_scalar_function_set_return_type(self.ptr, ty.as_raw()) };
}
pub(crate) fn set_volatile(&self) {
unsafe { duckdb_scalar_function_set_volatile(self.ptr) };
}
pub(crate) fn set_special_handling(&self) {
unsafe { duckdb_scalar_function_set_special_handling(self.ptr) };
}
pub(crate) fn set_function(
&self,
f: duckdb_scalar_function_t,
) {
unsafe { duckdb_scalar_function_set_function(self.ptr, f) };
}
pub(crate) fn set_extra_info<T: Send + Sync + 'static>(
&self,
state: T,
) {
let ptr = Box::into_raw(Box::new(state)).cast::<c_void>();
unsafe { duckdb_scalar_function_set_extra_info(self.ptr, ptr, Some(drop_boxed::<T>)) };
}
pub(crate) fn as_raw(&self) -> duckdb_scalar_function {
self.ptr
}
}
impl Drop for ScalarFunction {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { duckdb_destroy_scalar_function(&mut self.ptr) };
}
}
}
pub(crate) struct ScalarFunctionSet {
ptr: duckdb_scalar_function_set,
}
impl ScalarFunctionSet {
pub(crate) fn new(name: &CStr) -> Self {
let ptr = unsafe { duckdb_create_scalar_function_set(name.as_ptr()) };
Self { ptr }
}
pub(crate) fn add_function(
&self,
function: &ScalarFunction,
) -> Result<()> {
let rc = unsafe { duckdb_add_scalar_function_to_set(self.ptr, function.as_raw()) };
if rc != crate::ffi::DuckDBSuccess {
return Err(Error::DuckDBFailure(
crate::ffi::Error::new(rc),
Some(
"failed to add overload to scalar function set (conflicting signature?)"
.to_owned(),
),
));
}
Ok(())
}
pub(crate) fn register(
&self,
con: duckdb_connection,
name: &str,
) -> Result<()> {
let rc = unsafe { duckdb_register_scalar_function_set(con, self.ptr) };
if rc != crate::ffi::DuckDBSuccess {
return Err(Error::DuckDBFailure(
crate::ffi::Error::new(rc),
Some(format!(
"failed to register scalar function `{name}` (name conflict, or invalid signature)"
)),
));
}
Ok(())
}
}
impl Drop for ScalarFunctionSet {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { duckdb_destroy_scalar_function_set(&mut self.ptr) };
}
}
}
pub(crate) struct ScalarFunctionInfo {
ptr: duckdb_function_info,
}
impl ScalarFunctionInfo {
pub(crate) fn from(ptr: duckdb_function_info) -> Self {
Self { ptr }
}
pub(crate) unsafe fn state<T>(&self) -> &T {
let raw = unsafe { duckdb_scalar_function_get_extra_info(self.ptr) };
unsafe { &*raw.cast::<T>() }
}
}
impl CallbackErrorSink for ScalarFunctionInfo {
fn set_c_error(
&self,
error: &CStr,
) {
unsafe { duckdb_scalar_function_set_error(self.ptr, error.as_ptr()) };
}
}