Skip to main content

rupg_catalog/
operator.rs

1//! The operators of `pg_operator` that `CREATE OPERATOR` makes, as `OperatorCreate`, `OperatorShellMake`, `OperatorUpd` and `makeOperatorDependencies` of `pg_operator.c` make them.
2
3use rupg_common::Result;
4
5use super::{Catalog, ObjRef, PG_NAMESPACE, PG_PROC, PG_TYPE, no_object};
6
7/// The OID of `pg_operator`.
8pub const PG_OPERATOR: u32 = 2617;
9
10/// An operator, one row of `pg_operator`.
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct Operator {
13    /// The OID. [`Catalog::create_operator`] sets it.
14    pub oid: u32,
15    /// The name.
16    pub name: String,
17    /// The OID of the schema.
18    pub namespace: u32,
19    /// The OID of the owner role.
20    pub owner: u32,
21    /// `oprkind`: `b` for an infix operator or `l` for a prefix operator.
22    pub kind: u8,
23    /// `oprcanmerge`.
24    pub can_merge: bool,
25    /// `oprcanhash`.
26    pub can_hash: bool,
27    /// `oprleft`: the type of the left input, or 0 for a prefix operator.
28    pub left: u32,
29    /// `oprright`.
30    pub right: u32,
31    /// `oprresult`, or 0 for a shell.
32    pub result: u32,
33    /// `oprcom`: the commutator, or 0.
34    pub commutator: u32,
35    /// `oprnegate`: the negator, or 0.
36    pub negator: u32,
37    /// `oprcode`: the function, or 0 for a shell.
38    pub code: u32,
39    /// `oprrest`: the restriction estimator, or 0.
40    pub restrict: u32,
41    /// `oprjoin`: the join estimator, or 0.
42    pub join: u32,
43}
44
45impl Operator {
46    /// `OperatorShellMake`: an operator with a name and input types only, which a later `CREATE OPERATOR` fills.
47    pub fn shell(name: &str, namespace: u32, owner: u32, left: u32, right: u32) -> Operator {
48        Operator {
49            oid: 0,
50            name: name.to_string(),
51            namespace,
52            owner,
53            kind: if left == 0 { b'l' } else { b'b' },
54            can_merge: false,
55            can_hash: false,
56            left,
57            right,
58            result: 0,
59            commutator: 0,
60            negator: 0,
61            code: 0,
62            restrict: 0,
63            join: 0,
64        }
65    }
66}
67
68impl Catalog {
69    /// The operators of the catalog, in the order of their OIDs.
70    pub fn operators(&self) -> impl Iterator<Item = &Operator> {
71        self.operators.values()
72    }
73
74    /// The operator with the OID.
75    pub fn operator(&self, oid: u32) -> Option<&Operator> {
76        self.operators.get(&oid)
77    }
78
79    /// `OperatorGet`: the operator of the schema with the name and the input types.
80    pub fn operator_by_name(
81        &self,
82        namespace: u32,
83        name: &str,
84        left: u32,
85        right: u32,
86    ) -> Option<&Operator> {
87        self.operators.values().find(|o| {
88            o.namespace == namespace && o.name == name && o.left == left && o.right == right
89        })
90    }
91
92    /// `OperatorCreate` and `OperatorShellMake` for a new operator, which gets the next OID, with the dependencies of `makeOperatorDependencies`.
93    pub fn create_operator(&mut self, mut new: Operator) -> u32 {
94        let oid = self.new_oid();
95        new.oid = oid;
96        self.operators.insert(oid, new);
97        self.operator_depends(oid);
98        oid
99    }
100
101    /// `OperatorCreate` for a shell operator that exists: the operator gets the new facts and keeps its OID, and its dependencies are made again.
102    ///
103    /// # Errors
104    ///
105    /// An internal error when no operator has the OID.
106    pub fn replace_operator(&mut self, oid: u32, mut new: Operator) -> Result<()> {
107        if !self.operators.contains_key(&oid) {
108            return Err(no_object("operator", oid));
109        }
110        new.oid = oid;
111        self.operators.insert(oid, new);
112        let me = ObjRef::new(PG_OPERATOR, oid);
113        self.depends.retain(|d| d.object != me);
114        self.operator_depends(oid);
115        Ok(())
116    }
117
118    /// Changes the row of the operator, as `OperatorUpd` and `AlterOperator` change it.
119    ///
120    /// # Errors
121    ///
122    /// An internal error when no operator has the OID.
123    pub fn alter_operator(&mut self, oid: u32, change: impl FnOnce(&mut Operator)) -> Result<()> {
124        let operator = self.operators.get_mut(&oid).ok_or_else(|| no_object("operator", oid))?;
125        change(operator);
126        Ok(())
127    }
128
129    /// `RemoveOperatorById`: the commutator and the negator of the operator lose their link to it, as `OperatorUpd` with `isDelete` clears them, and the operator goes.
130    pub(crate) fn remove_operator(&mut self, oid: u32) {
131        let Some(old) = self.operators.remove(&oid) else { return };
132        if let Some(commutator) = self.operators.get_mut(&old.commutator) {
133            commutator.commutator = 0;
134        }
135        if let Some(negator) = self.operators.get_mut(&old.negator) {
136            negator.negator = 0;
137        }
138    }
139
140    /// `makeOperatorDependencies`: the operator depends on its schema, its types and its functions.
141    fn operator_depends(&mut self, oid: u32) {
142        let Some(op) = self.operators.get(&oid) else { return };
143        let mut refs = vec![ObjRef::new(PG_NAMESPACE, op.namespace)];
144        refs.extend(
145            [op.left, op.right, op.result]
146                .into_iter()
147                .filter(|&ty| ty != 0)
148                .map(|ty| ObjRef::new(PG_TYPE, ty)),
149        );
150        refs.extend(
151            [op.code, op.restrict, op.join]
152                .into_iter()
153                .filter(|&f| f != 0)
154                .map(|f| ObjRef::new(PG_PROC, f)),
155        );
156        self.depend_all(ObjRef::new(PG_OPERATOR, oid), refs);
157    }
158}