pgrx_pg_sys/node.rs
1use core::ffi::CStr;
2use core::ptr::NonNull;
3
4/// A trait applied to all Postgres `pg_sys::Node` types and subtypes
5pub trait PgNode: crate::seal::Sealed {
6 /// Format this node
7 ///
8 /// # Safety
9 ///
10 /// While pgrx controls the types for which [`PgNode`] is implemented and only pgrx can implement
11 /// [`PgNode`] it cannot control the members of those types and a user could assign any pointer
12 /// type member to something invalid that Postgres wouldn't understand.
13 ///
14 /// Because this function is used by `impl Display` we purposely don't mark it `unsafe`. The
15 /// assumption here, which might be a bad one, is that only intentional misuse would actually
16 /// cause undefined behavior.
17 #[inline]
18 fn display_node(&self) -> String {
19 // SAFETY: The trait is pub but this impl is private, and
20 // this is only implemented for things known to be "Nodes"
21 unsafe { display_node_impl(NonNull::from(self).cast()) }
22 }
23}
24
25/// implementation function for `impl Display for $NodeType`
26///
27/// # Safety
28/// Don't use this on anything that doesn't impl PgNode, or the type may be off
29#[warn(unsafe_op_in_unsafe_fn)]
30pub(crate) unsafe fn display_node_impl(node: NonNull<crate::Node>) -> String {
31 // SAFETY: It's fine to call nodeToString with non-null well-typed pointers,
32 // and pg_sys::nodeToString() returns data via palloc, which is never null
33 // as Postgres will ERROR rather than giving us a null pointer,
34 // and Postgres starts and finishes constructing StringInfos by writing '\0'
35 unsafe {
36 let node_cstr = crate::nodeToString(node.as_ptr().cast());
37
38 let result = match CStr::from_ptr(node_cstr).to_str() {
39 Ok(cstr) => cstr.to_string(),
40 Err(e) => format!("<ffi error: {e:?}>"),
41 };
42
43 crate::pfree(node_cstr.cast());
44
45 result
46 }
47}