Skip to content

Commit e4fd443

Browse files
Missing ArgAbi and BoxRet trait implementations for datums (#1757)
After updating to version `0.12.0-beta.0` I can no longer use `JsonB` as a `pg_extern` function argument, and I can no longer use `JsonB`, `AnyArray`, or `AnyElement` as state type in `pg_aggregate`. Unfortunately, pgrx lacked any tests for these types, so they were not checked for compilation when adding ArgAbi and RetAbi.
1 parent b8392e7 commit e4fd443

File tree

6 files changed

+230
-3
lines changed

6 files changed

+230
-3
lines changed

pgrx-tests/src/tests/aggregate_tests.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,74 @@ impl Aggregate for DemoCustomState {
143143
}
144144
}
145145

146+
struct FirstJson;
147+
148+
#[pg_aggregate]
149+
impl Aggregate for FirstJson {
150+
type State = pgrx::Json;
151+
type Args = pgrx::name!(value, pgrx::Json);
152+
153+
#[pgrx(parallel_safe, immutable, strict)]
154+
fn state(
155+
current: Self::State,
156+
_arg: Self::Args,
157+
_fcinfo: pg_sys::FunctionCallInfo,
158+
) -> Self::State {
159+
current
160+
}
161+
}
162+
163+
struct FirstJsonB;
164+
165+
#[pg_aggregate]
166+
impl Aggregate for FirstJsonB {
167+
type State = pgrx::JsonB;
168+
type Args = pgrx::name!(value, pgrx::JsonB);
169+
170+
#[pgrx(parallel_safe, immutable, strict)]
171+
fn state(
172+
current: Self::State,
173+
_arg: Self::Args,
174+
_fcinfo: pg_sys::FunctionCallInfo,
175+
) -> Self::State {
176+
current
177+
}
178+
}
179+
180+
struct FirstAnyArray;
181+
182+
#[pg_aggregate]
183+
impl Aggregate for FirstAnyArray {
184+
type State = pgrx::AnyArray;
185+
type Args = pgrx::name!(value, pgrx::AnyArray);
186+
187+
#[pgrx(parallel_safe, immutable, strict)]
188+
fn state(
189+
current: Self::State,
190+
_arg: Self::Args,
191+
_fcinfo: pg_sys::FunctionCallInfo,
192+
) -> Self::State {
193+
current
194+
}
195+
}
196+
197+
struct FirstAnyElement;
198+
199+
#[pg_aggregate]
200+
impl Aggregate for FirstAnyElement {
201+
type State = pgrx::AnyElement;
202+
type Args = pgrx::name!(value, pgrx::AnyElement);
203+
204+
#[pgrx(parallel_safe, immutable, strict)]
205+
fn state(
206+
current: Self::State,
207+
_arg: Self::Args,
208+
_fcinfo: pg_sys::FunctionCallInfo,
209+
) -> Self::State {
210+
current
211+
}
212+
}
213+
146214
#[cfg(any(test, feature = "pg_test"))]
147215
#[pgrx::pg_schema]
148216
mod tests {
@@ -190,4 +258,60 @@ mod tests {
190258
);
191259
assert_eq!(retval, Ok(Some(4)));
192260
}
261+
262+
#[pg_test]
263+
fn aggregate_first_json() -> Result<(), pgrx::spi::Error> {
264+
let retval = Spi::get_one_with_args::<pgrx::Json>(
265+
"SELECT FirstJson(value) FROM UNNEST(ARRAY [$1, $2]) as value;",
266+
vec![
267+
(
268+
PgBuiltInOids::JSONOID.oid(),
269+
pgrx::Json(serde_json::json!({ "foo": "one" })).into_datum(),
270+
),
271+
(
272+
PgBuiltInOids::JSONOID.oid(),
273+
pgrx::Json(serde_json::json!({ "foo": "two" })).into_datum(),
274+
),
275+
],
276+
)?
277+
.map(|json| json.0);
278+
279+
assert_eq!(retval, Some(serde_json::json!({ "foo": "one" })));
280+
281+
Ok(())
282+
}
283+
284+
#[pg_test]
285+
fn aggregate_first_jsonb() -> Result<(), pgrx::spi::Error> {
286+
let retval = Spi::get_one_with_args::<pgrx::JsonB>(
287+
"SELECT FirstJsonB(value) FROM UNNEST(ARRAY [$1, $2]) as value;",
288+
vec![
289+
(
290+
PgBuiltInOids::JSONBOID.oid(),
291+
pgrx::JsonB(serde_json::json!({ "foo": "one" })).into_datum(),
292+
),
293+
(
294+
PgBuiltInOids::JSONBOID.oid(),
295+
pgrx::JsonB(serde_json::json!({ "foo": "two" })).into_datum(),
296+
),
297+
],
298+
)?
299+
.map(|json| json.0);
300+
301+
assert_eq!(retval, Some(serde_json::json!({ "foo": "one" })));
302+
303+
Ok(())
304+
}
305+
306+
#[pg_test]
307+
fn aggregate_first_anyelement() -> Result<(), pgrx::spi::Error> {
308+
let retval = Spi::get_one::<pgrx::AnyElement>(
309+
"SELECT FirstAnyElement(value) FROM UNNEST(ARRAY [1, 2]) as value;",
310+
)?
311+
.map(|element| element.into_datum());
312+
313+
assert_eq!(retval, Some(1.into_datum()));
314+
315+
Ok(())
316+
}
193317
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use pgrx::{prelude::*, AnyElement};
2+
3+
#[pg_extern]
4+
fn anyelement_arg(element: AnyElement) -> AnyElement {
5+
element
6+
}
7+
8+
#[cfg(any(test, feature = "pg_test"))]
9+
#[pgrx::pg_schema]
10+
mod tests {
11+
#[allow(unused_imports)]
12+
use crate as pgrx_tests;
13+
14+
use pgrx::{prelude::*, AnyElement};
15+
16+
#[pg_test]
17+
fn test_anyelement_arg() -> Result<(), pgrx::spi::Error> {
18+
let element = Spi::get_one_with_args::<AnyElement>(
19+
"SELECT anyelement_arg($1);",
20+
vec![(PgBuiltInOids::ANYELEMENTOID.oid(), 123.into_datum())],
21+
)?
22+
.map(|e| e.datum());
23+
24+
assert_eq!(element, 123.into_datum());
25+
26+
Ok(())
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use pgrx::{prelude::*, AnyNumeric};
2+
3+
#[pg_extern]
4+
fn anynumeric_arg(numeric: AnyNumeric) -> AnyNumeric {
5+
numeric
6+
}
7+
8+
#[cfg(any(test, feature = "pg_test"))]
9+
#[pgrx::pg_schema]
10+
mod tests {
11+
#[allow(unused_imports)]
12+
use crate as pgrx_tests;
13+
14+
use pgrx::{prelude::*, AnyNumeric};
15+
16+
#[pg_test]
17+
fn test_anynumeric_arg() -> Result<(), pgrx::spi::Error> {
18+
let numeric = Spi::get_one_with_args::<AnyNumeric>(
19+
"SELECT anynumeric_arg($1);",
20+
vec![(PgBuiltInOids::INT4OID.oid(), 123.into_datum())],
21+
)?
22+
.map(|n| n.normalize().to_string());
23+
24+
assert_eq!(numeric, Some("123".to_string()));
25+
26+
Ok(())
27+
}
28+
}

pgrx-tests/src/tests/json_tests.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@
77
//LICENSE All rights reserved.
88
//LICENSE
99
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
10+
use pgrx::prelude::*;
11+
use pgrx::{Json, JsonB};
12+
13+
#[pg_extern]
14+
fn json_arg(json: Json) -> Json {
15+
json
16+
}
17+
18+
#[pg_extern]
19+
fn jsonb_arg(json: JsonB) -> JsonB {
20+
json
21+
}
22+
1023
#[cfg(any(test, feature = "pg_test"))]
1124
#[pgrx::pg_schema]
1225
mod tests {
@@ -61,4 +74,36 @@ mod tests {
6174
assert_eq!(user.last_name, "McBlahFace");
6275
Ok(())
6376
}
77+
78+
#[pg_test]
79+
fn test_json_arg() -> Result<(), pgrx::spi::Error> {
80+
let json = Spi::get_one_with_args::<Json>(
81+
"SELECT json_arg($1);",
82+
vec![(
83+
PgBuiltInOids::JSONOID.oid(),
84+
Json(serde_json::json!({ "foo": "bar" })).into_datum(),
85+
)],
86+
)?
87+
.expect("json was null");
88+
89+
assert_eq!(json.0, serde_json::json!({ "foo": "bar" }));
90+
91+
Ok(())
92+
}
93+
94+
#[pg_test]
95+
fn test_jsonb_arg() -> Result<(), pgrx::spi::Error> {
96+
let json = Spi::get_one_with_args::<JsonB>(
97+
"SELECT jsonb_arg($1);",
98+
vec![(
99+
PgBuiltInOids::JSONBOID.oid(),
100+
JsonB(serde_json::json!({ "foo": "bar" })).into_datum(),
101+
)],
102+
)?
103+
.expect("json was null");
104+
105+
assert_eq!(json.0, serde_json::json!({ "foo": "bar" }));
106+
107+
Ok(())
108+
}
64109
}

pgrx-tests/src/tests/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
1010
mod aggregate_tests;
1111
mod anyarray_tests;
12+
mod anyelement_tests;
13+
mod anynumeric_tests;
1214
mod array_tests;
1315
mod attributes_tests;
1416
mod bgworker_tests;

pgrx/src/callconv.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::heap_tuple::PgHeapTuple;
1616
use crate::nullable::Nullable;
1717
use crate::{
1818
pg_return_null, pg_sys, AnyArray, AnyElement, AnyNumeric, Date, FromDatum, Inet, Internal,
19-
Interval, IntoDatum, Json, PgBox, PgMemoryContexts, PgVarlena, Time, TimeWithTimeZone,
19+
Interval, IntoDatum, Json, JsonB, PgBox, PgMemoryContexts, PgVarlena, Time, TimeWithTimeZone,
2020
Timestamp, TimestampWithTimeZone, UnboxDatum, Uuid,
2121
};
2222
use core::marker::PhantomData;
@@ -258,7 +258,7 @@ macro_rules! argue_from_datum {
258258
argue_from_datum! { 'fcx; i8, i16, i32, i64, f32, f64, bool, char, String, Vec<u8> }
259259
argue_from_datum! { 'fcx; Date, Interval, Time, TimeWithTimeZone, Timestamp, TimestampWithTimeZone }
260260
argue_from_datum! { 'fcx; AnyArray, AnyElement, AnyNumeric }
261-
argue_from_datum! { 'fcx; Inet, Internal, Json, Uuid }
261+
argue_from_datum! { 'fcx; Inet, Internal, Json, JsonB, Uuid }
262262
argue_from_datum! { 'fcx; pg_sys::Oid, pg_sys::Point, pg_sys::BOX }
263263
argue_from_datum! { 'fcx; &'fcx str, &'fcx CStr, &'fcx [u8] }
264264

@@ -505,7 +505,7 @@ macro_rules! impl_repackage_into_datum {
505505

506506
impl_repackage_into_datum! {
507507
String, CString, Vec<u8>, char,
508-
Json, Inet, Uuid, AnyNumeric, Internal,
508+
Json, JsonB, Inet, Uuid, AnyNumeric, AnyArray, AnyElement, Internal,
509509
Date, Interval, Time, TimeWithTimeZone, Timestamp, TimestampWithTimeZone,
510510
pg_sys::Oid, pg_sys::BOX, pg_sys::Point
511511
}

0 commit comments

Comments
 (0)