use crate::{pg_sys, void_mut_ptr, FromDatum, PgBox, PgMemoryContexts};
#[macro_export]
macro_rules! default {
($ty:ty, $val:tt) => {
$ty
};
($ty:ty, $val:path) => {
$ty
};
($ty:ty, $val:expr) => {
$ty
};
}
pub struct NULL;
#[macro_export]
macro_rules! name {
($name:tt, $ty:ty) => {
$ty
};
}
#[macro_export]
macro_rules! variadic {
($ty:ty) => {
$ty
};
}
#[cfg(any(feature = "pg11"))]
mod pg_11 {
use crate::{pg_sys, FromDatum};
#[inline]
pub unsafe fn pg_getarg<T: FromDatum>(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> Option<T> {
let datum = unsafe { fcinfo.as_ref() }.unwrap().arg[num];
let isnull = pg_arg_is_null(fcinfo, num);
unsafe {
if T::GET_TYPOID {
T::from_polymorphic_datum(datum, isnull, super::pg_getarg_type(fcinfo, num))
} else {
T::from_datum(datum, isnull)
}
}
}
#[inline]
pub unsafe fn pg_arg_is_null(fcinfo: pg_sys::FunctionCallInfo, num: usize) -> bool {
unsafe { fcinfo.as_ref() }.unwrap().argnull[num] as bool
}
#[inline]
pub unsafe fn pg_getarg_datum(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> Option<pg_sys::Datum> {
if pg_arg_is_null(fcinfo, num) {
None
} else {
Some(unsafe { fcinfo.as_ref() }.unwrap().arg[num])
}
}
#[inline]
pub unsafe fn pg_getarg_datum_raw(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> pg_sys::Datum {
unsafe { fcinfo.as_ref() }.unwrap().arg[num]
}
#[inline]
pub unsafe fn pg_return_null(fcinfo: pg_sys::FunctionCallInfo) -> pg_sys::Datum {
unsafe { fcinfo.as_mut() }.unwrap().isnull = true;
pg_sys::Datum::from(0)
}
}
#[cfg(any(feature = "pg12", feature = "pg13", feature = "pg14", feature = "pg15"))]
mod pg_12_13_14_15 {
use crate::{pg_sys, FromDatum};
#[inline]
pub unsafe fn pg_getarg<T: FromDatum>(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> Option<T> {
let datum = get_nullable_datum(fcinfo, num);
unsafe {
if T::GET_TYPOID {
T::from_polymorphic_datum(
datum.value,
datum.isnull,
super::pg_getarg_type(fcinfo, num),
)
} else {
T::from_datum(datum.value, datum.isnull)
}
}
}
#[inline]
pub unsafe fn pg_arg_is_null(fcinfo: pg_sys::FunctionCallInfo, num: usize) -> bool {
get_nullable_datum(fcinfo, num).isnull
}
#[inline]
pub unsafe fn pg_getarg_datum(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> Option<pg_sys::Datum> {
if pg_arg_is_null(fcinfo, num) {
None
} else {
Some(get_nullable_datum(fcinfo, num).value)
}
}
#[inline]
pub unsafe fn pg_getarg_datum_raw(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> pg_sys::Datum {
get_nullable_datum(fcinfo, num).value
}
#[doc(hidden)]
#[inline]
unsafe fn get_nullable_datum(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> pg_sys::NullableDatum {
let fcinfo = unsafe { fcinfo.as_mut() }.unwrap();
unsafe {
let nargs = fcinfo.nargs;
let len = std::mem::size_of::<pg_sys::NullableDatum>() * nargs as usize;
fcinfo.args.as_slice(len)[num].clone()
}
}
#[inline]
pub unsafe fn pg_return_null(fcinfo: pg_sys::FunctionCallInfo) -> pg_sys::Datum {
let fcinfo = unsafe { fcinfo.as_mut() }.unwrap();
fcinfo.isnull = true;
pg_sys::Datum::from(0)
}
}
#[cfg(any(feature = "pg11"))]
pub use pg_11::*;
#[cfg(any(feature = "pg12", feature = "pg13", feature = "pg14", feature = "pg15"))]
pub use pg_12_13_14_15::*;
#[inline]
pub unsafe fn pg_getarg_pointer<T>(fcinfo: pg_sys::FunctionCallInfo, num: usize) -> Option<*mut T> {
unsafe {
match pg_getarg_datum(fcinfo, num) {
Some(datum) => Some(datum.cast_mut_ptr::<T>()),
None => None,
}
}
}
#[inline]
pub unsafe fn pg_getarg_type(fcinfo: pg_sys::FunctionCallInfo, num: usize) -> pg_sys::Oid {
pg_sys::get_fn_expr_argtype(fcinfo.as_ref().unwrap().flinfo, num as std::os::raw::c_int)
}
#[inline]
pub unsafe fn pg_getarg_cstr<'a>(
fcinfo: pg_sys::FunctionCallInfo,
num: usize,
) -> Option<&'a std::ffi::CStr> {
match pg_getarg_pointer(fcinfo, num) {
Some(ptr) => Some(unsafe { std::ffi::CStr::from_ptr(ptr) }),
None => None,
}
}
#[inline]
pub unsafe fn pg_return_void() -> pg_sys::Datum {
pg_sys::Datum::from(0)
}
pub unsafe fn pg_func_extra<ReturnType, DefaultValue: FnOnce() -> ReturnType>(
fcinfo: pg_sys::FunctionCallInfo,
default: DefaultValue,
) -> PgBox<ReturnType> {
let fcinfo = PgBox::from_pg(fcinfo);
let mut flinfo = PgBox::from_pg(fcinfo.flinfo);
if flinfo.fn_extra.is_null() {
flinfo.fn_extra = PgMemoryContexts::For(flinfo.fn_mcxt).leak_and_drop_on_delete(default())
as void_mut_ptr;
}
PgBox::from_pg(flinfo.fn_extra as *mut ReturnType)
}
pub unsafe fn direct_function_call<R: FromDatum>(
func: unsafe fn(pg_sys::FunctionCallInfo) -> pg_sys::Datum,
args: Vec<Option<pg_sys::Datum>>,
) -> Option<R> {
direct_function_call_as_datum(func, args).map_or(None, |d| R::from_datum(d, false))
}
pub unsafe fn direct_pg_extern_function_call<R: FromDatum>(
func: unsafe extern "C" fn(pg_sys::FunctionCallInfo) -> pg_sys::Datum,
args: Vec<Option<pg_sys::Datum>>,
) -> Option<R> {
direct_pg_extern_function_call_as_datum(func, args).map_or(None, |d| R::from_datum(d, false))
}
pub unsafe fn direct_function_call_as_datum(
func: unsafe fn(pg_sys::FunctionCallInfo) -> pg_sys::Datum,
args: Vec<Option<pg_sys::Datum>>,
) -> Option<pg_sys::Datum> {
direct_function_call_as_datum_internal(|fcinfo| func(fcinfo), args)
}
#[cfg(feature = "pg11")]
unsafe fn direct_function_call_as_datum_internal(
func: impl FnOnce(pg_sys::FunctionCallInfo) -> pg_sys::Datum,
args: Vec<Option<pg_sys::Datum>>,
) -> Option<pg_sys::Datum> {
let fcinfo_ptr = pg_sys::palloc(std::mem::size_of::<pg_sys::FunctionCallInfoData>())
.cast::<pg_sys::FunctionCallInfoData>();
let fcinfo = fcinfo_ptr.as_mut().unwrap_unchecked();
fcinfo.flinfo = std::ptr::null_mut();
fcinfo.context = std::ptr::null_mut();
fcinfo.resultinfo = std::ptr::null_mut();
fcinfo.fncollation = pg_sys::InvalidOid;
fcinfo.isnull = false;
fcinfo.nargs = args.len() as _;
for (i, arg) in args.into_iter().enumerate() {
fcinfo.argnull[i] = arg.is_none();
fcinfo.arg[i] = arg.unwrap_or(pg_sys::Datum::from(0));
}
let result = func(fcinfo_ptr);
let result = if fcinfo.isnull { None } else { Some(result) };
pg_sys::pfree(fcinfo_ptr.cast());
return result;
}
#[cfg(not(feature = "pg11"))]
unsafe fn direct_function_call_as_datum_internal(
func: impl FnOnce(pg_sys::FunctionCallInfo) -> pg_sys::Datum,
args: Vec<Option<pg_sys::Datum>>,
) -> Option<pg_sys::Datum> {
let nargs = args.len();
let fcinfo_ptr = pg_sys::palloc(
std::mem::size_of::<pg_sys::FunctionCallInfoBaseData>()
+ std::mem::size_of::<pg_sys::NullableDatum>() * nargs,
)
.cast::<pg_sys::FunctionCallInfoBaseData>();
let fcinfo = fcinfo_ptr.as_mut().unwrap_unchecked();
fcinfo.flinfo = std::ptr::null_mut();
fcinfo.context = std::ptr::null_mut();
fcinfo.resultinfo = std::ptr::null_mut();
fcinfo.fncollation = pg_sys::InvalidOid;
fcinfo.isnull = false;
fcinfo.nargs = nargs as _;
let arg_slice = fcinfo.args.as_mut_slice(nargs);
for (i, arg) in args.into_iter().enumerate() {
arg_slice[i].isnull = arg.is_none();
arg_slice[i].value = arg.unwrap_or(pg_sys::Datum::from(0));
}
let result = func(fcinfo_ptr);
let result = if fcinfo.isnull { None } else { Some(result) };
pg_sys::pfree(fcinfo_ptr.cast());
return result;
}
pub unsafe fn direct_pg_extern_function_call_as_datum(
func: unsafe extern "C" fn(pg_sys::FunctionCallInfo) -> pg_sys::Datum,
args: Vec<Option<pg_sys::Datum>>,
) -> Option<pg_sys::Datum> {
direct_function_call_as_datum_internal(|fcinfo| func(fcinfo), args)
}
#[inline]
pub unsafe fn srf_is_first_call(fcinfo: pg_sys::FunctionCallInfo) -> bool {
(*(*fcinfo).flinfo).fn_extra.is_null()
}
#[inline]
pub unsafe fn srf_first_call_init(
fcinfo: pg_sys::FunctionCallInfo,
) -> *mut pg_sys::FuncCallContext {
pg_sys::init_MultiFuncCall(fcinfo)
}
#[inline]
pub unsafe fn srf_per_call_setup(fcinfo: pg_sys::FunctionCallInfo) -> *mut pg_sys::FuncCallContext {
pg_sys::per_MultiFuncCall(fcinfo)
}
#[inline]
pub unsafe fn srf_return_next(
fcinfo: pg_sys::FunctionCallInfo,
funcctx: *mut pg_sys::FuncCallContext,
) {
(*funcctx).call_cntr += 1;
(*((*fcinfo).resultinfo as *mut pg_sys::ReturnSetInfo)).isDone =
pg_sys::ExprDoneCond_ExprMultipleResult;
}
#[inline]
pub unsafe fn srf_return_done(
fcinfo: pg_sys::FunctionCallInfo,
funcctx: *mut pg_sys::FuncCallContext,
) {
pg_sys::end_MultiFuncCall(fcinfo, funcctx);
(*((*fcinfo).resultinfo as *mut pg_sys::ReturnSetInfo)).isDone =
pg_sys::ExprDoneCond_ExprEndResult;
}