Skip to content

Commit

Permalink
Include type when getting argument (#740)
Browse files Browse the repository at this point in the history
* Include type when getting argument

* Test that oid of AnyElement is correct
* Only get argument type when needed
* Use separate trait function when OID needed
* from_datum_with_typid -> from_polymorphic_datum

Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com>
  • Loading branch information
syvb and workingjubilee authored Oct 7, 2022
1 parent 6f80b69 commit c9a23a1
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 4 deletions.
13 changes: 13 additions & 0 deletions pgx-tests/src/tests/pg_extern_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,17 @@ mod tests {
.expect("failed to get SPI result");
assert_eq!(create_result, 42);
}

#[pg_extern]
fn anyele_type(x: pgx::AnyElement) -> i32 {
x.oid() as i32
}

#[pg_test]
fn test_anyele_type() {
let interval_type =
Spi::get_one::<i32>(r#"SELECT tests."anyele_type"('5 hours'::interval)"#)
.expect("failed to get SPI result");
assert_eq!(interval_type as u32, pg_sys::INTERVALOID);
}
}
11 changes: 11 additions & 0 deletions pgx/src/datum/anyarray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,22 @@ impl AnyArray {
}

impl FromDatum for AnyArray {
const GET_TYPOID: bool = true;

#[inline]
unsafe fn from_datum(
datum: pg_sys::Datum,
is_null: bool,
typoid: pg_sys::Oid,
) -> Option<AnyArray> {
FromDatum::from_polymorphic_datum(datum, is_null, typoid)
}

#[inline]
unsafe fn from_polymorphic_datum(
datum: pg_sys::Datum,
is_null: bool,
typoid: pg_sys::Oid,
) -> Option<AnyArray> {
if is_null {
None
Expand Down
11 changes: 11 additions & 0 deletions pgx/src/datum/anyelement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,22 @@ impl AnyElement {
}

impl FromDatum for AnyElement {
const GET_TYPOID: bool = true;

#[inline]
unsafe fn from_datum(
datum: pg_sys::Datum,
is_null: bool,
typoid: pg_sys::Oid,
) -> Option<AnyElement> {
FromDatum::from_polymorphic_datum(datum, is_null, typoid)
}

#[inline]
unsafe fn from_polymorphic_datum(
datum: pg_sys::Datum,
is_null: bool,
typoid: pg_sys::Oid,
) -> Option<AnyElement> {
if is_null {
None
Expand Down
20 changes: 20 additions & 0 deletions pgx/src/datum/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ pub enum TryFromDatumError {
/// If implementing this, also implement `IntoDatum` for the reverse
/// conversion.
pub trait FromDatum {
/// Should a type OID be fetched when calling `from_datum`?
const GET_TYPOID: bool = false;

/// ## Safety
///
/// This method is inherently unsafe as the `datum` argument can represent an arbitrary
Expand All @@ -54,6 +57,23 @@ pub trait FromDatum {
where
Self: Sized;

/// Like `from_datum` for instantiating polymorphic types
/// which require preserving the dynamic type metadata.
///
/// ## Safety
///
/// Same caveats as `FromDatum::from_datum(...)`.
unsafe fn from_polymorphic_datum(
datum: pg_sys::Datum,
is_null: bool,
typoid: pg_sys::Oid,
) -> Option<Self>
where
Self: Sized,
{
FromDatum::from_datum(datum, is_null, typoid)
}

/// Default implementation switched to the specified memory context and then simply calls
/// `FromDatum::from_datum(...)` from within that context.
///
Expand Down
18 changes: 14 additions & 4 deletions pgx/src/fcinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,11 @@ mod pg_10_11 {
let datum = unsafe { fcinfo.as_ref() }.unwrap().arg[num];
let isnull = pg_arg_is_null(fcinfo, num);
unsafe {
let typid = pg_sys::InvalidOid;
T::from_datum(datum, isnull, typid)
if T::GET_TYPOID {
T::from_polymorphic_datum(datum, isnull, super::pg_getarg_type(fcinfo, num))
} else {
T::from_datum(datum, isnull, pg_sys::InvalidOid)
}
}
}

Expand Down Expand Up @@ -134,8 +137,15 @@ mod pg_12_13_14 {
pub fn pg_getarg<T: FromDatum>(fcinfo: pg_sys::FunctionCallInfo, num: usize) -> Option<T> {
let datum = get_nullable_datum(fcinfo, num);
unsafe {
let typid = pg_sys::InvalidOid;
T::from_datum(datum.value, datum.isnull, typid)
if T::GET_TYPOID {
T::from_polymorphic_datum(
datum.value,
datum.isnull,
super::pg_getarg_type(fcinfo, num),
)
} else {
T::from_datum(datum.value, datum.isnull, pg_sys::InvalidOid)
}
}
}

Expand Down

0 comments on commit c9a23a1

Please sign in to comment.