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