Running as a relation's owner, as a SECURITY DEFINER function does.
The answer cache is readable and writable only by its owner: a role
that could write it could forge answers, as jev.mock_response would
(contract Cost and safety). A role granted EXECUTE on jev_prob
must still use it, so the scan reaches it as the owner.
8use std::ffi::CStr;
10use pgrx::{pg_sys, spi::Spi};
Runs f as the owner of relation. The previous user is restored on
return and on unwind; an ERROR's abort restores it too.
14pub fn as_owner_of<T>(relation: &CStr, f: impl FnOnce() -> T) -> Result<T, String> { 15 let name = relation.to_str().map_err(|e| e.to_string())?; 16 let owner = Spi::get_one_with_args::<pg_sys::Oid>( 17 "SELECT relowner FROM pg_class WHERE oid = to_regclass($1)", 18 &[name.into()], 19 ) 20 .map_err(|e| e.to_string())? 21 .ok_or_else(|| format!("{name} does not exist"))?; 22 let mut previous = pg_sys::InvalidOid; 23 let mut context = 0; 24 // SAFETY: the pair a SECURITY DEFINER call makes (fmgr.c), on the 25 // backend thread; `Restore` undoes it exactly once. 26 unsafe { 27 pg_sys::GetUserIdAndSecContext(&mut previous, &mut context); 28 pg_sys::SetUserIdAndSecContext(owner, context | pg_sys::SECURITY_LOCAL_USERID_CHANGE as i32); 29 } 30 let _restore = Restore { previous, context }; 31 Ok(f()) 32}