1use super::{
8 Deserialize, Expr, FunctionParallel, RoutineAclEntry, RoutineConfigAction,
9 RoutineSecurityAttributes, Serialize, Statement,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
15pub enum FunctionParamMode {
16 In,
18 Out,
21 InOut,
23 Variadic,
25 Table,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct FunctionParam {
33 pub name: String,
36 pub type_name: String,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
41 pub type_reference: Option<RoutineColumnTypeReference>,
42 pub mode: FunctionParamMode,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub default: Option<Expr>,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
50pub struct RoutineColumnTypeReference {
51 pub schema: Option<String>,
52 pub relation: String,
53 pub column: String,
54}
55
56impl RoutineColumnTypeReference {
57 pub fn new(schema: Option<String>, relation: String, column: String) -> Self {
58 Self {
59 schema,
60 relation,
61 column,
62 }
63 }
64
65 pub fn relation_reference(&self) -> String {
66 match self.schema.as_deref() {
67 Some(schema) => format!(
68 "{}.{}",
69 render_identifier_component(schema),
70 render_identifier_component(&self.relation)
71 ),
72 None => render_identifier_component(&self.relation),
73 }
74 }
75
76 pub fn type_reference(&self) -> String {
77 format!(
78 "{}.{}%type",
79 self.relation_reference(),
80 render_identifier_component(&self.column)
81 )
82 }
83}
84
85fn render_identifier_component(component: &str) -> String {
86 let can_render_bare = component
87 .bytes()
88 .enumerate()
89 .all(|(index, byte)| match byte {
90 b'a'..=b'z' | b'_' => true,
91 b'0'..=b'9' | b'$' => index != 0,
92 _ => false,
93 });
94 if can_render_bare && !component.is_empty() {
95 component.to_string()
96 } else {
97 format!("\"{}\"", component.replace('"', "\"\""))
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub enum FunctionReturns {
104 None,
107 Scalar { type_name: String },
109 SetOf { type_name: String },
111 Table,
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
119pub enum FunctionVolatility {
120 Immutable,
121 Stable,
122 #[default]
123 Volatile,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub enum FunctionBody {
129 Source(String),
132 Statements(Vec<Statement>),
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct CreateFunction {
140 #[serde(default, skip_serializing_if = "Option::is_none")]
142 pub object_id: Option<[u8; 16]>,
143 pub name: String,
144 pub or_replace: bool,
145 pub is_procedure: bool,
146 pub params: Vec<FunctionParam>,
147 pub returns: FunctionReturns,
148 #[serde(default, skip_serializing_if = "Option::is_none")]
150 pub return_type_reference: Option<RoutineColumnTypeReference>,
151 pub language: String,
153 pub body: FunctionBody,
154 #[serde(default, skip_serializing_if = "Vec::is_empty")]
156 pub creation_search_path: Vec<String>,
157 pub volatility: FunctionVolatility,
158 pub strict: bool,
161 #[serde(
163 default,
164 deserialize_with = "super::routine_security::deserialize_routine_owner"
165 )]
166 pub owner: Option<uqa_core::catalog_role::RoleIdentity>,
167 #[serde(default, flatten)]
169 pub security: RoutineSecurityAttributes,
170 #[serde(default)]
172 pub parallel: FunctionParallel,
173 #[serde(default, skip_serializing_if = "Option::is_none")]
175 pub support: Option<String>,
176 #[serde(default, skip_serializing_if = "Vec::is_empty")]
178 pub config: Vec<(String, String)>,
179 #[serde(default, skip_serializing_if = "Vec::is_empty")]
181 pub config_actions: Vec<RoutineConfigAction>,
182 #[serde(default)]
184 pub execute_acl: Option<Vec<RoutineAclEntry>>,
185}
186
187impl CreateFunction {
188 pub fn identity_params(&self) -> Vec<&FunctionParam> {
190 self.params
191 .iter()
192 .filter(|param| Self::is_identity_param(param))
193 .collect()
194 }
195
196 pub fn identity_arity(&self) -> usize {
198 self.params
199 .iter()
200 .filter(|param| Self::is_identity_param(param))
201 .count()
202 }
203
204 fn is_identity_param(param: &FunctionParam) -> bool {
205 matches!(
206 param.mode,
207 FunctionParamMode::In | FunctionParamMode::InOut | FunctionParamMode::Variadic
208 )
209 }
210
211 pub fn call_params(&self) -> Vec<&FunctionParam> {
213 self.params
214 .iter()
215 .filter(|param| self.is_call_param(param))
216 .collect()
217 }
218
219 pub fn call_arity(&self) -> usize {
221 self.params
222 .iter()
223 .filter(|param| self.is_call_param(param))
224 .count()
225 }
226
227 pub fn required_call_arity(&self) -> usize {
229 self.params
230 .iter()
231 .filter(|param| {
232 self.is_call_param(param)
233 && param.default.is_none()
234 && param.mode != FunctionParamMode::Variadic
235 })
236 .count()
237 }
238
239 fn is_call_param(&self, param: &FunctionParam) -> bool {
240 match param.mode {
241 FunctionParamMode::In | FunctionParamMode::InOut | FunctionParamMode::Variadic => true,
242 FunctionParamMode::Out => self.is_procedure,
243 FunctionParamMode::Table => false,
244 }
245 }
246
247 pub fn signature_arity(&self) -> usize {
249 self.call_arity()
250 }
251
252 pub fn required_arity(&self) -> usize {
254 self.required_call_arity()
255 }
256
257 pub fn signature_params(&self) -> Vec<&FunctionParam> {
259 self.call_params()
260 }
261
262 pub fn output_params(&self) -> Vec<&FunctionParam> {
265 self.params
266 .iter()
267 .filter(|p| {
268 matches!(
269 p.mode,
270 FunctionParamMode::Out | FunctionParamMode::InOut | FunctionParamMode::Table
271 )
272 })
273 .collect()
274 }
275
276 pub fn returns_set(&self) -> bool {
279 matches!(
280 self.returns,
281 FunctionReturns::SetOf { .. } | FunctionReturns::Table
282 )
283 }
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct DropFunctionItem {
289 pub name: String,
290 pub arg_types: Option<Vec<String>>,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
300pub struct DropFunctionStmt {
301 pub is_procedure: bool,
302 pub if_exists: bool,
303 #[serde(default)]
304 pub cascade: bool,
305 pub items: Vec<DropFunctionItem>,
306}