pgx/
itemptr.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//! Helper functions for working with Postgres `ItemPointerData` (`tid`) type
11
12use crate::{pg_sys, AllocatedByRust, PgBox};
13
14/// ## Safety
15///
16/// This function s unsafe because it does not check that the specified ItemPointerData pointer
17/// might be null
18#[inline]
19pub unsafe fn item_pointer_get_block_number(
20    ctid: *const pg_sys::ItemPointerData,
21) -> pg_sys::BlockNumber {
22    assert!(item_pointer_is_valid(ctid));
23    item_pointer_get_block_number_no_check(*ctid)
24}
25
26/// ## Safety
27///
28/// This function s unsafe because it does not check that the specified ItemPointerData pointer
29/// might be null
30#[inline]
31pub unsafe fn item_pointer_get_offset_number(
32    ctid: *const pg_sys::ItemPointerData,
33) -> pg_sys::OffsetNumber {
34    assert!(item_pointer_is_valid(ctid));
35    item_pointer_get_offset_number_no_check(*ctid)
36}
37
38/// ## Safety
39///
40/// This function is unsafe because it does not check that the specified ItemPointerData pointer
41/// might be null
42#[inline]
43pub unsafe fn item_pointer_get_block_number_no_check(
44    ctid: pg_sys::ItemPointerData,
45) -> pg_sys::BlockNumber {
46    let block_id = ctid.ip_blkid;
47    (((block_id.bi_hi as u32) << 16) | (block_id.bi_lo as u32)) as pg_sys::BlockNumber
48}
49
50/// ## Safety
51///
52/// This function is unsafe because it does not check that the specified ItemPointerData pointer
53/// might be null
54#[inline]
55pub unsafe fn item_pointer_get_offset_number_no_check(
56    ctid: pg_sys::ItemPointerData,
57) -> pg_sys::OffsetNumber {
58    ctid.ip_posid
59}
60
61#[inline]
62pub fn item_pointer_get_both(
63    ctid: pg_sys::ItemPointerData,
64) -> (pg_sys::BlockNumber, pg_sys::OffsetNumber) {
65    unsafe {
66        (
67            item_pointer_get_block_number_no_check(ctid),
68            item_pointer_get_offset_number_no_check(ctid),
69        )
70    }
71}
72
73#[inline]
74pub fn item_pointer_set_all(
75    tid: &mut pg_sys::ItemPointerData,
76    blockno: pg_sys::BlockNumber,
77    offno: pg_sys::OffsetNumber,
78) {
79    tid.ip_posid = offno;
80    tid.ip_blkid.bi_hi = (blockno >> 16).try_into().unwrap();
81    tid.ip_blkid.bi_lo = (blockno & 0xffff).try_into().unwrap();
82}
83
84/// Convert an `ItemPointerData` struct into a `u64`
85#[inline]
86pub fn item_pointer_to_u64(ctid: pg_sys::ItemPointerData) -> u64 {
87    let (blockno, offno) = item_pointer_get_both(ctid);
88    let blockno = blockno as u64;
89    let offno = offno as u64;
90
91    (blockno << 32) | offno
92}
93
94/// Deconstruct a `u64` into an otherwise uninitialized `ItemPointerData` struct
95#[inline]
96pub fn u64_to_item_pointer(value: u64, tid: &mut pg_sys::ItemPointerData) {
97    let blockno = (value >> 32) as pg_sys::BlockNumber;
98    let offno = value as pg_sys::OffsetNumber;
99    item_pointer_set_all(tid, blockno, offno);
100}
101
102#[inline]
103pub fn u64_to_item_pointer_parts(value: u64) -> (pg_sys::BlockNumber, pg_sys::OffsetNumber) {
104    let blockno = (value >> 32) as pg_sys::BlockNumber;
105    let offno = value as pg_sys::OffsetNumber;
106    (blockno, offno)
107}
108
109#[allow(clippy::not_unsafe_ptr_arg_deref)] // this is okay b/c we guard against ctid being null
110#[inline]
111pub unsafe fn item_pointer_is_valid(ctid: *const pg_sys::ItemPointerData) -> bool {
112    if ctid.is_null() {
113        false
114    } else {
115        (*ctid).ip_posid != pg_sys::InvalidOffsetNumber
116    }
117}
118
119#[inline]
120pub fn new_item_pointer(
121    blockno: pg_sys::BlockNumber,
122    offno: pg_sys::OffsetNumber,
123) -> PgBox<pg_sys::ItemPointerData, AllocatedByRust> {
124    let mut tid = unsafe { PgBox::<pg_sys::ItemPointerData>::alloc() };
125    tid.ip_blkid.bi_hi = (blockno >> 16) as u16;
126    tid.ip_blkid.bi_lo = (blockno & 0xffff) as u16;
127    tid.ip_posid = offno;
128    tid
129}