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}