use crate::*;
use seq_macro::seq;
use std::num::NonZeroUsize;
#[inline]
pub fn composite_row_type_make_tuple(
row: pg_sys::Datum,
) -> PgBox<pg_sys::HeapTupleData, AllocatedByRust> {
let htup_header =
unsafe { pg_sys::pg_detoast_datum_packed(row.cast_mut_ptr()) } as pg_sys::HeapTupleHeader;
let mut tuple = unsafe { PgBox::<pg_sys::HeapTupleData>::alloc0() };
tuple.t_len = heap_tuple_header_get_datum_length(htup_header) as u32;
tuple.t_data = htup_header;
tuple
}
#[inline]
pub fn heap_tuple_header_get_datum_length(htup_header: pg_sys::HeapTupleHeader) -> usize {
if htup_header.is_null() {
panic!("Attempt to dereference a null HeapTupleHeader");
}
unsafe { crate::varlena::varsize(htup_header as *const pg_sys::varlena) }
}
#[inline]
pub fn heap_tuple_get_datum(heap_tuple: pg_sys::HeapTuple) -> pg_sys::Datum {
unsafe { pg_sys::HeapTupleHeaderGetDatum((*heap_tuple).t_data) }
}
#[inline]
pub unsafe fn heap_tuple_header_get_type_id(htup_header: pg_sys::HeapTupleHeader) -> pg_sys::Oid {
htup_header.as_ref().unwrap().t_choice.t_datum.datum_typeid
}
#[inline]
pub unsafe fn heap_tuple_header_get_typmod(htup_header: pg_sys::HeapTupleHeader) -> i32 {
htup_header.as_ref().unwrap().t_choice.t_datum.datum_typmod
}
#[inline]
pub fn heap_getattr<T: FromDatum, AllocatedBy: WhoAllocated>(
tuple: &PgBox<pg_sys::HeapTupleData, AllocatedBy>,
attno: NonZeroUsize,
tupdesc: &PgTupleDesc,
) -> Option<T> {
let mut is_null = false;
let datum = unsafe {
pg_sys::heap_getattr(tuple.as_ptr(), attno.get() as _, tupdesc.as_ptr(), &mut is_null)
};
let typoid = tupdesc.get(attno.get() - 1).expect("no attribute").type_oid();
if is_null {
None
} else {
unsafe { T::from_polymorphic_datum(datum, false, typoid.value()) }
}
}
#[inline]
pub unsafe fn heap_getattr_raw(
tuple: *mut pg_sys::HeapTupleData,
attno: NonZeroUsize,
tupdesc: pg_sys::TupleDesc,
) -> Option<pg_sys::Datum> {
let mut is_null = false;
let datum = pg_sys::heap_getattr(tuple, attno.get() as _, tupdesc, &mut is_null);
if is_null {
None
} else {
Some(datum)
}
}
#[derive(Debug, Clone)]
pub struct DatumWithTypeInfo {
pub datum: pg_sys::Datum,
pub is_null: bool,
pub typoid: PgOid,
pub typlen: i16,
pub typbyval: bool,
}
impl DatumWithTypeInfo {
#[inline]
pub fn into_value<T: FromDatum>(self) -> T {
unsafe { T::from_polymorphic_datum(self.datum, self.is_null, self.typoid.value()).unwrap() }
}
}
#[inline]
pub fn heap_getattr_datum_ex(
tuple: &PgBox<pg_sys::HeapTupleData>,
attno: NonZeroUsize,
tupdesc: &PgTupleDesc,
) -> DatumWithTypeInfo {
let mut is_null = false;
let datum = unsafe {
pg_sys::heap_getattr(tuple.as_ptr(), attno.get() as _, tupdesc.as_ptr(), &mut is_null)
};
let typoid = tupdesc.get(attno.get() - 1).expect("no attribute").type_oid();
let mut typlen = 0;
let mut typbyval = false;
let mut typalign = 0 as std::os::raw::c_char;
unsafe {
pg_sys::get_typlenbyvalalign(typoid.value(), &mut typlen, &mut typbyval, &mut typalign);
}
DatumWithTypeInfo { datum, is_null, typoid, typlen, typbyval }
}
pub trait IntoHeapTuple {
unsafe fn into_heap_tuple(
self,
tupdesc: *mut pg_sys::TupleDescData,
) -> *mut pg_sys::HeapTupleData;
}
seq!(I in 0..32 {
#(
seq!(N in 0..I {
impl<#(T~N: IntoDatum,)*> IntoHeapTuple for (#(T~N,)*) {
unsafe fn into_heap_tuple(self, tupdesc: pg_sys::TupleDesc) -> *mut pg_sys::HeapTupleData {
let mut datums = [pg_sys::Datum::from(0); I];
let mut nulls = [false; I];
#(
match self.N.into_datum() {
Some(datum) => datums[N] = datum,
None => nulls[N] = true,
}
)*
unsafe {
pg_sys::heap_form_tuple(tupdesc, datums.as_mut_ptr(), nulls.as_mut_ptr())
}
}
}
});
)*
});