uqa_sql/routines/
lifecycle.rs1pub mod binding;
10pub mod dependencies;
11pub mod lookup;
12pub mod names;
13pub mod relations;
14pub mod rename;
15pub mod restoration;
16pub mod rewrites;
17
18use super::SQLUserFunction;
19use crate::{
20 ast::{AlterRoutineKind, CreateFunction, FunctionBinding},
21 SQLError,
22};
23use std::{
24 collections::{BTreeMap, BTreeSet},
25 sync::Arc,
26};
27
28pub type RoutineRegistry = BTreeMap<String, Vec<Arc<SQLUserFunction>>>;
29
30#[derive(Default)]
31pub struct RoutineDropResolution {
32 pub targets: Vec<RoutineDropTarget>,
33 pub seen_targets: BTreeSet<RoutineDropTarget>,
34 pub notices: Vec<crate::SQLNotice>,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
38pub struct RoutineDropTarget {
39 pub object_id: Option<[u8; 16]>,
40 pub name: String,
41 pub argument_types: Vec<String>,
42 pub is_procedure: bool,
43}
44
45impl RoutineDropTarget {
46 pub fn kind(&self) -> &'static str {
47 if self.is_procedure {
48 "procedure"
49 } else {
50 "function"
51 }
52 }
53
54 pub fn label(&self) -> String {
55 routine_signature_label(&self.name, &self.argument_types)
56 }
57
58 pub fn names(&self, function: &SQLUserFunction) -> bool {
60 function.def.is_procedure == self.is_procedure
61 && super::routine_signature_types(&function.def) == self.argument_types
62 && (self.object_id.is_none() || function.def.object_id == self.object_id)
63 }
64
65 pub fn binding(&self) -> FunctionBinding {
66 FunctionBinding {
67 object_id: self.object_id,
68 name: self.name.clone(),
69 argument_types: self.argument_types.clone(),
70 builtin: false,
71 dispatch: None,
72 invocation: None,
73 composite_field: None,
74 resolution_error: None,
75 }
76 }
77}
78
79pub fn routine_signature_label(name: &str, types: &[String]) -> String {
80 let display_types = types
81 .iter()
82 .map(|type_name| {
83 crate::ast::ColumnType::from_sql_name(type_name)
84 .map_or_else(|_| type_name.clone(), |column_type| column_type.sql_name())
85 })
86 .collect::<Vec<_>>();
87 format!("{name}({})", display_types.join(", "))
88}
89
90pub fn routine_signature_display(
92 catalog: &dyn names::RoutineNameCatalog,
93 name: &str,
94 types: &[String],
95) -> String {
96 let types = types
97 .iter()
98 .map(|type_name| catalog.routine_type_display(type_name))
99 .collect::<Vec<_>>();
100 format!("{name}({})", types.join(", "))
101}
102
103pub fn wrong_routine_kind_error(signature: &str, expected_kind: &str) -> SQLError {
105 SQLError::Routine {
106 sqlstate: "42809".into(),
107 message: format!("{signature} is not a {expected_kind}"),
108 }
109}
110
111pub fn ambiguous_routine_error(kind: &str, name: &str) -> SQLError {
113 SQLError::Diagnostic {
114 sqlstate: "42725".into(),
115 message: format!("{kind} name \"{name}\" is not unique"),
116 detail: None,
117 hint: Some(format!(
118 "Specify the argument list to select the {kind} unambiguously."
119 )),
120 }
121}
122
123pub fn alter_routine_kind_name(kind: AlterRoutineKind) -> &'static str {
124 match kind {
125 AlterRoutineKind::Function => "function",
126 AlterRoutineKind::Procedure => "procedure",
127 AlterRoutineKind::Routine => "routine",
128 }
129}
130
131pub fn alter_routine_kind_matches(kind: AlterRoutineKind, def: &CreateFunction) -> bool {
132 match kind {
133 AlterRoutineKind::Function => !def.is_procedure,
134 AlterRoutineKind::Procedure => def.is_procedure,
135 AlterRoutineKind::Routine => true,
136 }
137}
138
139pub fn require_routine_ownership(
141 kind: &str,
142 name: &str,
143 current_user_has_owner_privileges: bool,
144) -> Result<(), SQLError> {
145 if current_user_has_owner_privileges {
146 Ok(())
147 } else {
148 Err(SQLError::Routine {
149 sqlstate: "42501".into(),
150 message: format!("must be owner of {kind} {name}"),
151 })
152 }
153}