Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
74 changes: 74 additions & 0 deletions pgrx-pg-sys/src/submodules/transaction_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//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,
};

pub type MultiXactId = TransactionId;

/// An `xid` type from PostgreSQL
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also want to impl Display too. Have it just be the u32 value. It's not uncommon to want to convert a transaction id into a string for logging purposes

#[derive(serde::Deserialize, serde::Serialize)]
pub struct TransactionId(u32);

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

#[inline]
pub const fn from_u32(xid: u32) -> Self {
Self(xid)
}

#[inline]
pub const fn to_u32(self) -> u32 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really fine? I would like to avoid any further name bikeshading as it's a little disaster even if another method added and this marked as deprecated. Shouldn't it be into_u32?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

honestly, we should call this into_inner(self) and then do the same over on pg_sys::Oid and close #2011.

And there's also no need for this from_u32(xid: u32) function either, because of impl From<u32> for TransactionId down below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from_u32 is for const only since traits cannot have that modifier on the functions. It can be removed, but then it won't be possible to use during compiler time.

If there's no need in const fns then I see no reason in from_smthg and into_smthg at all as there are from and into. Makes sense?

self.0
}
}

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

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

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

impl From<TransactionId> for crate::Datum {
fn from(xid: TransactionId) -> Self {
xid.to_u32().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")))
}
}
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_u32)
}
}
}

/// 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.to_u32() 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.to_u32() as u64
}
Loading