pgx_pg_sys/
lib.rs

1/*
2Portions Copyright 2019-2021 ZomboDB, LLC.
3Portions Copyright 2021-2022 Technology Concepts & Design, Inc. <support@tcdi.com>
4
5All rights reserved.
6
7Use of this source code is governed by the MIT license that can be found in the LICENSE file.
8*/
9
10//
11// we allow improper_ctypes just to eliminate these warnings:
12//      = note: `#[warn(improper_ctypes)]` on by default
13//      = note: 128-bit integers don't currently have a known stable ABI
14#![allow(non_camel_case_types)]
15#![allow(non_snake_case)]
16#![allow(dead_code)]
17#![allow(non_upper_case_globals)]
18#![allow(improper_ctypes)]
19#![allow(clippy::unneeded_field_pattern)]
20#![cfg_attr(nightly, feature(strict_provenance))]
21
22#[cfg(
23    any(
24        // no features at all will cause problems
25        not(any(feature = "pg11", feature = "pg12", feature = "pg13", feature = "pg14", feature = "pg15")),
26  ))]
27std::compile_error!("exactly one one feature must be provided (pg11, pg12, pg13, pg14, pg15)");
28
29pub mod submodules;
30
31use core::ffi::CStr;
32use core::ptr::NonNull;
33use std::os::raw::c_char;
34
35// for convenience we pull up everything submodules exposes
36pub use submodules::*;
37
38//
39// our actual bindings modules -- these are generated by build.rs
40//
41
42// feature gate each pg version module
43#[cfg(all(feature = "pg11", not(docsrs)))]
44mod pg11 {
45    include!(concat!(env!("OUT_DIR"), "/pg11.rs"));
46}
47#[cfg(all(feature = "pg11", docsrs))]
48mod pg11;
49
50#[cfg(all(feature = "pg12", not(docsrs)))]
51mod pg12 {
52    include!(concat!(env!("OUT_DIR"), "/pg12.rs"));
53}
54#[cfg(all(feature = "pg12", docsrs))]
55mod pg12;
56
57#[cfg(all(feature = "pg13", not(docsrs)))]
58mod pg13 {
59    include!(concat!(env!("OUT_DIR"), "/pg13.rs"));
60}
61#[cfg(all(feature = "pg13", docsrs))]
62mod pg13;
63
64#[cfg(all(feature = "pg14", not(docsrs)))]
65mod pg14 {
66    include!(concat!(env!("OUT_DIR"), "/pg14.rs"));
67}
68#[cfg(all(feature = "pg14", docsrs))]
69mod pg14;
70
71#[cfg(all(feature = "pg15", not(docsrs)))]
72mod pg15 {
73    include!(concat!(env!("OUT_DIR"), "/pg15.rs"));
74}
75#[cfg(all(feature = "pg15", docsrs))]
76mod pg15;
77
78// export each module publicly
79#[cfg(feature = "pg11")]
80pub use pg11::*;
81#[cfg(feature = "pg12")]
82pub use pg12::*;
83#[cfg(feature = "pg13")]
84pub use pg13::*;
85#[cfg(feature = "pg14")]
86pub use pg14::*;
87#[cfg(feature = "pg15")]
88pub use pg15::*;
89
90// feature gate each pg-specific oid module
91#[cfg(all(feature = "pg11", not(docsrs)))]
92mod pg11_oids {
93    include!(concat!(env!("OUT_DIR"), "/pg11_oids.rs"));
94}
95#[cfg(all(feature = "pg11", docsrs))]
96mod pg11;
97
98#[cfg(all(feature = "pg12", not(docsrs)))]
99mod pg12_oids {
100    include!(concat!(env!("OUT_DIR"), "/pg12_oids.rs"));
101}
102#[cfg(all(feature = "pg12", docsrs))]
103mod pg12_oids;
104
105#[cfg(all(feature = "pg13", not(docsrs)))]
106mod pg13_oids {
107    include!(concat!(env!("OUT_DIR"), "/pg13_oids.rs"));
108}
109#[cfg(all(feature = "pg13", docsrs))]
110mod pg13_oids;
111
112#[cfg(all(feature = "pg14", not(docsrs)))]
113mod pg14_oids {
114    include!(concat!(env!("OUT_DIR"), "/pg14_oids.rs"));
115}
116#[cfg(all(feature = "pg14", docsrs))]
117mod pg14_oids;
118
119#[cfg(all(feature = "pg15", not(docsrs)))]
120mod pg15_oids {
121    include!(concat!(env!("OUT_DIR"), "/pg15_oids.rs"));
122}
123#[cfg(all(feature = "pg15", docsrs))]
124mod pg15_oids;
125
126// export that module publicly
127#[cfg(feature = "pg11")]
128pub use pg11_oids::*;
129#[cfg(feature = "pg12")]
130pub use pg12_oids::*;
131#[cfg(feature = "pg13")]
132pub use pg13_oids::*;
133#[cfg(feature = "pg14")]
134pub use pg14_oids::*;
135#[cfg(feature = "pg15")]
136pub use pg15_oids::*;
137
138// expose things we want available for all versions
139pub use all_versions::*;
140
141// and things that are version-specific
142#[cfg(feature = "pg11")]
143pub use internal::pg11::IndexBuildHeapScan;
144#[cfg(feature = "pg11")]
145pub use internal::pg11::*;
146
147#[cfg(feature = "pg12")]
148pub use internal::pg12::*;
149
150#[cfg(feature = "pg13")]
151pub use internal::pg13::*;
152
153#[cfg(feature = "pg14")]
154pub use internal::pg14::*;
155
156#[cfg(feature = "pg15")]
157pub use internal::pg15::*;
158
159/// A trait applied to all Postgres `pg_sys::Node` types and subtypes
160pub trait PgNode: seal::Sealed {
161    /// Format this node
162    ///
163    /// # Safety
164    ///
165    /// While pgx controls the types for which [`PgNode`] is implemented and only pgx can implement
166    /// [`PgNode`] it cannot control the members of those types and a user could assign any pointer
167    /// type member to something invalid that Postgres wouldn't understand.
168    ///
169    /// Because this function is used by `impl Display` we purposely don't mark it `unsafe`.  The
170    /// assumption here, which might be a bad one, is that only intentional misuse would actually
171    /// cause undefined behavior.
172    #[inline]
173    fn display_node(&self) -> std::string::String {
174        // SAFETY: The trait is pub but this impl is private, and
175        // this is only implemented for things known to be "Nodes"
176        unsafe { display_node_impl(NonNull::from(self).cast()) }
177    }
178}
179
180mod seal {
181    pub trait Sealed {}
182}
183
184/// implementation function for `impl Display for $NodeType`
185///
186/// # Safety
187/// Don't use this on anything that doesn't impl PgNode, or the type may be off
188#[warn(unsafe_op_in_unsafe_fn)]
189pub(crate) unsafe fn display_node_impl(node: NonNull<crate::Node>) -> std::string::String {
190    // SAFETY: It's fine to call nodeToString with non-null well-typed pointers,
191    // and pg_sys::nodeToString() returns data via palloc, which is never null
192    // as Postgres will ERROR rather than giving us a null pointer,
193    // and Postgres starts and finishes constructing StringInfos by writing '\0'
194    unsafe {
195        let node_cstr = crate::nodeToString(node.as_ptr().cast());
196
197        let result = match CStr::from_ptr(node_cstr).to_str() {
198            Ok(cstr) => cstr.to_string(),
199            Err(e) => format!("<ffi error: {:?}>", e),
200        };
201
202        crate::pfree(node_cstr.cast());
203
204        result
205    }
206}
207
208/// A trait for converting a thing into a `char *` that is allocated by Postgres' palloc
209pub trait AsPgCStr {
210    /// Consumes `self` and converts it into a Postgres-allocated `char *`
211    fn as_pg_cstr(self) -> *mut std::os::raw::c_char;
212}
213
214impl<'a> AsPgCStr for &'a str {
215    fn as_pg_cstr(self) -> *mut std::os::raw::c_char {
216        let self_bytes = self.as_bytes();
217        let pg_cstr = unsafe { crate::palloc0(self_bytes.len() + 1) as *mut std::os::raw::c_uchar };
218        let slice = unsafe { std::slice::from_raw_parts_mut(pg_cstr, self_bytes.len()) };
219        slice.copy_from_slice(self_bytes);
220        pg_cstr as *mut std::os::raw::c_char
221    }
222}
223
224impl<'a> AsPgCStr for Option<&'a str> {
225    fn as_pg_cstr(self) -> *mut c_char {
226        match self {
227            Some(s) => s.as_pg_cstr(),
228            None => std::ptr::null_mut(),
229        }
230    }
231}
232
233impl AsPgCStr for std::string::String {
234    fn as_pg_cstr(self) -> *mut std::os::raw::c_char {
235        self.as_str().as_pg_cstr()
236    }
237}
238
239impl AsPgCStr for &std::string::String {
240    fn as_pg_cstr(self) -> *mut std::os::raw::c_char {
241        self.as_str().as_pg_cstr()
242    }
243}
244
245impl AsPgCStr for Option<std::string::String> {
246    fn as_pg_cstr(self) -> *mut c_char {
247        match self {
248            Some(s) => s.as_pg_cstr(),
249            None => std::ptr::null_mut(),
250        }
251    }
252}
253
254impl AsPgCStr for Option<&std::string::String> {
255    fn as_pg_cstr(self) -> *mut c_char {
256        match self {
257            Some(s) => s.as_pg_cstr(),
258            None => std::ptr::null_mut(),
259        }
260    }
261}
262
263impl AsPgCStr for &Option<std::string::String> {
264    fn as_pg_cstr(self) -> *mut c_char {
265        match self {
266            Some(s) => s.as_pg_cstr(),
267            None => std::ptr::null_mut(),
268        }
269    }
270}
271
272/// item declarations we want to add to all versions
273mod all_versions {
274    use crate as pg_sys;
275    use pgx_macros::*;
276
277    use memoffset::*;
278    use std::str::FromStr;
279
280    pub use crate::submodules::htup::*;
281
282    /// this comes from `postgres_ext.h`
283    pub const InvalidOid: crate::Oid = crate::Oid::INVALID;
284    pub const InvalidOffsetNumber: super::OffsetNumber = 0;
285    pub const FirstOffsetNumber: super::OffsetNumber = 1;
286    pub const MaxOffsetNumber: super::OffsetNumber =
287        (super::BLCKSZ as usize / std::mem::size_of::<super::ItemIdData>()) as super::OffsetNumber;
288    pub const InvalidBlockNumber: u32 = 0xFFFF_FFFF as crate::BlockNumber;
289    pub const VARHDRSZ: usize = std::mem::size_of::<super::int32>();
290    pub const InvalidTransactionId: super::TransactionId = 0 as super::TransactionId;
291    pub const InvalidCommandId: super::CommandId = (!(0 as super::CommandId)) as super::CommandId;
292    pub const FirstCommandId: super::CommandId = 0 as super::CommandId;
293    pub const BootstrapTransactionId: super::TransactionId = 1 as super::TransactionId;
294    pub const FrozenTransactionId: super::TransactionId = 2 as super::TransactionId;
295    pub const FirstNormalTransactionId: super::TransactionId = 3 as super::TransactionId;
296    pub const MaxTransactionId: super::TransactionId = 0xFFFF_FFFF as super::TransactionId;
297
298    #[cfg(feature = "cshim")]
299    #[pgx_macros::pg_guard]
300    extern "C" {
301        pub fn pgx_list_nth(list: *mut super::List, nth: i32) -> *mut std::os::raw::c_void;
302        pub fn pgx_list_nth_int(list: *mut super::List, nth: i32) -> i32;
303        pub fn pgx_list_nth_oid(list: *mut super::List, nth: i32) -> super::Oid;
304        pub fn pgx_list_nth_cell(list: *mut super::List, nth: i32) -> *mut super::ListCell;
305    }
306
307    /// Given a valid HeapTuple pointer, return address of the user data
308    ///
309    /// # Safety
310    ///
311    /// This function cannot determine if the `tuple` argument is really a non-null pointer to a [`HeapTuple`].
312    #[inline(always)]
313    pub unsafe fn GETSTRUCT(tuple: crate::HeapTuple) -> *mut std::os::raw::c_char {
314        // #define GETSTRUCT(TUP) ((char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff)
315
316        // SAFETY:  The caller has asserted `tuple` is a valid HeapTuple and is properly aligned
317        // Additionally, t_data.t_hoff is an a u8, so it'll fit inside a usize
318        (*tuple).t_data.cast::<std::os::raw::c_char>().add((*(*tuple).t_data).t_hoff as _)
319    }
320
321    //
322    // TODO: [`TYPEALIGN`] and [`MAXALIGN`] are also part of PR #948 and when that's all merged,
323    //       their uses should be switched to these
324    //
325
326    #[allow(non_snake_case)]
327    #[inline(always)]
328    pub const unsafe fn TYPEALIGN(alignval: usize, len: usize) -> usize {
329        // #define TYPEALIGN(ALIGNVAL,LEN)  \
330        // (((uintptr_t) (LEN) + ((ALIGNVAL) - 1)) & ~((uintptr_t) ((ALIGNVAL) - 1)))
331        ((len) + ((alignval) - 1)) & !((alignval) - 1)
332    }
333
334    #[allow(non_snake_case)]
335    #[inline(always)]
336    pub const unsafe fn MAXALIGN(len: usize) -> usize {
337        // #define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
338        TYPEALIGN(pg_sys::MAXIMUM_ALIGNOF as _, len)
339    }
340
341    ///  Given a currently-allocated chunk of Postgres allocated memory, determine the context
342    ///  it belongs to.
343    ///
344    /// All chunks allocated by any memory context manager are required to be
345    /// preceded by the corresponding MemoryContext stored, without padding, in the
346    /// preceding sizeof(void*) bytes.  A currently-allocated chunk must contain a
347    /// backpointer to its owning context.  The backpointer is used by pfree() and
348    /// repalloc() to find the context to call.
349    ///
350    /// # Safety
351    ///
352    /// The specified `pointer` **must** be one allocated by Postgres (via [`palloc`] and friends).
353    ///
354    ///
355    /// # Panics
356    ///
357    /// This function will panic if `pointer` is null, if it's not properly aligned, or if the memory
358    /// it points do doesn't have the a header that looks like a memory context pointer
359    #[allow(non_snake_case)]
360    pub unsafe fn GetMemoryContextChunk(
361        pointer: *mut std::os::raw::c_void,
362    ) -> pg_sys::MemoryContext {
363        /*
364         * Try to detect bogus pointers handed to us, poorly though we can.
365         * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
366         * allocated chunk.
367         */
368        assert!(!pointer.is_null());
369        assert_eq!(pointer, MAXALIGN(pointer as usize) as *mut ::std::os::raw::c_void);
370
371        /*
372         * OK, it's probably safe to look at the context.
373         */
374        // 	context = *(MemoryContext *) (((char *) pointer) - sizeof(void *));
375        let context = unsafe {
376            // SAFETY: the caller has assured us that `pointer` points to palloc'd memory, which
377            // means it'll have this header before it
378            *(pointer
379                .cast::<::std::os::raw::c_char>()
380                .sub(std::mem::size_of::<*mut ::std::os::raw::c_void>())
381                .cast())
382        };
383
384        assert!(MemoryContextIsValid(context));
385
386        context
387    }
388
389    /// Returns true if memory context is valid, as Postgres determines such a thing.
390    ///
391    /// # Safety
392    ///
393    /// Caller must determine that the specified `context` pointer, if it's probably a [`MemoryContextData`]
394    /// pointer, really is.  This function is a best effort, not a guarantee.
395    ///
396    /// # Implementation Note
397    ///
398    /// If Postgres adds more memory context types in the future, we need to do that here too.
399    #[allow(non_snake_case)]
400    #[inline(always)]
401    pub unsafe fn MemoryContextIsValid(context: *mut crate::MemoryContextData) -> bool {
402        // #define MemoryContextIsValid(context) \
403        // 	((context) != NULL && \
404        // 	 (IsA((context), AllocSetContext) || \
405        // 	  IsA((context), SlabContext) || \
406        // 	  IsA((context), GenerationContext)))
407
408        !context.is_null()
409            && unsafe {
410                // SAFETY:  we just determined that context isn't null, so it's safe to `.as_ref()`
411                // and `.unwrap_unchecked()`
412                (*context).type_ == crate::NodeTag_T_AllocSetContext
413                    || (*context).type_ == crate::NodeTag_T_SlabContext
414                    || (*context).type_ == crate::NodeTag_T_GenerationContext
415            }
416    }
417
418    #[inline]
419    pub fn VARHDRSZ_EXTERNAL() -> usize {
420        offset_of!(super::varattrib_1b_e, va_data)
421    }
422
423    #[inline]
424    pub fn VARHDRSZ_SHORT() -> usize {
425        offset_of!(super::varattrib_1b, va_data)
426    }
427
428    #[inline]
429    pub fn get_pg_major_version_string() -> &'static str {
430        let mver = core::ffi::CStr::from_bytes_with_nul(super::PG_MAJORVERSION).unwrap();
431        mver.to_str().unwrap()
432    }
433
434    #[inline]
435    pub fn get_pg_major_version_num() -> u16 {
436        u16::from_str(super::get_pg_major_version_string()).unwrap()
437    }
438
439    #[inline]
440    pub fn get_pg_version_string() -> &'static str {
441        let ver = core::ffi::CStr::from_bytes_with_nul(super::PG_VERSION_STR).unwrap();
442        ver.to_str().unwrap()
443    }
444
445    #[inline]
446    pub fn get_pg_major_minor_version_string() -> &'static str {
447        let mver = core::ffi::CStr::from_bytes_with_nul(super::PG_VERSION).unwrap();
448        mver.to_str().unwrap()
449    }
450
451    #[inline]
452    pub fn TransactionIdIsNormal(xid: super::TransactionId) -> bool {
453        xid >= FirstNormalTransactionId
454    }
455
456    /// ```c
457    ///     #define type_is_array(typid)  (get_element_type(typid) != InvalidOid)
458    /// ```
459    #[inline]
460    pub unsafe fn type_is_array(typoid: super::Oid) -> bool {
461        super::get_element_type(typoid) != InvalidOid
462    }
463
464    #[cfg(feature = "cshim")]
465    #[pg_guard]
466    extern "C" {
467        #[link_name = "pgx_planner_rt_fetch"]
468        pub fn planner_rt_fetch(
469            index: super::Index,
470            root: *mut super::PlannerInfo,
471        ) -> *mut super::RangeTblEntry;
472    }
473
474    /// ```c
475    /// #define rt_fetch(rangetable_index, rangetable) \
476    ///     ((RangeTblEntry *) list_nth(rangetable, (rangetable_index)-1))
477    /// ```
478    #[cfg(feature = "cshim")]
479    #[inline]
480    pub unsafe fn rt_fetch(
481        index: super::Index,
482        range_table: *mut super::List,
483    ) -> *mut super::RangeTblEntry {
484        pgx_list_nth(range_table, index as i32 - 1) as *mut super::RangeTblEntry
485    }
486
487    /// #define BufferGetPage(buffer) ((Page)BufferGetBlock(buffer))
488    #[inline]
489    pub unsafe fn BufferGetPage(buffer: crate::Buffer) -> crate::Page {
490        BufferGetBlock(buffer) as crate::Page
491    }
492
493    /// #define BufferGetBlock(buffer) \
494    /// ( \
495    ///      AssertMacro(BufferIsValid(buffer)), \
496    ///      BufferIsLocal(buffer) ? \
497    ///            LocalBufferBlockPointers[-(buffer) - 1] \
498    ///      : \
499    ///            (Block) (BufferBlocks + ((Size) ((buffer) - 1)) * BLCKSZ) \
500    /// )
501    #[inline]
502    pub unsafe fn BufferGetBlock(buffer: crate::Buffer) -> crate::Block {
503        if BufferIsLocal(buffer) {
504            *crate::LocalBufferBlockPointers.offset(((-buffer) - 1) as isize)
505        } else {
506            crate::BufferBlocks
507                .offset((((buffer as crate::Size) - 1) * crate::BLCKSZ as usize) as isize)
508                as crate::Block
509        }
510    }
511
512    /// #define BufferIsLocal(buffer)      ((buffer) < 0)
513    #[inline]
514    pub unsafe fn BufferIsLocal(buffer: crate::Buffer) -> bool {
515        buffer < 0
516    }
517
518    /// Retrieve the "user data" of the specified [`HeapTuple`] as a specific type. Typically this
519    /// will be a struct that represents a Postgres system catalog, such as [`FormData_pg_class`].
520    ///
521    /// # Returns
522    ///
523    /// A pointer to the [`HeapTuple`]'s "user data", cast as a mutable pointer to `T`.  If the
524    /// specified `htup` pointer is null, the null pointer is returned.
525    ///
526    /// # Safety
527    ///
528    /// This function cannot verify that the specified `htup` points to a valid [`HeapTuple`] nor
529    /// that if it does, that its bytes are bitwise compatible with `T`.
530    #[inline]
531    pub unsafe fn heap_tuple_get_struct<T>(htup: super::HeapTuple) -> *mut T {
532        if htup.is_null() {
533            std::ptr::null_mut()
534        } else {
535            unsafe {
536                // SAFETY:  The caller has told us `htop` is a valid HeapTuple
537                GETSTRUCT(htup).cast()
538            }
539        }
540    }
541
542    #[pg_guard]
543    extern "C" {
544        pub fn query_tree_walker(
545            query: *mut super::Query,
546            walker: ::std::option::Option<
547                unsafe extern "C" fn(*mut super::Node, *mut ::std::os::raw::c_void) -> bool,
548            >,
549            context: *mut ::std::os::raw::c_void,
550            flags: ::std::os::raw::c_int,
551        ) -> bool;
552    }
553
554    #[pg_guard]
555    extern "C" {
556        pub fn expression_tree_walker(
557            node: *mut super::Node,
558            walker: ::std::option::Option<
559                unsafe extern "C" fn(*mut super::Node, *mut ::std::os::raw::c_void) -> bool,
560            >,
561            context: *mut ::std::os::raw::c_void,
562        ) -> bool;
563    }
564
565    #[cfg(feature = "cshim")]
566    #[pgx_macros::pg_guard]
567    extern "C" {
568        #[link_name = "pgx_SpinLockInit"]
569        pub fn SpinLockInit(lock: *mut pg_sys::slock_t);
570        #[link_name = "pgx_SpinLockAcquire"]
571        pub fn SpinLockAcquire(lock: *mut pg_sys::slock_t);
572        #[link_name = "pgx_SpinLockRelease"]
573        pub fn SpinLockRelease(lock: *mut pg_sys::slock_t);
574        #[link_name = "pgx_SpinLockFree"]
575        pub fn SpinLockFree(lock: *mut pg_sys::slock_t) -> bool;
576    }
577
578    #[inline(always)]
579    pub unsafe fn MemoryContextSwitchTo(context: crate::MemoryContext) -> crate::MemoryContext {
580        let old = crate::CurrentMemoryContext;
581
582        crate::CurrentMemoryContext = context;
583        old
584    }
585}
586
587mod internal {
588    //
589    // for specific versions
590    //
591    #[cfg(feature = "pg11")]
592    pub(crate) mod pg11 {
593        pub use crate::pg11::tupleDesc as TupleDescData;
594        pub type QueryCompletion = std::os::raw::c_char;
595
596        /// # Safety
597        ///
598        /// This function wraps Postgres' internal `IndexBuildHeapScan` method, and therefore, is
599        /// inherently unsafe
600        pub unsafe fn IndexBuildHeapScan<T>(
601            heap_relation: crate::Relation,
602            index_relation: crate::Relation,
603            index_info: *mut crate::pg11::IndexInfo,
604            build_callback: crate::IndexBuildCallback,
605            build_callback_state: *mut T,
606        ) {
607            crate::pg11::IndexBuildHeapScan(
608                heap_relation,
609                index_relation,
610                index_info,
611                true,
612                build_callback,
613                build_callback_state as *mut std::os::raw::c_void,
614                std::ptr::null_mut(),
615            );
616        }
617    }
618
619    #[cfg(feature = "pg12")]
620    pub(crate) mod pg12 {
621        pub use crate::pg12::AllocSetContextCreateInternal as AllocSetContextCreateExtended;
622        pub type QueryCompletion = std::os::raw::c_char;
623
624        pub const QTW_EXAMINE_RTES: u32 = crate::pg12::QTW_EXAMINE_RTES_BEFORE;
625
626        /// # Safety
627        ///
628        /// This function wraps Postgres' internal `IndexBuildHeapScan` method, and therefore, is
629        /// inherently unsafe
630        pub unsafe fn IndexBuildHeapScan<T>(
631            heap_relation: crate::Relation,
632            index_relation: crate::Relation,
633            index_info: *mut crate::pg12::IndexInfo,
634            build_callback: crate::IndexBuildCallback,
635            build_callback_state: *mut T,
636        ) {
637            let heap_relation_ref = heap_relation.as_ref().unwrap();
638            let table_am = heap_relation_ref.rd_tableam.as_ref().unwrap();
639
640            table_am.index_build_range_scan.unwrap()(
641                heap_relation,
642                index_relation,
643                index_info,
644                true,
645                false,
646                true,
647                0,
648                crate::InvalidBlockNumber,
649                build_callback,
650                build_callback_state as *mut std::os::raw::c_void,
651                std::ptr::null_mut(),
652            );
653        }
654    }
655
656    #[cfg(feature = "pg13")]
657    pub(crate) mod pg13 {
658        pub use crate::pg13::AllocSetContextCreateInternal as AllocSetContextCreateExtended;
659
660        pub const QTW_EXAMINE_RTES: u32 = crate::pg13::QTW_EXAMINE_RTES_BEFORE;
661
662        /// # Safety
663        ///
664        /// This function wraps Postgres' internal `IndexBuildHeapScan` method, and therefore, is
665        /// inherently unsafe
666        pub unsafe fn IndexBuildHeapScan<T>(
667            heap_relation: crate::Relation,
668            index_relation: crate::Relation,
669            index_info: *mut crate::IndexInfo,
670            build_callback: crate::IndexBuildCallback,
671            build_callback_state: *mut T,
672        ) {
673            let heap_relation_ref = heap_relation.as_ref().unwrap();
674            let table_am = heap_relation_ref.rd_tableam.as_ref().unwrap();
675
676            table_am.index_build_range_scan.unwrap()(
677                heap_relation,
678                index_relation,
679                index_info,
680                true,
681                false,
682                true,
683                0,
684                crate::InvalidBlockNumber,
685                build_callback,
686                build_callback_state as *mut std::os::raw::c_void,
687                std::ptr::null_mut(),
688            );
689        }
690    }
691
692    #[cfg(feature = "pg14")]
693    pub(crate) mod pg14 {
694        pub use crate::pg14::AllocSetContextCreateInternal as AllocSetContextCreateExtended;
695
696        pub const QTW_EXAMINE_RTES: u32 = crate::pg14::QTW_EXAMINE_RTES_BEFORE;
697
698        /// # Safety
699        ///
700        /// This function wraps Postgres' internal `IndexBuildHeapScan` method, and therefore, is
701        /// inherently unsafe
702        pub unsafe fn IndexBuildHeapScan<T>(
703            heap_relation: crate::Relation,
704            index_relation: crate::Relation,
705            index_info: *mut crate::IndexInfo,
706            build_callback: crate::IndexBuildCallback,
707            build_callback_state: *mut T,
708        ) {
709            let heap_relation_ref = heap_relation.as_ref().unwrap();
710            let table_am = heap_relation_ref.rd_tableam.as_ref().unwrap();
711
712            table_am.index_build_range_scan.unwrap()(
713                heap_relation,
714                index_relation,
715                index_info,
716                true,
717                false,
718                true,
719                0,
720                crate::InvalidBlockNumber,
721                build_callback,
722                build_callback_state as *mut std::os::raw::c_void,
723                std::ptr::null_mut(),
724            );
725        }
726    }
727
728    #[cfg(feature = "pg15")]
729    pub(crate) mod pg15 {
730        pub use crate::pg15::AllocSetContextCreateInternal as AllocSetContextCreateExtended;
731
732        pub const QTW_EXAMINE_RTES: u32 = crate::pg15::QTW_EXAMINE_RTES_BEFORE;
733
734        /// # Safety
735        ///
736        /// This function wraps Postgres' internal `IndexBuildHeapScan` method, and therefore, is
737        /// inherently unsafe
738        pub unsafe fn IndexBuildHeapScan<T>(
739            heap_relation: crate::Relation,
740            index_relation: crate::Relation,
741            index_info: *mut crate::IndexInfo,
742            build_callback: crate::IndexBuildCallback,
743            build_callback_state: *mut T,
744        ) {
745            let heap_relation_ref = heap_relation.as_ref().unwrap();
746            let table_am = heap_relation_ref.rd_tableam.as_ref().unwrap();
747
748            table_am.index_build_range_scan.unwrap()(
749                heap_relation,
750                index_relation,
751                index_info,
752                true,
753                false,
754                true,
755                0,
756                crate::InvalidBlockNumber,
757                build_callback,
758                build_callback_state as *mut std::os::raw::c_void,
759                std::ptr::null_mut(),
760            );
761        }
762    }
763}
764
765// Hack to fix linker errors that we get under amazonlinux2 on some PG versions
766// due to our wrappers for various system library functions. Should be fairly
767// harmless, but ideally we would not wrap these functions
768// (https://github.com/tcdi/pgx/issues/730).
769#[cfg(target_os = "linux")]
770#[link(name = "resolv")]
771extern "C" {}