1use crate as pg_sys;
2use core::mem::offset_of;
3use core::str::FromStr;
4
5pub const InvalidOid: crate::Oid = crate::Oid::INVALID;
7pub const InvalidOffsetNumber: super::OffsetNumber = 0;
8pub const FirstOffsetNumber: super::OffsetNumber = 1;
9pub const MaxOffsetNumber: super::OffsetNumber =
10 (super::BLCKSZ as usize / std::mem::size_of::<super::ItemIdData>()) as super::OffsetNumber;
11pub const InvalidBlockNumber: u32 = 0xFFFF_FFFF as crate::BlockNumber;
12pub const VARHDRSZ: usize = std::mem::size_of::<super::int32>();
13pub const InvalidCommandId: super::CommandId = (!(0 as super::CommandId)) as super::CommandId;
14pub const FirstCommandId: super::CommandId = 0 as super::CommandId;
15pub const InvalidTransactionId: crate::TransactionId = crate::TransactionId::INVALID;
16pub const BootstrapTransactionId: crate::TransactionId = crate::TransactionId::BOOTSTRAP;
17pub const FrozenTransactionId: crate::TransactionId = crate::TransactionId::FROZEN;
18pub const FirstNormalTransactionId: crate::TransactionId = crate::TransactionId::FIRST_NORMAL;
19pub const MaxTransactionId: crate::TransactionId = crate::TransactionId::MAX;
20
21#[inline(always)]
27pub unsafe fn GETSTRUCT(tuple: crate::HeapTuple) -> *mut std::os::raw::c_char {
28 (*tuple).t_data.cast::<std::os::raw::c_char>().add((*(*tuple).t_data).t_hoff as _)
33}
34
35#[allow(non_snake_case)]
41#[inline(always)]
42pub const unsafe fn TYPEALIGN(alignval: usize, len: usize) -> usize {
43 ((len) + ((alignval) - 1)) & !((alignval) - 1)
46}
47
48#[allow(non_snake_case)]
49#[inline(always)]
50pub const unsafe fn MAXALIGN(len: usize) -> usize {
51 TYPEALIGN(pg_sys::MAXIMUM_ALIGNOF as _, len)
53}
54
55#[allow(non_snake_case)]
76pub unsafe fn GetMemoryChunkContext(pointer: *mut std::os::raw::c_void) -> pg_sys::MemoryContext {
77 #[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
78 {
79 assert!(!pointer.is_null());
87 assert_eq!(pointer, MAXALIGN(pointer as usize) as *mut ::std::os::raw::c_void);
88
89 let context = unsafe {
94 *(pointer
97 .cast::<::std::os::raw::c_char>()
98 .sub(std::mem::size_of::<*mut ::std::os::raw::c_void>())
99 .cast())
100 };
101
102 assert!(MemoryContextIsValid(context));
103
104 context
105 }
106 #[cfg(any(feature = "pg16", feature = "pg17"))]
107 {
108 #[pgrx_macros::pg_guard]
109 extern "C-unwind" {
110 #[link_name = "GetMemoryChunkContext"]
111 pub fn extern_fn(pointer: *mut std::os::raw::c_void) -> pg_sys::MemoryContext;
112 }
113 extern_fn(pointer)
114 }
115}
116
117#[allow(non_snake_case)]
128#[inline(always)]
129pub unsafe fn MemoryContextIsValid(context: crate::MemoryContext) -> bool {
130 !context.is_null()
137 && unsafe {
138 let tag = (*context.cast::<crate::Node>()).type_;
141 use crate::NodeTag::*;
142 matches!(tag, T_AllocSetContext | T_SlabContext | T_GenerationContext)
143 }
144}
145
146pub const VARHDRSZ_EXTERNAL: usize = offset_of!(super::varattrib_1b_e, va_data);
147pub const VARHDRSZ_SHORT: usize = offset_of!(super::varattrib_1b, va_data);
148
149#[inline]
150pub fn get_pg_major_version_string() -> &'static str {
151 super::PG_MAJORVERSION.to_str().unwrap()
152}
153
154#[inline]
155pub fn get_pg_major_version_num() -> u16 {
156 u16::from_str(super::get_pg_major_version_string()).unwrap()
157}
158
159#[cfg(any(not(target_env = "msvc"), feature = "pg17"))]
160#[inline]
161pub fn get_pg_version_string() -> &'static str {
162 super::PG_VERSION_STR.to_str().unwrap()
163}
164
165#[cfg(all(
166 target_env = "msvc",
167 any(feature = "pg13", feature = "pg14", feature = "pg15", feature = "pg16")
168))]
169#[inline]
170pub fn get_pg_version_string() -> &'static str {
171 static PG_VERSION_STR: [u8; 256] = const {
174 let major = super::PG_MAJORVERSION_NUM;
175 let minor = super::PG_MINORVERSION_NUM;
176 #[cfg(target_pointer_width = "32")]
177 let pointer_width = 32_u32;
178 #[cfg(target_pointer_width = "64")]
179 let pointer_width = 64_u32;
180 let msc_ver = b"1700";
182 let mut buffer = [0u8; 256];
183 let mut pointer = 0;
184 {
185 let s = b"PostgreSQL ";
186 let mut i = 0;
187 while i < s.len() {
188 buffer[pointer + i] = s[i];
189 i += 1;
190 }
191 pointer += s.len();
192 }
193 {
194 buffer[pointer + 0] = b'0' + (major / 10) as u8;
195 buffer[pointer + 1] = b'0' + (major % 10) as u8;
196 pointer += 2;
197 }
198 {
199 let s = b".";
200 let mut i = 0;
201 while i < s.len() {
202 buffer[pointer + i] = s[i];
203 i += 1;
204 }
205 pointer += s.len();
206 }
207 if minor < 10 {
208 buffer[pointer + 0] = b'0' + (minor % 10) as u8;
209 pointer += 1;
210 } else {
211 buffer[pointer + 0] = b'0' + (minor / 10) as u8;
212 buffer[pointer + 1] = b'0' + (minor % 10) as u8;
213 pointer += 2;
214 }
215 {
216 let s = b", compiled by Visual C++ build ";
217 let mut i = 0;
218 while i < s.len() {
219 buffer[pointer + i] = s[i];
220 i += 1;
221 }
222 pointer += s.len();
223 }
224 {
225 let s = msc_ver;
226 let mut i = 0;
227 while i < s.len() {
228 buffer[pointer + i] = s[i];
229 i += 1;
230 }
231 pointer += s.len();
232 }
233 {
234 let s = b", ";
235 let mut i = 0;
236 while i < s.len() {
237 buffer[pointer + i] = s[i];
238 i += 1;
239 }
240 pointer += s.len();
241 }
242 {
243 buffer[pointer + 0] = b'0' + (pointer_width / 10) as u8;
244 buffer[pointer + 1] = b'0' + (pointer_width % 10) as u8;
245 pointer += 2;
246 }
247 {
248 let s = b"-bit";
249 let mut i = 0;
250 while i < s.len() {
251 buffer[pointer + i] = s[i];
252 i += 1;
253 }
254 pointer += s.len();
255 }
256 buffer[pointer] = 0;
257 buffer
258 };
259 unsafe { std::ffi::CStr::from_ptr(PG_VERSION_STR.as_ptr().cast()).to_str().unwrap() }
260}
261
262#[inline]
263pub fn get_pg_major_minor_version_string() -> &'static str {
264 super::PG_VERSION.to_str().unwrap()
265}
266
267#[inline]
268pub fn TransactionIdIsNormal(xid: super::TransactionId) -> bool {
269 xid >= FirstNormalTransactionId
270}
271
272#[inline]
276pub unsafe fn type_is_array(typoid: super::Oid) -> bool {
277 super::get_element_type(typoid) != InvalidOid
278}
279
280#[inline]
282pub unsafe fn BufferGetPage(buffer: crate::Buffer) -> crate::Page {
283 BufferGetBlock(buffer) as crate::Page
284}
285
286#[inline]
295pub unsafe fn BufferGetBlock(buffer: crate::Buffer) -> crate::Block {
296 if BufferIsLocal(buffer) {
297 *crate::LocalBufferBlockPointers.offset(((-buffer) - 1) as isize)
298 } else {
299 crate::BufferBlocks.add(((buffer as crate::Size) - 1) * crate::BLCKSZ as usize)
300 as crate::Block
301 }
302}
303
304#[inline]
306pub unsafe fn BufferIsLocal(buffer: crate::Buffer) -> bool {
307 buffer < 0
308}
309
310#[inline]
325pub unsafe fn heap_tuple_get_struct<T>(htup: super::HeapTuple) -> *mut T {
326 if htup.is_null() {
327 std::ptr::null_mut()
328 } else {
329 unsafe {
330 GETSTRUCT(htup).cast()
332 }
333 }
334}
335
336#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
342#[::pgrx_macros::pg_guard]
343extern "C-unwind" {
344 pub fn planstate_tree_walker(
345 planstate: *mut super::PlanState,
346 walker: ::core::option::Option<
347 unsafe extern "C-unwind" fn(*mut super::PlanState, *mut ::core::ffi::c_void) -> bool,
348 >,
349 context: *mut ::core::ffi::c_void,
350 ) -> bool;
351
352 pub fn query_tree_walker(
353 query: *mut super::Query,
354 walker: ::core::option::Option<
355 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
356 >,
357 context: *mut ::core::ffi::c_void,
358 flags: ::core::ffi::c_int,
359 ) -> bool;
360
361 pub fn query_or_expression_tree_walker(
362 node: *mut super::Node,
363 walker: ::core::option::Option<
364 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
365 >,
366 context: *mut ::core::ffi::c_void,
367 flags: ::core::ffi::c_int,
368 ) -> bool;
369
370 pub fn range_table_entry_walker(
371 rte: *mut super::RangeTblEntry,
372 walker: ::core::option::Option<
373 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
374 >,
375 context: *mut ::core::ffi::c_void,
376 flags: ::core::ffi::c_int,
377 ) -> bool;
378
379 pub fn range_table_walker(
380 rtable: *mut super::List,
381 walker: ::core::option::Option<
382 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
383 >,
384 context: *mut ::core::ffi::c_void,
385 flags: ::core::ffi::c_int,
386 ) -> bool;
387
388 pub fn expression_tree_walker(
389 node: *mut super::Node,
390 walker: ::core::option::Option<
391 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
392 >,
393 context: *mut ::core::ffi::c_void,
394 ) -> bool;
395
396 pub fn raw_expression_tree_walker(
397 node: *mut super::Node,
398 walker: ::core::option::Option<
399 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
400 >,
401 context: *mut ::core::ffi::c_void,
402 ) -> bool;
403}
404
405#[cfg(any(feature = "pg16", feature = "pg17"))]
406pub unsafe fn planstate_tree_walker(
407 planstate: *mut super::PlanState,
408 walker: ::core::option::Option<
409 unsafe extern "C-unwind" fn(*mut super::PlanState, *mut ::core::ffi::c_void) -> bool,
410 >,
411 context: *mut ::core::ffi::c_void,
412) -> bool {
413 crate::planstate_tree_walker_impl(planstate, walker, context)
414}
415
416#[cfg(any(feature = "pg16", feature = "pg17"))]
417pub unsafe fn query_tree_walker(
418 query: *mut super::Query,
419 walker: ::core::option::Option<
420 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
421 >,
422 context: *mut ::core::ffi::c_void,
423 flags: ::core::ffi::c_int,
424) -> bool {
425 crate::query_tree_walker_impl(query, walker, context, flags)
426}
427
428#[cfg(any(feature = "pg16", feature = "pg17"))]
429pub unsafe fn query_or_expression_tree_walker(
430 node: *mut super::Node,
431 walker: ::core::option::Option<
432 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
433 >,
434 context: *mut ::core::ffi::c_void,
435 flags: ::core::ffi::c_int,
436) -> bool {
437 crate::query_or_expression_tree_walker_impl(node, walker, context, flags)
438}
439
440#[cfg(any(feature = "pg16", feature = "pg17"))]
441pub unsafe fn expression_tree_walker(
442 node: *mut crate::Node,
443 walker: Option<unsafe extern "C-unwind" fn(*mut crate::Node, *mut ::core::ffi::c_void) -> bool>,
444 context: *mut ::core::ffi::c_void,
445) -> bool {
446 crate::expression_tree_walker_impl(node, walker, context)
447}
448
449#[cfg(any(feature = "pg16", feature = "pg17"))]
450pub unsafe fn range_table_entry_walker(
451 rte: *mut super::RangeTblEntry,
452 walker: ::core::option::Option<
453 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
454 >,
455 context: *mut ::core::ffi::c_void,
456 flags: ::core::ffi::c_int,
457) -> bool {
458 crate::range_table_entry_walker_impl(rte, walker, context, flags)
459}
460
461#[cfg(any(feature = "pg16", feature = "pg17"))]
462pub unsafe fn range_table_walker(
463 rtable: *mut super::List,
464 walker: ::core::option::Option<
465 unsafe extern "C-unwind" fn(*mut super::Node, *mut ::core::ffi::c_void) -> bool,
466 >,
467 context: *mut ::core::ffi::c_void,
468 flags: ::core::ffi::c_int,
469) -> bool {
470 crate::range_table_walker_impl(rtable, walker, context, flags)
471}
472
473#[cfg(any(feature = "pg16", feature = "pg17"))]
474pub unsafe fn raw_expression_tree_walker(
475 node: *mut crate::Node,
476 walker: Option<unsafe extern "C-unwind" fn(*mut crate::Node, *mut ::core::ffi::c_void) -> bool>,
477 context: *mut ::core::ffi::c_void,
478) -> bool {
479 crate::raw_expression_tree_walker_impl(node, walker, context)
480}
481
482#[inline(always)]
483pub unsafe fn MemoryContextSwitchTo(context: crate::MemoryContext) -> crate::MemoryContext {
484 let old = crate::CurrentMemoryContext;
485
486 crate::CurrentMemoryContext = context;
487 old
488}
489
490#[allow(non_snake_case)]
491#[inline(always)]
492#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
493pub unsafe fn BufferGetPageSize(buffer: pg_sys::Buffer) -> pg_sys::Size {
494 assert!(BufferIsValid(buffer));
500 pg_sys::BLCKSZ as pg_sys::Size
501}
502
503#[allow(non_snake_case)]
504#[inline(always)]
505#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
506pub unsafe fn ItemIdGetOffset(item_id: pg_sys::ItemId) -> u32 {
507 (*item_id).lp_off()
510}
511
512#[allow(non_snake_case)]
513#[inline(always)]
514#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
515pub unsafe fn PageIsValid(page: pg_sys::Page) -> bool {
516 !page.is_null()
518}
519
520#[allow(non_snake_case)]
521#[inline(always)]
522#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
523pub unsafe fn PageIsEmpty(page: pg_sys::Page) -> bool {
524 const SizeOfPageHeaderData: pg_sys::Size =
527 core::mem::offset_of!(pg_sys::PageHeaderData, pd_linp);
528 let page_header = page as *mut pg_sys::PageHeaderData;
529 (*page_header).pd_lower <= SizeOfPageHeaderData as u16
530}
531
532#[allow(non_snake_case)]
533#[inline(always)]
534#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
535pub unsafe fn PageIsNew(page: pg_sys::Page) -> bool {
536 let page_header = page as *mut pg_sys::PageHeaderData;
538 (*page_header).pd_upper == 0
539}
540
541#[allow(non_snake_case)]
542#[inline(always)]
543#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
544pub unsafe fn PageGetItemId(page: pg_sys::Page, offset: pg_sys::OffsetNumber) -> pg_sys::ItemId {
545 let page_header = page as *mut pg_sys::PageHeaderData;
548 (*page_header).pd_linp.as_mut_ptr().add(offset as usize - 1)
549}
550
551#[allow(non_snake_case)]
552#[inline(always)]
553#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
554pub unsafe fn PageGetContents(page: pg_sys::Page) -> *mut ::core::ffi::c_char {
555 const SizeOfPageHeaderData: pg_sys::Size =
558 core::mem::offset_of!(pg_sys::PageHeaderData, pd_linp);
559 page.add(pg_sys::MAXALIGN(SizeOfPageHeaderData) as usize) as *mut ::core::ffi::c_char
560}
561
562#[allow(non_snake_case)]
563#[inline(always)]
564#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
565pub fn PageSizeIsValid(page_size: usize) -> bool {
566 page_size == pg_sys::BLCKSZ as usize
568}
569
570#[allow(non_snake_case)]
571#[inline(always)]
572#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
573pub unsafe fn PageGetPageSize(page: pg_sys::Page) -> usize {
574 let page_header = page as *mut pg_sys::PageHeaderData;
577 ((*page_header).pd_pagesize_version & 0xFF00) as usize
578}
579
580#[allow(non_snake_case)]
581#[inline(always)]
582#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
583pub unsafe fn PageGetPageLayoutVersion(page: pg_sys::Page) -> ::core::ffi::c_char {
584 let page_header = page as *mut pg_sys::PageHeaderData;
587 ((*page_header).pd_pagesize_version & 0x00FF) as ::core::ffi::c_char
588}
589
590#[allow(non_snake_case)]
591#[inline(always)]
592#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
593pub unsafe fn PageSetPageSizeAndVersion(page: pg_sys::Page, size: u16, version: u8) {
594 let page_header = page as *mut pg_sys::PageHeaderData;
597 (*page_header).pd_pagesize_version = size | (version as u16);
598}
599
600#[allow(non_snake_case)]
601#[inline(always)]
602#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
603pub unsafe fn PageGetSpecialSize(page: pg_sys::Page) -> u16 {
604 let page_header = page as *mut pg_sys::PageHeaderData;
607 PageGetPageSize(page) as u16 - (*page_header).pd_special
608}
609
610#[allow(non_snake_case)]
611#[inline(always)]
612#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
613pub unsafe fn PageGetSpecialPointer(page: pg_sys::Page) -> *mut ::core::ffi::c_char {
614 let page_header = page as *mut pg_sys::PageHeaderData;
617 page.add((*page_header).pd_special as usize) as *mut ::core::ffi::c_char
618}
619
620#[allow(non_snake_case)]
621#[inline(always)]
622#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
623pub unsafe fn PageGetItem(page: pg_sys::Page, item_id: pg_sys::ItemId) -> *mut ::core::ffi::c_char {
624 page.add(ItemIdGetOffset(item_id) as usize)
627}
628
629#[allow(non_snake_case)]
630#[inline(always)]
631#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
632pub unsafe fn PageGetMaxOffsetNumber(page: pg_sys::Page) -> pg_sys::OffsetNumber {
633 const SizeOfPageHeaderData: pg_sys::Size =
637 core::mem::offset_of!(pg_sys::PageHeaderData, pd_linp);
638 let page_header = page as *mut pg_sys::PageHeaderData;
639 if (*page_header).pd_lower <= SizeOfPageHeaderData as u16 {
640 0
641 } else {
642 ((*page_header).pd_lower - SizeOfPageHeaderData as u16)
643 / std::mem::size_of::<pg_sys::ItemIdData>() as u16
644 }
645}
646
647#[allow(non_snake_case)]
648#[inline(always)]
649#[cfg(any(feature = "pg13", feature = "pg14", feature = "pg15"))]
650pub unsafe fn BufferIsValid(buffer: pg_sys::Buffer) -> bool {
651 assert!(buffer <= pg_sys::NBuffers);
660 assert!(buffer >= -pg_sys::NLocBuffer);
661 buffer != pg_sys::InvalidBuffer as pg_sys::Buffer
662}