1use serde::{Deserialize, Serialize};
8
9use super::RangeSubtype;
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct FunctionBinding {
13 #[serde(default, skip_serializing_if = "Option::is_none")]
15 pub object_id: Option<[u8; 16]>,
16 pub name: String,
17 pub argument_types: Vec<String>,
18 #[serde(default)]
19 pub builtin: bool,
20 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub dispatch: Option<FunctionDispatch>,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub invocation: Option<Box<RoutineInvocationBinding>>,
26 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub resolution_error: Option<FunctionResolutionError>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub enum FunctionResolutionError {
34 UndefinedFunction { signature: String },
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
39pub enum FunctionDispatch {
40 NamedArgument,
41 VariadicArgument,
42 ArraySubscripts,
43 ArraySlices,
44 Subscript,
45 Slice,
46 AnyOperator,
47 AllOperator,
48 IsDistinct,
49 BetweenSymmetric,
50 ToBinInt4,
51 ToBinInt8,
52 ToHexInt4,
53 ToHexInt8,
54 ToOctInt4,
55 ToOctInt8,
56 RandomInt4Range,
57 RandomInt8Range,
58 RandomNumericRange,
59 ArraySortJson,
60 Range {
61 operation: RangeFunctionOperation,
62 subtype: RangeSubtype,
63 multirange: bool,
64 },
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69pub enum RangeFunctionOperation {
70 Lower,
71 Upper,
72 IsEmpty,
73 LowerInclusive,
74 UpperInclusive,
75 LowerInfinite,
76 UpperInfinite,
77 Merge,
78 Multirange,
79 Overlap,
80 Contains,
81 ContainedBy,
82 Adjacent,
83}
84
85impl FunctionDispatch {
86 #[must_use]
88 pub const fn label(self) -> &'static str {
89 match self {
90 Self::NamedArgument => "named argument",
91 Self::VariadicArgument => "VARIADIC argument",
92 Self::ArraySubscripts | Self::Subscript => "subscript",
93 Self::ArraySlices | Self::Slice => "slice",
94 Self::AnyOperator => "ANY operator",
95 Self::AllOperator => "ALL operator",
96 Self::IsDistinct => "IS DISTINCT FROM",
97 Self::BetweenSymmetric => "BETWEEN SYMMETRIC",
98 Self::ToBinInt4 | Self::ToBinInt8 => "pg_catalog.to_bin",
99 Self::ToHexInt4 | Self::ToHexInt8 => "pg_catalog.to_hex",
100 Self::ToOctInt4 | Self::ToOctInt8 => "pg_catalog.to_oct",
101 Self::RandomInt4Range | Self::RandomInt8Range | Self::RandomNumericRange => {
102 "pg_catalog.random"
103 }
104 Self::ArraySortJson => "pg_catalog.array_sort",
105 Self::Range { operation, .. } => operation.label(),
106 }
107 }
108
109 #[must_use]
110 pub const fn is_call_argument_marker(self) -> bool {
111 matches!(self, Self::NamedArgument | Self::VariadicArgument)
112 }
113
114 #[doc(hidden)]
116 #[must_use]
117 pub fn from_legacy_serialized_name(name: &str) -> Option<Self> {
118 let fixed = match name {
119 "__named_arg" => Self::NamedArgument,
120 "__variadic_arg" => Self::VariadicArgument,
121 "__array_subscripts" => Self::ArraySubscripts,
122 "__array_slices" => Self::ArraySlices,
123 "__subscript" => Self::Subscript,
124 "__slice" => Self::Slice,
125 "__any_op" => Self::AnyOperator,
126 "__all_op" => Self::AllOperator,
127 "__is_distinct" => Self::IsDistinct,
128 "__between_symmetric" => Self::BetweenSymmetric,
129 "__to_bin_int4" => Self::ToBinInt4,
130 "__to_bin_int8" => Self::ToBinInt8,
131 "__to_hex_int4" => Self::ToHexInt4,
132 "__to_hex_int8" => Self::ToHexInt8,
133 "__to_oct_int4" => Self::ToOctInt4,
134 "__to_oct_int8" => Self::ToOctInt8,
135 "__random_int4_range" => Self::RandomInt4Range,
136 "__random_int8_range" => Self::RandomInt8Range,
137 "__random_numeric_range" => Self::RandomNumericRange,
138 "__array_sort_json" => Self::ArraySortJson,
139 _ => return Self::legacy_range_dispatch(name),
140 };
141 Some(fixed)
142 }
143
144 fn legacy_range_dispatch(name: &str) -> Option<Self> {
145 let encoded = name.strip_prefix("__range_")?;
146 let subtypes = [
147 RangeSubtype::Integer,
148 RangeSubtype::BigInteger,
149 RangeSubtype::Numeric,
150 RangeSubtype::Date,
151 RangeSubtype::Timestamp,
152 RangeSubtype::TimestampTz,
153 ];
154 for subtype in subtypes {
155 for (type_name, multirange) in [
156 (subtype.multirange_name(), true),
157 (subtype.range_name(), false),
158 ] {
159 let Some(operation) = encoded.strip_suffix(type_name) else {
160 continue;
161 };
162 let operation = match operation.trim_end_matches('_') {
163 "lower" => RangeFunctionOperation::Lower,
164 "upper" => RangeFunctionOperation::Upper,
165 "isempty" => RangeFunctionOperation::IsEmpty,
166 "lower_inc" => RangeFunctionOperation::LowerInclusive,
167 "upper_inc" => RangeFunctionOperation::UpperInclusive,
168 "lower_inf" => RangeFunctionOperation::LowerInfinite,
169 "upper_inf" => RangeFunctionOperation::UpperInfinite,
170 "merge" => RangeFunctionOperation::Merge,
171 "multirange" => RangeFunctionOperation::Multirange,
172 "overlap" => RangeFunctionOperation::Overlap,
173 "contains" => RangeFunctionOperation::Contains,
174 "contained_by" => RangeFunctionOperation::ContainedBy,
175 "adjacent" => RangeFunctionOperation::Adjacent,
176 _ => continue,
177 };
178 return Some(Self::Range {
179 operation,
180 subtype,
181 multirange,
182 });
183 }
184 }
185 None
186 }
187}
188
189impl RangeFunctionOperation {
190 #[must_use]
191 pub const fn label(self) -> &'static str {
192 match self {
193 Self::Lower => "pg_catalog.lower",
194 Self::Upper => "pg_catalog.upper",
195 Self::IsEmpty => "pg_catalog.isempty",
196 Self::LowerInclusive => "pg_catalog.lower_inc",
197 Self::UpperInclusive => "pg_catalog.upper_inc",
198 Self::LowerInfinite => "pg_catalog.lower_inf",
199 Self::UpperInfinite => "pg_catalog.upper_inf",
200 Self::Merge => "pg_catalog.range_merge",
201 Self::Multirange => "pg_catalog.multirange",
202 Self::Overlap => "range overlap operator",
203 Self::Contains => "range contains operator",
204 Self::ContainedBy => "range contained-by operator",
205 Self::Adjacent => "range adjacent operator",
206 }
207 }
208}
209
210#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
212pub struct RoutineInvocationBinding {
213 pub argument_positions: Vec<usize>,
215 pub argument_targets: Vec<String>,
217 #[serde(default, skip_serializing_if = "Vec::is_empty")]
219 pub argument_sources: Vec<Option<String>>,
220 pub parameter_types: Vec<String>,
222 pub return_type: Option<String>,
224 pub variadic_mode: RoutineVariadicMode,
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
230pub enum RoutineVariadicMode {
231 #[default]
233 None,
234 Expanded {
236 parameter_index: usize,
238 },
239 Explicit {
241 parameter_index: usize,
243 },
244}
245
246impl FunctionBinding {
247 #[must_use]
249 pub fn polymorphic_builtin_syntax(name: &str) -> Self {
250 assert!(Self::is_polymorphic_builtin_syntax_name(name));
251 Self {
252 object_id: None,
253 name: name.into(),
254 argument_types: Vec::new(),
255 builtin: true,
256 dispatch: None,
257 invocation: None,
258 resolution_error: None,
259 }
260 }
261
262 #[must_use]
264 pub fn dispatched(dispatch: FunctionDispatch) -> Self {
265 Self {
266 object_id: None,
267 name: dispatch.label().into(),
268 argument_types: Vec::new(),
269 builtin: true,
270 dispatch: Some(dispatch),
271 invocation: None,
272 resolution_error: None,
273 }
274 }
275
276 #[must_use]
278 pub fn undefined_function(name: impl Into<String>, signature: impl Into<String>) -> Self {
279 Self {
280 object_id: None,
281 name: name.into(),
282 argument_types: Vec::new(),
283 builtin: false,
284 dispatch: None,
285 invocation: None,
286 resolution_error: Some(FunctionResolutionError::UndefinedFunction {
287 signature: signature.into(),
288 }),
289 }
290 }
291
292 #[doc(hidden)]
294 pub fn upgrade_legacy_serialized_dispatch(
295 display_name: &mut String,
296 binding: &mut Option<Self>,
297 ) -> bool {
298 if binding
299 .as_ref()
300 .is_some_and(|binding| binding.dispatch.is_some() || !binding.builtin)
301 {
302 return false;
303 }
304 let Some(dispatch) = FunctionDispatch::from_legacy_serialized_name(display_name) else {
305 return false;
306 };
307 if let Some(binding) = binding {
308 binding.dispatch = Some(dispatch);
309 display_name.clone_from(&binding.name);
310 } else {
311 let upgraded = Self::dispatched(dispatch);
312 display_name.clone_from(&upgraded.name);
313 *binding = Some(upgraded);
314 }
315 true
316 }
317
318 #[must_use]
320 pub fn is_polymorphic_builtin_syntax(&self) -> bool {
321 self.builtin
322 && self.argument_types.is_empty()
323 && Self::is_polymorphic_builtin_syntax_name(&self.name)
324 }
325
326 #[must_use]
328 pub fn is_polymorphic_builtin_syntax_name(name: &str) -> bool {
329 matches!(name, "coalesce" | "greatest" | "least" | "nullif")
330 }
331}
332
333pub type GeneratedFunctionDependency = FunctionBinding;