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