@@ -9,6 +9,8 @@ use crate::{
99 FromDatum , IntoDatum , PgBox , PgMemoryContexts , PgTupleDesc , TriggerTuple , TryFromDatumError ,
1010 WhoAllocated ,
1111} ;
12+ use pgrx_pg_sys:: errcodes:: PgSqlErrorCode ;
13+ use pgrx_pg_sys:: PgTryBuilder ;
1214use pgrx_sql_entity_graph:: metadata:: {
1315 ArgumentError , Returns , ReturnsError , SqlMapping , SqlTranslatable ,
1416} ;
@@ -22,6 +24,12 @@ pub enum PgHeapTupleError {
2224
2325 #[ error( "The specified composite type, {0}, does not exist" ) ]
2426 NoSuchType ( String ) ,
27+
28+ #[ error( "The specified composite type, {0}, does not exist" ) ]
29+ NoSuchTypeOid ( pg_sys:: Oid ) ,
30+
31+ #[ error( "Oid `{0}` is not a composite type" ) ]
32+ NotACompositeType ( pg_sys:: Oid ) ,
2533}
2634
2735/// A [`PgHeapTuple`] is a lightweight wrapper around Postgres' [`pg_sys::HeapTuple`] object and a [`PgTupleDesc`].
@@ -199,28 +207,52 @@ impl<'a> PgHeapTuple<'a, AllocatedByRust> {
199207 ) -> Result < PgHeapTuple < ' a , AllocatedByRust > , PgHeapTupleError > {
200208 let tuple_desc = PgTupleDesc :: for_composite_type ( type_name)
201209 . ok_or_else ( || PgHeapTupleError :: NoSuchType ( type_name. to_string ( ) ) ) ?;
202- let natts = tuple_desc. len ( ) ;
203- unsafe {
204- let datums =
205- pg_sys:: palloc0 ( natts * std:: mem:: size_of :: < pg_sys:: Datum > ( ) ) as * mut pg_sys:: Datum ;
206- let mut is_null = ( 0 ..natts) . map ( |_| true ) . collect :: < Vec < _ > > ( ) ;
207210
208- let heap_tuple =
209- pg_sys :: heap_form_tuple ( tuple_desc . as_ptr ( ) , datums , is_null . as_mut_ptr ( ) ) ;
211+ Self :: new_composite_type_by_oid ( tuple_desc . oid ( ) )
212+ }
210213
211- Ok ( PgHeapTuple {
212- tuple : PgBox :: < pg_sys:: HeapTupleData , AllocatedByRust > :: from_rust ( heap_tuple) ,
213- tupdesc : tuple_desc,
214- } )
215- }
214+ pub fn new_composite_type_by_oid (
215+ typoid : pg_sys:: Oid ,
216+ ) -> Result < PgHeapTuple < ' a , AllocatedByRust > , PgHeapTupleError > {
217+ PgTryBuilder :: new ( || {
218+ let tuple_desc = PgTupleDesc :: for_composite_type_by_oid ( typoid)
219+ . ok_or_else ( || PgHeapTupleError :: NotACompositeType ( typoid) ) ?;
220+ let natts = tuple_desc. len ( ) ;
221+
222+ unsafe {
223+ let datums = pg_sys:: palloc0 ( natts * std:: mem:: size_of :: < pg_sys:: Datum > ( ) )
224+ as * mut pg_sys:: Datum ;
225+ let mut is_null = vec ! [ true ; natts] ;
226+
227+ let heap_tuple =
228+ pg_sys:: heap_form_tuple ( tuple_desc. as_ptr ( ) , datums, is_null. as_mut_ptr ( ) ) ;
229+
230+ Ok ( PgHeapTuple {
231+ tuple : PgBox :: < pg_sys:: HeapTupleData , AllocatedByRust > :: from_rust ( heap_tuple) ,
232+ tupdesc : tuple_desc,
233+ } )
234+ }
235+ } )
236+ . catch_when ( PgSqlErrorCode :: ERRCODE_WRONG_OBJECT_TYPE , |_| {
237+ Err ( PgHeapTupleError :: NotACompositeType ( typoid) )
238+ } )
239+ . catch_when ( PgSqlErrorCode :: ERRCODE_UNDEFINED_OBJECT , |_| {
240+ Err ( PgHeapTupleError :: NoSuchTypeOid ( typoid) )
241+ } )
242+ . execute ( )
216243 }
217244
218245 /// Create a new [PgHeapTuple] from a [PgTupleDesc] from an iterator of Datums.
219246 ///
220247 /// ## Errors
221248 /// - [PgHeapTupleError::IncorrectAttributeCount] if the number of items in the iterator
222249 /// does not match the number of attributes in the [PgTupleDesc].
223- pub fn from_datums < I : IntoIterator < Item = Option < pg_sys:: Datum > > > (
250+ ///
251+ /// # Safety
252+ ///
253+ /// This function is unsafe as we cannot guarantee the provided [`pg_sys::Datum`]s are valid
254+ /// as the specified [`PgTupleDesc`] might expect
255+ pub unsafe fn from_datums < I : IntoIterator < Item = Option < pg_sys:: Datum > > > (
224256 tupdesc : PgTupleDesc < ' a > ,
225257 datums : I ,
226258 ) -> Result < PgHeapTuple < ' a , AllocatedByRust > , PgHeapTupleError > {
0 commit comments