Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions pgrx-bindgen/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::process::{Command, Output};
use std::rc::Rc;
use syn::{Item, ItemConst};

const BLOCKLISTED_TYPES: [&str; 3] = ["Datum", "NullableDatum", "Oid"];
const BLOCKLISTED_TYPES: [&str; 4] = ["Datum", "NullableDatum", "Oid", "TransactionId"];

// These postgres versions were effectively "yanked" by the community, even tho they still exist
// in the wild. pgrx will refuse to compile against them
Expand Down Expand Up @@ -348,7 +348,7 @@ fn generate_bindings(
&bindings_file,
quote! {
use crate as pg_sys;
use crate::{Datum, Oid, PgNode};
use crate::{Datum, MultiXactId, Oid, PgNode, TransactionId};
},
is_for_release,
)
Expand Down Expand Up @@ -864,6 +864,8 @@ pub const {module}_{variant}: {ty} = {value};"#,
fn add_blocklists(bind: bindgen::Builder) -> bindgen::Builder {
bind.blocklist_type("Datum") // manually wrapping datum for correctness
.blocklist_type("Oid") // "Oid" is not just any u32
.blocklist_type("TransactionId") // "TransactionId" is not just any u32
.blocklist_type("MultiXactId") // it's an alias of "TransactionId"
.blocklist_var("CONFIGURE_ARGS") // configuration during build is hopefully irrelevant
.blocklist_var("_*(?:HAVE|have)_.*") // header tracking metadata
.blocklist_var("_[A-Z_]+_H") // more header metadata
Expand Down
10 changes: 5 additions & 5 deletions pgrx-pg-sys/src/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ pub const MaxOffsetNumber: super::OffsetNumber =
(super::BLCKSZ as usize / std::mem::size_of::<super::ItemIdData>()) as super::OffsetNumber;
pub const InvalidBlockNumber: u32 = 0xFFFF_FFFF as crate::BlockNumber;
pub const VARHDRSZ: usize = std::mem::size_of::<super::int32>();
pub const InvalidTransactionId: super::TransactionId = 0 as super::TransactionId;
pub const InvalidCommandId: super::CommandId = (!(0 as super::CommandId)) as super::CommandId;
pub const FirstCommandId: super::CommandId = 0 as super::CommandId;
pub const BootstrapTransactionId: super::TransactionId = 1 as super::TransactionId;
pub const FrozenTransactionId: super::TransactionId = 2 as super::TransactionId;
pub const FirstNormalTransactionId: super::TransactionId = 3 as super::TransactionId;
pub const MaxTransactionId: super::TransactionId = 0xFFFF_FFFF as super::TransactionId;
pub const InvalidTransactionId: crate::TransactionId = crate::TransactionId::INVALID;
pub const BootstrapTransactionId: crate::TransactionId = crate::TransactionId::BOOTSTRAP;
pub const FrozenTransactionId: crate::TransactionId = crate::TransactionId::FROZEN;
pub const FirstNormalTransactionId: crate::TransactionId = crate::TransactionId::FIRST_NORMAL;
pub const MaxTransactionId: crate::TransactionId = crate::TransactionId::MAX;

/// Given a valid HeapTuple pointer, return address of the user data
///
Expand Down
2 changes: 2 additions & 0 deletions pgrx-pg-sys/src/submodules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//LICENSE
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
pub mod datum;
pub mod transaction_id;
#[macro_use]
pub mod elog;
pub mod cmp;
Expand All @@ -27,6 +28,7 @@ pub mod utils;
mod sql_translatable;

pub use datum::Datum;
pub use transaction_id::{MultiXactId, TransactionId};

pub use htup::*;
pub use oids::*;
Expand Down
85 changes: 85 additions & 0 deletions pgrx-pg-sys/src/submodules/transaction_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//LICENSE Portions Copyright 2019-2021 ZomboDB, LLC.
//LICENSE
//LICENSE Portions Copyright 2021-2023 Technology Concepts & Design, Inc.
//LICENSE
//LICENSE Portions Copyright 2023-2023 PgCentral Foundation, Inc. <[email protected]>
//LICENSE
//LICENSE All rights reserved.
//LICENSE
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
use pgrx_sql_entity_graph::metadata::{
ArgumentError, Returns, ReturnsError, SqlMapping, SqlTranslatable,
};
use std::fmt::{self, Debug, Display, Formatter};

pub type MultiXactId = TransactionId;

/// An `xid` type from PostgreSQL
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(serde::Deserialize, serde::Serialize)]
pub struct TransactionId(u32);

impl TransactionId {
pub const INVALID: Self = Self(0);
pub const BOOTSTRAP: Self = Self(1);
pub const FROZEN: Self = Self(2);
pub const FIRST_NORMAL: Self = Self(3);
pub const MAX: Self = Self(u32::MAX);

pub const fn from_inner(xid: u32) -> Self {
Self(xid)
}

pub const fn into_inner(self) -> u32 {
self.0
}
}

impl Default for TransactionId {
fn default() -> Self {
Self::INVALID
}
}

impl From<u32> for TransactionId {
#[inline]
fn from(xid: u32) -> Self {
Self::from_inner(xid)
}
}

impl From<TransactionId> for u32 {
#[inline]
fn from(xid: TransactionId) -> Self {
xid.into_inner()
}
}

impl From<TransactionId> for crate::Datum {
fn from(xid: TransactionId) -> Self {
xid.into_inner().into()
}
}

