use crate::{pg_sys, rust_regtypein, PgBox, PgOid, WhoAllocated};
use core::fmt::Display;
use pgx_pg_sys::panic::ErrorReportable;
use pgx_pg_sys::{Datum, Oid};
use std::any::Any;
pub trait IntoDatum {
fn into_datum(self) -> Option<pg_sys::Datum>;
fn type_oid() -> pg_sys::Oid;
fn composite_type_oid(&self) -> Option<Oid> {
None
}
fn array_type_oid() -> pg_sys::Oid {
unsafe { pg_sys::get_array_type(Self::type_oid()) }
}
#[inline]
fn is_compatible_with(other: pg_sys::Oid) -> bool {
Self::type_oid() == other
}
}
impl<T> IntoDatum for Option<T>
where
T: IntoDatum,
{
fn into_datum(self) -> Option<pg_sys::Datum> {
match self {
Some(t) => t.into_datum(),
None => None,
}
}
fn type_oid() -> pg_sys::Oid {
T::type_oid()
}
}
impl<T, E> IntoDatum for Result<T, E>
where
T: IntoDatum,
E: Any + Display,
{
#[inline]
fn into_datum(self) -> Option<Datum> {
self.report().into_datum()
}
#[inline]
fn type_oid() -> pg_sys::Oid {
T::type_oid()
}
}
impl IntoDatum for bool {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(pg_sys::Datum::from(if self { 1 } else { 0 }))
}
fn type_oid() -> pg_sys::Oid {
pg_sys::BOOLOID
}
}
impl IntoDatum for i8 {
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(pg_sys::Datum::from(self))
}
fn type_oid() -> pg_sys::Oid {
pg_sys::CHAROID
}
}
impl IntoDatum for i16 {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(pg_sys::Datum::from(self))
}
fn type_oid() -> pg_sys::Oid {
pg_sys::INT2OID
}
fn is_compatible_with(other: pg_sys::Oid) -> bool {
Self::type_oid() == other || i8::type_oid() == other
}
}
impl IntoDatum for i32 {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(pg_sys::Datum::from(self))
}
fn type_oid() -> pg_sys::Oid {
pg_sys::INT4OID
}
fn is_compatible_with(other: pg_sys::Oid) -> bool {
Self::type_oid() == other || i8::type_oid() == other || i16::type_oid() == other
}
}
impl IntoDatum for u32 {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(pg_sys::Datum::from(self))
}
fn type_oid() -> pg_sys::Oid {
pg_sys::OIDOID
}
fn is_compatible_with(other: pg_sys::Oid) -> bool {
Self::type_oid() == other
|| i8::type_oid() == other
|| i16::type_oid() == other
|| i32::type_oid() == other
}
}
impl IntoDatum for i64 {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(pg_sys::Datum::from(self))
}
fn type_oid() -> pg_sys::Oid {
pg_sys::INT8OID
}
fn is_compatible_with(other: pg_sys::Oid) -> bool {
Self::type_oid() == other
|| i8::type_oid() == other
|| i16::type_oid() == other
|| i32::type_oid() == other
|| i64::type_oid() == other
}
}
impl IntoDatum for f32 {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(self.to_bits().into())
}
fn type_oid() -> pg_sys::Oid {
pg_sys::FLOAT4OID
}
}
impl IntoDatum for f64 {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(self.to_bits().into())
}
fn type_oid() -> pg_sys::Oid {
pg_sys::FLOAT8OID
}
}
impl IntoDatum for pg_sys::Oid {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
if self == pg_sys::Oid::INVALID {
None
} else {
Some(pg_sys::Datum::from(self.as_u32()))
}
}
#[inline]
fn type_oid() -> pg_sys::Oid {
pg_sys::OIDOID
}
}
impl IntoDatum for PgOid {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
match self {
PgOid::Invalid => None,
oid => Some(oid.value().into()),
}
}
fn type_oid() -> pg_sys::Oid {
pg_sys::OIDOID
}
}
impl<'a> IntoDatum for &'a str {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
self.as_bytes().into_datum()
}
fn type_oid() -> pg_sys::Oid {
pg_sys::TEXTOID
}
#[inline]
fn is_compatible_with(other: Oid) -> bool {
Self::type_oid() == other || other == pg_sys::VARCHAROID
}
}
impl IntoDatum for String {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
self.as_str().into_datum()
}
fn type_oid() -> pg_sys::Oid {
pg_sys::TEXTOID
}
#[inline]
fn is_compatible_with(other: Oid) -> bool {
Self::type_oid() == other || other == pg_sys::VARCHAROID
}
}
impl IntoDatum for &String {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
self.as_str().into_datum()
}
fn type_oid() -> pg_sys::Oid {
pg_sys::TEXTOID
}
#[inline]
fn is_compatible_with(other: Oid) -> bool {
Self::type_oid() == other || other == pg_sys::VARCHAROID
}
}
impl IntoDatum for char {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
self.to_string().into_datum()
}
fn type_oid() -> pg_sys::Oid {
pg_sys::VARCHAROID
}
#[inline]
fn is_compatible_with(other: Oid) -> bool {
Self::type_oid() == other || other == pg_sys::VARCHAROID
}
}
impl<'a> IntoDatum for &'a std::ffi::CStr {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(self.as_ptr().into())
}
fn type_oid() -> pg_sys::Oid {
pg_sys::CSTRINGOID
}
}
impl IntoDatum for std::ffi::CString {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(self.as_ptr().into())
}
fn type_oid() -> pg_sys::Oid {
pg_sys::CSTRINGOID
}
}
impl<'a> IntoDatum for &'a crate::cstr_core::CStr {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(self.as_ptr().into())
}
fn type_oid() -> pg_sys::Oid {
pg_sys::CSTRINGOID
}
}
impl<'a> IntoDatum for &'a [u8] {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
let len = pg_sys::VARHDRSZ + self.len();
unsafe {
let varlena = pg_sys::palloc(len) as *mut pg_sys::varlena;
let varattrib_4b = varlena
.cast::<pg_sys::varattrib_4b>()
.as_mut()
.unwrap_unchecked()
.va_4byte
.as_mut();
varattrib_4b.va_header = <usize as TryInto<u32>>::try_into(len)
.expect("Rust string too large for a Postgres varlena datum")
<< 2u32;
std::ptr::copy_nonoverlapping(
self.as_ptr().cast(),
varattrib_4b.va_data.as_mut_ptr(),
self.len(),
);
Some(Datum::from(varlena))
}
}
#[inline]
fn type_oid() -> pg_sys::Oid {
pg_sys::BYTEAOID
}
}
impl IntoDatum for Vec<u8> {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
(&self[..]).into_datum()
}
#[inline]
fn type_oid() -> pg_sys::Oid {
pg_sys::BYTEAOID
}
}
impl IntoDatum for () {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(Datum::from(0))
}
fn type_oid() -> pg_sys::Oid {
pg_sys::VOIDOID
}
}
impl<T, AllocatedBy: WhoAllocated> IntoDatum for PgBox<T, AllocatedBy> {
#[inline]
fn into_datum(self) -> Option<pg_sys::Datum> {
if self.is_null() {
None
} else {
Some(self.into_pg().into())
}
}
fn type_oid() -> pg_sys::Oid {
rust_regtypein::<T>()
}
}
impl IntoDatum for pg_sys::Datum {
fn into_datum(self) -> Option<pg_sys::Datum> {
Some(self)
}
fn type_oid() -> pg_sys::Oid {
pg_sys::INT8OID
}
}