feat(Postgres): support nested domain types (#3641)

* feat(Postgres): support nested domain types

* chore: clippy

* fix(postgres): Recurse when looking for type info.
This commit is contained in:
Joey de Waal
2025-07-07 03:37:56 +02:00
committed by GitHub
parent 1228d243be
commit 9f28837bca
4 changed files with 86 additions and 22 deletions

View File

@@ -1013,7 +1013,7 @@ impl PgType {
/// If `soft_eq` is true and `self` or `other` is `DeclareWithOid` but not both, return `true`
/// before checking names.
fn eq_impl(&self, other: &Self, soft_eq: bool) -> bool {
if let (Some(a), Some(b)) = (self.try_oid(), other.try_oid()) {
if let (Some(a), Some(b)) = (self.try_base_oid(), other.try_base_oid()) {
// If there are OIDs available, use OIDs to perform a direct match
return a == b;
}
@@ -1035,6 +1035,18 @@ impl PgType {
// Otherwise, perform a match on the name
name_eq(self.name(), other.name())
}
// Tries to return the OID of the type, returns the OID of the base_type for domain types
#[inline(always)]
fn try_base_oid(&self) -> Option<Oid> {
match self {
PgType::Custom(custom) => match &custom.kind {
PgTypeKind::Domain(domain) => domain.try_oid(),
_ => Some(custom.oid),
},
ty => ty.try_oid(),
}
}
}
impl TypeInfo for PgTypeInfo {

View File

@@ -103,27 +103,7 @@ impl<'r> PgRecordDecoder<'r> {
match self.fmt {
PgValueFormat::Binary => {
let element_type_oid = Oid(self.buf.get_u32());
let element_type_opt = match self.typ.0.kind() {
PgTypeKind::Simple if self.typ.0 == PgType::Record => {
PgTypeInfo::try_from_oid(element_type_oid)
}
PgTypeKind::Composite(fields) => {
let ty = fields[self.ind].1.clone();
if ty.0.oid() != element_type_oid {
return Err("unexpected mismatch of composite type information".into());
}
Some(ty)
}
_ => {
return Err(
"unexpected non-composite type being decoded as a composite type"
.into(),
);
}
};
let element_type_opt = self.find_type_info(&self.typ, element_type_oid)?;
if let Some(ty) = &element_type_opt {
if !ty.is_null() && !T::compatible(ty) {
@@ -202,4 +182,24 @@ impl<'r> PgRecordDecoder<'r> {
}
}
}
fn find_type_info(
&self,
typ: &PgTypeInfo,
oid: Oid,
) -> Result<Option<PgTypeInfo>, BoxDynError> {
match typ.kind() {
PgTypeKind::Simple if typ.0 == PgType::Record => Ok(PgTypeInfo::try_from_oid(oid)),
PgTypeKind::Composite(fields) => {
let ty = fields[self.ind].1.clone();
if ty.0.oid() != oid {
return Err("unexpected mismatch of composite type information".into());
}
Ok(Some(ty))
}
PgTypeKind::Domain(domain) => self.find_type_info(domain, oid),
_ => Err("unexpected custom type being decoded as a composite type".into()),
}
}
}