unsafe impl SqlTranslatable for TransactionId {
fn argument_sql() -> Result<SqlMapping, ArgumentError> {
Ok(SqlMapping::literal("xid"))
}

fn return_sql() -> Result<Returns, ReturnsError> {
Ok(Returns::One(SqlMapping::literal("xid")))
}
}

impl Debug for TransactionId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}

impl Display for TransactionId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
1 change: 1 addition & 0 deletions pgrx-tests/src/tests/roundtrip_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ mod tests {
roundtrip!(rt_point, test_rt_point, pg_sys::Point, pg_sys::Point { x: 1.0, y: 2.0 });
roundtrip!(rt_string, test_rt_string, String, String::from("string"));
roundtrip!(rt_oid, test_rt_oid, pg_sys::Oid, pg_sys::Oid::from(BuiltinOid::ANYOID));
roundtrip!(rt_xid, test_rt_xid, pg_sys::TransactionId, pg_sys::TransactionId::FIRST_NORMAL);
roundtrip!(rt_i16, test_rt_i16, i16, i16::MAX);
roundtrip!(rt_f64, test_rt_f64, f64, f64::MAX);
roundtrip!(
Expand Down
2 changes: 1 addition & 1 deletion pgrx-tests/src/tests/xid64_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod tests {

#[pg_test]
fn test_convert_xid_to_u64() {
let xid = xid_to_64bit(32768);
let xid = xid_to_64bit(32768.into());
assert_eq!(xid, 32768)
}
}
4 changes: 2 additions & 2 deletions pgrx/src/callconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ argue_from_datum! { 'fcx; i8, i16, i32, i64, f32, f64, bool, char, String, Vec<u
argue_from_datum! { 'fcx; Date, Interval, Time, TimeWithTimeZone, Timestamp, TimestampWithTimeZone }
argue_from_datum! { 'fcx; AnyArray, AnyElement, AnyNumeric }
argue_from_datum! { 'fcx; Inet, Internal, Json, JsonB, Uuid, PgRelation }
argue_from_datum! { 'fcx; pg_sys::BOX, pg_sys::ItemPointerData, pg_sys::Oid, pg_sys::Point }
argue_from_datum! { 'fcx; pg_sys::BOX, pg_sys::ItemPointerData, pg_sys::Oid, pg_sys::Point, pg_sys::TransactionId }
// We could use the upcoming impl of ArgAbi for `&'fcx T where T: ?Sized + BorrowDatum`
// to support these types by implementing BorrowDatum for them also, but we reject this.
// It would greatly complicate other users of BorrowDatum like FlatArray, which want all impls
Expand Down Expand Up @@ -566,7 +566,7 @@ impl_repackage_into_datum! {
String, CString, Vec<u8>, char,
Json, JsonB, Inet, Uuid, AnyNumeric, AnyArray, AnyElement, Internal,
Date, Interval, Time, TimeWithTimeZone, Timestamp, TimestampWithTimeZone,
pg_sys::BOX, pg_sys::ItemPointerData, pg_sys::Oid, pg_sys::Point
pg_sys::BOX, pg_sys::ItemPointerData, pg_sys::Oid, pg_sys::Point, pg_sys::TransactionId
}

unsafe impl<const P: u32, const S: u32> BoxRet for Numeric<P, S> {
Expand Down
15 changes: 15 additions & 0 deletions pgrx/src/datum/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,21 @@ impl FromDatum for pg_sys::Oid {
}
}

impl FromDatum for pg_sys::TransactionId {
#[inline]
unsafe fn from_polymorphic_datum(
datum: pg_sys::Datum,
is_null: bool,
_typoid: pg_sys::Oid,
) -> Option<Self> {
if is_null {
None
} else {
datum.value().try_into().ok().map(Self::from_inner)
}
}
}

/// for bool
impl FromDatum for bool {
#[inline]
Expand Down
16 changes: 16 additions & 0 deletions pgrx/src/datum/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,22 @@ impl IntoDatum for pg_sys::Oid {
}
}

impl IntoDatum for pg_sys::TransactionId {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
if self == Self::INVALID {
None
} else {
Some(self.into())
}
}

#[inline]
fn type_oid() -> pg_sys::Oid {
pg_sys::XIDOID
}
}

impl IntoDatum for PgOid {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Expand Down
12 changes: 8 additions & 4 deletions pgrx/src/xid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ pub fn xid_to_64bit(xid: pg_sys::TransactionId) -> u64 {
let last_xid = full_xid.value as u32;
let epoch = (full_xid.value >> 32) as u32;

convert_xid_common(xid, last_xid, epoch)
convert_xid_common(xid, last_xid.into(), epoch)
}

#[inline]
fn convert_xid_common(xid: pg_sys::TransactionId, last_xid: u32, epoch: u32) -> u64 {
fn convert_xid_common(
xid: pg_sys::TransactionId,
last_xid: pgrx_pg_sys::TransactionId,
epoch: u32,
) -> u64 {
/* return special xid's as-is */
if !pg_sys::TransactionIdIsNormal(xid) {
return xid as u64;
return xid.into_inner() as u64;
}

/* xid can be on either side when near wrap-around */
Expand All @@ -34,5 +38,5 @@ fn convert_xid_common(xid: pg_sys::TransactionId, last_xid: u32, epoch: u32) ->
epoch += 1;
}

(epoch << 32) | xid as u64
(epoch << 32) | xid.into_inner() as u64
}
Loading