diff --git a/README.md b/README.md index 4d00ca994e..10808a6096 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,9 @@ those remain untested. So far, some of PGRX's build tooling works on Windows, bu ‡ A local PostgreSQL server installation is not required. `cargo pgrx` can download and compile PostgreSQL versions on its own. - ⹋ PGRX has not been tested to work on 32-bit: the library assumes an 8-byte `pg_sys::Datum` -which may result in unexpected behavior on 32-bit, like dropping 4 bytes of data from `int8` -and `double`. This may not be "unsound" in itself, as it is "merely" illogical, -but it may undermine otherwise-reasonable safety assumptions of PGRX extensions. -We do not plan to add support without considerable ongoing technical and financial contributions. + ⹋ PGRX has not been tested to work on 32-bit, but the library attempts to handle conversion of `pg_sys::Datum` +to and from `int8` and `double` types. Use it only for your own risk. We do not plan to add offical support +without considerable ongoing technical and financial contributions.
How to: Homebrew on macOS diff --git a/pgrx-pg-sys/src/submodules/datum.rs b/pgrx-pg-sys/src/submodules/datum.rs index 41326f1cf5..9865ef5df2 100644 --- a/pgrx-pg-sys/src/submodules/datum.rs +++ b/pgrx-pg-sys/src/submodules/datum.rs @@ -129,7 +129,15 @@ impl From for Datum { impl From for Datum { #[inline] fn from(val: u64) -> Datum { - Datum::from(val as usize) + if cfg!(target_pointer_width = "64") { + Datum::from(val as usize) + } else { + unsafe { + let ptr = crate::palloc(size_of::()) as *mut u64; + *ptr = val; + Datum::from(ptr) + } + } } } @@ -157,7 +165,15 @@ impl From for Datum { impl From for Datum { #[inline] fn from(val: i64) -> Datum { - Datum::from(val as usize) + if cfg!(target_pointer_width = "64") { + Datum::from(val as usize) + } else { + unsafe { + let ptr = crate::palloc(size_of::()) as *mut i64; + *ptr = val; + Datum::from(ptr) + } + } } } @@ -223,41 +239,28 @@ mod test { #[test] fn roundtrip_integers() { - #[cfg(target_pointer_width = "64")] - mod types { - pub type UnsignedInt = u64; - pub type SignedInt = i64; - } - #[cfg(target_pointer_width = "32")] - mod types { - // 64-bit integers would be truncated on 32 bit platforms - pub type UnsignedInt = u32; - pub type SignedInt = i32; - } - use types::*; - - let val: SignedInt = 123456; + let val = i64::MAX; let datum = Datum::from(val); - assert_eq!(datum.value() as SignedInt, val); + assert_eq!(datum.value() as i64, val); - let val: isize = 123456; + let val = isize::MAX; let datum = Datum::from(val); assert_eq!(datum.value() as isize, val); - let val: SignedInt = -123456; + let val = i64::MIN; let datum = Datum::from(val); - assert_eq!(datum.value() as SignedInt, val); + assert_eq!(datum.value() as i64, val); - let val: isize = -123456; + let val = isize::MIN; let datum = Datum::from(val); assert_eq!(datum.value() as isize, val); - let val: UnsignedInt = 123456; + let val = u64::MAX; let datum = Datum::from(val); - assert_eq!(datum.value() as UnsignedInt, val); + assert_eq!(datum.value() as u64, val); - let val: usize = 123456; + let val = usize::MAX; let datum = Datum::from(val); - assert_eq!({ datum.value() }, val); + assert_eq!(datum.value(), val); } } diff --git a/pgrx/src/datum/from.rs b/pgrx/src/datum/from.rs index ff2b52940e..0194430681 100644 --- a/pgrx/src/datum/from.rs +++ b/pgrx/src/datum/from.rs @@ -12,7 +12,7 @@ use crate::{ pg_sys, varlena, varlena_to_byte_slice, AllocatedByPostgres, IntoDatum, PgBox, PgMemoryContexts, }; -use core::ffi::CStr; +use core::{ffi::CStr, mem::size_of}; use std::num::NonZeroUsize; /// If converting a Datum to a Rust type fails, this is the set of possible reasons why. @@ -283,7 +283,12 @@ impl FromDatum for i64 { if is_null { None } else { - Some(datum.value() as _) + let value = if size_of::() <= size_of::() { + datum.value() as _ + } else { + *(datum.cast_mut_ptr() as *const _) + }; + Some(value) } } } @@ -315,7 +320,12 @@ impl FromDatum for f64 { if is_null { None } else { - Some(f64::from_bits(datum.value() as _)) + let value = if size_of::() <= size_of::() { + f64::from_bits(datum.value() as _) + } else { + *(datum.cast_mut_ptr() as *const _) + }; + Some(value) } } }