use super::{
Catalog, DepKind, ObjRef, PG_NAMESPACE, PG_OPCLASS, PG_OPERATOR, PG_PROC, PG_TYPE, is_pinned,
};
pub const PG_AM: u32 = 2601;
pub const PG_AMOP: u32 = 2602;
pub const PG_AMPROC: u32 = 2603;
pub const PG_OPFAMILY: u32 = 2753;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OpFamily {
pub oid: u32,
pub method: u32,
pub name: String,
pub namespace: u32,
pub owner: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OpClass {
pub oid: u32,
pub method: u32,
pub name: String,
pub namespace: u32,
pub owner: u32,
pub family: u32,
pub intype: u32,
pub default: bool,
pub keytype: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AmOp {
pub oid: u32,
pub family: u32,
pub left: u32,
pub right: u32,
pub strategy: i16,
pub purpose: u8,
pub operator: u32,
pub method: u32,
pub sortfamily: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AmProc {
pub oid: u32,
pub family: u32,
pub left: u32,
pub right: u32,
pub number: i16,
pub function: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MemberLink {
pub hard: bool,
pub owner: ObjRef,
pub inputs: Vec<u32>,
}
impl MemberLink {
fn kind(&self) -> DepKind {
if self.hard { DepKind::Normal } else { DepKind::Auto }
}
fn needs_type(&self, ty: u32) -> bool {
!is_pinned(ObjRef::new(PG_TYPE, ty)) && !self.inputs.contains(&ty)
}
}
impl Catalog {
pub fn create_opfamily(&mut self, mut new: OpFamily) -> u32 {
let oid = self.new_oid();
new.oid = oid;
let me = ObjRef::new(PG_OPFAMILY, oid);
self.depend(me, ObjRef::new(PG_AM, new.method), DepKind::Auto);
self.depend(me, ObjRef::new(PG_NAMESPACE, new.namespace), DepKind::Normal);
self.opfamilies.insert(oid, new);
oid
}
pub fn create_opclass(&mut self, mut new: OpClass) -> u32 {
let oid = self.new_oid();
new.oid = oid;
self.opclasses.insert(oid, new);
oid
}
pub fn opclass_depends(&mut self, oid: u32) {
let Some(class) = self.opclasses.get(&oid) else { return };
let me = ObjRef::new(PG_OPCLASS, oid);
let mut refs = vec![
(ObjRef::new(PG_NAMESPACE, class.namespace), DepKind::Normal),
(ObjRef::new(PG_OPFAMILY, class.family), DepKind::Auto),
(ObjRef::new(PG_TYPE, class.intype), DepKind::Normal),
];
if class.keytype != 0 {
refs.push((ObjRef::new(PG_TYPE, class.keytype), DepKind::Normal));
}
for (referenced, kind) in refs {
self.depend(me, referenced, kind);
}
}
pub fn add_amop(&mut self, mut new: AmOp, link: &MemberLink) -> u32 {
let oid = self.new_oid();
new.oid = oid;
let me = ObjRef::new(PG_AMOP, oid);
self.depend(me, ObjRef::new(PG_OPERATOR, new.operator), link.kind());
self.member_depends(me, link, new.left, new.right);
if new.sortfamily != 0 {
self.depend(me, ObjRef::new(PG_OPFAMILY, new.sortfamily), link.kind());
}
self.amops.insert(oid, new);
oid
}
pub fn add_amproc(&mut self, mut new: AmProc, link: &MemberLink) -> u32 {
let oid = self.new_oid();
new.oid = oid;
let me = ObjRef::new(PG_AMPROC, oid);
self.depend(me, ObjRef::new(PG_PROC, new.function), link.kind());
self.member_depends(me, link, new.left, new.right);
self.amprocs.insert(oid, new);
oid
}
fn member_depends(&mut self, me: ObjRef, link: &MemberLink, left: u32, right: u32) {
let owner = if link.hard { DepKind::Internal } else { DepKind::Auto };
self.depend(me, link.owner, owner);
if link.needs_type(left) {
self.depend(me, ObjRef::new(PG_TYPE, left), link.kind());
}
if left != right && link.needs_type(right) {
self.depend(me, ObjRef::new(PG_TYPE, right), link.kind());
}
}
pub fn alter_opfamily(&mut self, oid: u32, change: impl FnOnce(&mut OpFamily)) {
if let Some(family) = self.opfamilies.get_mut(&oid) {
change(family);
}
}
pub fn alter_opclass(&mut self, oid: u32, change: impl FnOnce(&mut OpClass)) {
if let Some(class) = self.opclasses.get_mut(&oid) {
change(class);
}
}
pub fn set_opcf_namespace(&mut self, family: bool, oid: u32, namespace: u32) {
let (class, old) = if family {
let row = self.opfamilies.get_mut(&oid);
(PG_OPFAMILY, row.map(|f| std::mem::replace(&mut f.namespace, namespace)))
} else {
let row = self.opclasses.get_mut(&oid);
(PG_OPCLASS, row.map(|c| std::mem::replace(&mut c.namespace, namespace)))
};
if let Some(old) = old {
self.change_namespace_dependency(ObjRef::new(class, oid), old, namespace);
}
}
pub fn opfamilies(&self) -> impl Iterator<Item = &OpFamily> {
self.opfamilies.values()
}
pub fn opfamily(&self, oid: u32) -> Option<&OpFamily> {
self.opfamilies.get(&oid)
}
pub fn opclasses(&self) -> impl Iterator<Item = &OpClass> {
self.opclasses.values()
}
pub fn opclass(&self, oid: u32) -> Option<&OpClass> {
self.opclasses.get(&oid)
}
pub fn amops(&self) -> impl Iterator<Item = &AmOp> {
self.amops.values()
}
pub fn amop(&self, oid: u32) -> Option<&AmOp> {
self.amops.get(&oid)
}
pub fn amprocs(&self) -> impl Iterator<Item = &AmProc> {
self.amprocs.values()
}
pub fn amproc(&self, oid: u32) -> Option<&AmProc> {
self.amprocs.get(&oid)
}
}