1//! String settings validated when they are set. pgrx 0.19.2 made GUC 2//! hooks `unsafe` (#2348), so the hook lives here and callers supply the 3//! check as safe code through [`StringCheck`]. 4 5use std::ffi::{CStr, CString, c_char, c_void}; 6 7use pgrx::{GucCheckError, GucContext, GucFlags, GucRegistry, GucSetting, pg_guard, pg_sys}; 8 9/// Decides whether a proposed value is valid; `Err` carries the detail 10/// shown to the user. An unset value (NULL) is not checked. 11pub trait StringCheck { 12 fn check(value: &str) -> Result<(), String>; 13} 14 15/// Defines a string setting whose every `SET`, config-file value and 16/// placeholder adopted at load passes `C::check` first. Postgres reports 17/// 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} 42 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}