diff --git a/pgrx-examples/custom_types/src/hexint.rs b/pgrx-examples/custom_types/src/hexint.rs index 8aa39831c..2a9d04b79 100644 --- a/pgrx-examples/custom_types/src/hexint.rs +++ b/pgrx-examples/custom_types/src/hexint.rs @@ -107,6 +107,10 @@ where value } } + + unsafe fn unbox_argument(args: &mut ::pgrx::callconv::Arguments<'_, 'fcx>) -> Option { + args.next().and_then(|arg| arg.unbox_arg_using_from_datum()) + } } unsafe impl BoxRet for HexInt { diff --git a/pgrx-macros/src/lib.rs b/pgrx-macros/src/lib.rs index ad14c884b..a80535354 100644 --- a/pgrx-macros/src/lib.rs +++ b/pgrx-macros/src/lib.rs @@ -712,6 +712,11 @@ fn impl_postgres_enum(ast: DeriveInput) -> syn::Result .unwrap_or_else(|| panic!("argument {index} must not be null")) } } + + unsafe fn unbox_argument(args: &mut ::pgrx::callconv::Arguments<'_, #fcx_lt>) -> Option { + args.next().and_then(|arg| arg.unbox_arg_using_from_datum()) + } + } unsafe impl #generics ::pgrx::datum::UnboxDatum for #enum_ident #generics { @@ -923,6 +928,9 @@ fn impl_postgres_type(ast: DeriveInput) -> syn::Result .unwrap_or_else(|| panic!("argument {index} must not be null")) } } + unsafe fn unbox_argument(args: &mut ::pgrx::callconv::Arguments<'_, #fcx_lt>) -> Option { + args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() }) + } } } ) diff --git a/pgrx-sql-entity-graph/src/pg_extern/mod.rs b/pgrx-sql-entity-graph/src/pg_extern/mod.rs index 7447fba01..6422d9b3b 100644 --- a/pgrx-sql-entity-graph/src/pg_extern/mod.rs +++ b/pgrx-sql-entity-graph/src/pg_extern/mod.rs @@ -400,12 +400,13 @@ impl PgExtern { // false true }; + let args_ident = proc_macro2::Ident::new("_args", Span::call_site()); let arg_fetches = args.iter().enumerate().map(|(idx, arg)| { if new_unboxing { let pat = &arg_pats[idx]; let resolved_ty = &arg.used_ty.resolved_ty; quote_spanned!{ pat.span() => - let #pat = <#resolved_ty as ::pgrx::callconv::ArgAbi>::unbox_from_fcinfo_index(#fcinfo_ident, &mut #idx); + let #pat = <#resolved_ty as ::pgrx::callconv::ArgAbi>::unbox_argument(#args_ident).unwrap(); } } else { let pat = &arg_pats[idx]; @@ -448,13 +449,18 @@ impl PgExtern { #[allow(unused_unsafe)] unsafe { let #fcinfo_ident = fcinfo; - let result = match <#ret_ty as ::pgrx::callconv::RetAbi>::check_and_prepare(#fcinfo_ident) { + let call_flow = <#ret_ty as ::pgrx::callconv::RetAbi>::check_and_prepare(#fcinfo_ident); + let result = match call_flow { ::pgrx::callconv::CallCx::WrappedFn(mcx) => { let mut mcx = ::pgrx::PgMemoryContexts::For(mcx); - ::pgrx::callconv::RetAbi::to_ret(mcx.switch_to(|_| { + let fcinfo = &*#fcinfo_ident; + let mut args = fcinfo.arguments(); + let #args_ident= &mut args; + let call_result = mcx.switch_to(|_| { #(#arg_fetches)* #func_name( #(#arg_pats),* ) - })) + }); + ::pgrx::callconv::RetAbi::to_ret(call_result) } ::pgrx::callconv::CallCx::RestoreCx => <#ret_ty as ::pgrx::callconv::RetAbi>::ret_from_fcx(#fcinfo_ident), }; diff --git a/pgrx/src/callconv.rs b/pgrx/src/callconv.rs index 0166dab15..c9c99cb25 100644 --- a/pgrx/src/callconv.rs +++ b/pgrx/src/callconv.rs @@ -22,8 +22,8 @@ use crate::{ Timestamp, TimestampWithTimeZone, UnboxDatum, Uuid, }; use core::marker::PhantomData; -use core::mem; use core::panic::{RefUnwindSafe, UnwindSafe}; +use core::{iter, mem, slice}; use std::ffi::{CStr, CString}; use std::ptr::NonNull; @@ -51,7 +51,7 @@ pub unsafe trait ArgAbi<'fcx>: Sized { // FIXME: use an iterator or something? unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self; - unsafe fn uhh() -> () {} + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option; } pub fn wrap_fn<'fcx, A, F: FunctionMetadata>(fcinfo: &mut FcInfo<'fcx>, f: F) -> Datum<'fcx> { @@ -65,6 +65,10 @@ where unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { todo!() } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } unsafe impl<'fcx, T> ArgAbi<'fcx> for crate::datum::VariadicArray<'fcx, T> @@ -74,6 +78,10 @@ where unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { todo!() } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } // not sure how this is gonna work @@ -81,6 +89,10 @@ unsafe impl<'fcx, T> ArgAbi<'fcx> for crate::PgBox { unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { todo!() } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } unsafe impl<'fcx, W> ArgAbi<'fcx> for PgHeapTuple<'fcx, W> @@ -90,6 +102,10 @@ where unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { todo!() } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } unsafe impl<'fcx, T> ArgAbi<'fcx> for Option @@ -105,6 +121,10 @@ where Some(unsafe { ::unbox_from_fcinfo_index(fcinfo, index) }) } } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } unsafe impl<'fcx, T> ArgAbi<'fcx> for crate::Range @@ -121,6 +141,10 @@ where .unwrap_or_else(|| panic!("argument {index} must not be null")) } } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() }) + } } unsafe impl<'fcx, T> ArgAbi<'fcx> for Vec @@ -130,6 +154,10 @@ where unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { todo!() } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } unsafe impl<'fcx, T: Copy> ArgAbi<'fcx> for PgVarlena { @@ -141,6 +169,10 @@ unsafe impl<'fcx, T: Copy> ArgAbi<'fcx> for PgVarlena { assert_eq!(*isnull, false, "PgVarlena from argument {index} must not be null"); unsafe { Self::from_datum(*value) } } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } unsafe impl<'fcx, const P: u32, const S: u32> ArgAbi<'fcx> for crate::Numeric { @@ -154,12 +186,20 @@ unsafe impl<'fcx, const P: u32, const S: u32> ArgAbi<'fcx> for crate::Numeric) -> Option { + args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() }) + } } unsafe impl<'fcx> ArgAbi<'fcx> for pg_sys::FunctionCallInfo { unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { unsafe { fcinfo.as_mut_ptr() } } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } macro_rules! argue_from_datum { @@ -174,6 +214,10 @@ macro_rules! argue_from_datum { value } } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + args.next().and_then(|arg| unsafe { arg.unbox_arg_using_from_datum() }) + } })* }; } @@ -203,6 +247,10 @@ where unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { Defaulted(unsafe { ::unbox_from_fcinfo_index(fcinfo, index) }) } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } // basically intended to be the new version of the `name!` macro @@ -218,6 +266,10 @@ where unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { Named(unsafe { >::unbox_from_fcinfo_index(fcinfo, index) }) } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } // basically intended to be the new version of the `composite_type!` macro @@ -232,6 +284,10 @@ where unsafe fn unbox_from_fcinfo_index(fcinfo: &mut FcInfo<'fcx>, index: &mut usize) -> Self { CompositeType(unsafe { ::unbox_from_fcinfo_index(fcinfo, index) }) } + + unsafe fn unbox_argument(args: &mut Arguments<'_, 'fcx>) -> Option { + todo!() + } } /// How to return a value from Rust to Postgres @@ -260,7 +316,7 @@ pub unsafe trait RetAbi: Sized { CallCx::WrappedFn(unsafe { pg_sys::CurrentMemoryContext }) } - fn check_and_prepare<'fcx>(fcinfo: &mut FcInfo<'fcx>) -> CallCx { + fn check_and_prepare(fcinfo: &mut FcInfo<'_>) -> CallCx { unsafe { Self::check_fcinfo_and_prepare(fcinfo.0) } } @@ -297,7 +353,7 @@ pub unsafe trait RetAbi: Sized { unimplemented!() } - fn ret_from_fcx<'fcx>(fcinfo: &mut FcInfo<'fcx>) -> Self::Ret { + fn ret_from_fcx(fcinfo: &mut FcInfo<'_>) -> Self::Ret { let fcinfo = fcinfo.0; unsafe { Self::ret_from_fcinfo_fcx(fcinfo) } } @@ -547,10 +603,7 @@ impl<'fcx> FcInfo<'fcx> { } /// Retrieve the arguments to this function call as a slice of [`pgrx_pg_sys::NullableDatum`] #[inline] - pub fn raw_args<'a>(&'a self) -> &'fcx [pgrx_pg_sys::NullableDatum] - where - 'a: 'fcx, - { + pub fn raw_args(&self) -> &[pgrx_pg_sys::NullableDatum] { // Null pointer check already performed on immutable pointer // at construction time. unsafe { @@ -710,6 +763,39 @@ impl<'fcx> FcInfo<'fcx> { ReturnSetInfoWrapper::from_ptr((*self.0).resultinfo as *mut pg_sys::ReturnSetInfo) } } + + #[inline] + pub fn arguments<'arg>(&'arg self) -> Arguments<'arg, 'fcx> { + Arguments { iter: self.raw_args().iter().enumerate(), fcinfo: self } + } +} + +// TODO: rebadge this as AnyElement +pub struct Argument<'a, 'fcx>(&'a FcInfo<'fcx>, usize, &'a pg_sys::NullableDatum); + +impl<'a, 'fcx> Argument<'a, 'fcx> { + pub fn raw_oid(&self) -> pg_sys::Oid { + // we can just unwrap here because we know we were created using a valid index + self.0.get_arg_type(self.1).unwrap() + } + + pub unsafe fn unbox_arg_using_from_datum(self) -> Option { + let pg_sys::NullableDatum { isnull, value } = *self.2; + unsafe { FromDatum::from_datum(value, isnull) } + } +} + +pub struct Arguments<'a, 'fcx> { + iter: iter::Enumerate>, + fcinfo: &'a FcInfo<'fcx>, +} + +impl<'a, 'fcx> Iterator for Arguments<'a, 'fcx> { + type Item = Argument<'a, 'fcx>; + + fn next(&mut self) -> Option { + self.iter.next().map(|(i, dat)| Argument(self.fcinfo, i, dat)) + } } #[derive(Clone)]