String settings validated when they are set. pgrx 0.19.2 made GUC
hooks unsafe (#2348), so the hook lives here and callers supply the
check as safe code through [StringCheck].
5use std::ffi::{CStr, CString, c_char, c_void};
7use pgrx::{GucCheckError, GucContext, GucFlags, GucRegistry, GucSetting, pg_guard, pg_sys};
Decides whether a proposed value is valid; Err carries the detail
shown to the user. An unset value (NULL) is not checked.
Defines a string setting whose every SET, config-file value and
placeholder adopted at load passes C::check first. Postgres reports
a refusal as invalid value for parameter "<name>" with the detail.
18pub fn define_checked_string<C: StringCheck>( 19 name: &'static CStr, 20 short_description: &'static CStr, 21 long_description: &'static CStr, 22 setting: &'static GucSetting<Option<CString>>, 23 context: GucContext, 24 flags: GucFlags, 25) { 26 // SAFETY: the check hook is #[pg_guard]ed, so a panic in `C::check` 27 // becomes an ERROR instead of unwinding into Postgres. 28 unsafe { 29 GucRegistry::define_string_guc_with_hooks( 30 name, 31 short_description, 32 long_description, 33 setting, 34 context, 35 flags, 36 Some(check_hook::<C>), 37 None, 38 None, 39 ); 40 } 41}
43#[pg_guard] 44unsafe extern "C-unwind" fn check_hook<C: StringCheck>( 45 newval: *mut *mut c_char, 46 _extra: *mut *mut c_void, 47 _source: pg_sys::GucSource::Type, 48) -> bool { 49 // SAFETY: guc.c passes a valid pointer to the proposed value, which 50 // is NULL or a NUL-terminated string for the duration of the call. 51 let value = unsafe { *newval }; 52 if value.is_null() { 53 return true; 54 } 55 let value = unsafe { CStr::from_ptr(value) }.to_string_lossy(); 56 match C::check(&value) { 57 Ok(()) => true, 58 Err(detail) => { 59 // SAFETY: called from within a check hook, as `apply` requires. 60 unsafe { GucCheckError::default().with_detail(detail).apply() }; 61 false 62 } 63 } 64}