uqa_sql/routines/lifecycle/
rename.rs1use super::RoutineRegistry;
10use crate::{
11 ast::{CreateFunction, FunctionBinding, FunctionBody, RenameRoutineStmt},
12 routines::{routine_signature_types, SQLUserFunction},
13 SQLError,
14};
15use std::{collections::BTreeMap, sync::Arc};
16use uqa_core::RelationIdentity;
17
18pub struct RoutineRenameTarget {
19 pub old_name: String,
20 pub new_name: String,
21 pub position: usize,
22 pub binding: FunctionBinding,
23}
24
25pub fn routine_rename_identity(name: &str) -> Result<RelationIdentity, SQLError> {
26 RelationIdentity::from_legacy_name(name)
27 .map_err(|error| SQLError::Internal(format!("decode routine identity `{name}`: {error}")))
28}
29
30pub fn finish_routine_rename_target(
31 stmt: &RenameRoutineStmt,
32 old_name: String,
33 position: usize,
34 definition: &CreateFunction,
35 old_identity: &RelationIdentity,
36 registry: &RoutineRegistry,
37) -> Result<RoutineRenameTarget, SQLError> {
38 let signature = routine_signature_types(definition);
39 let new_name = routine_rename_destination(stmt, old_identity, &signature, registry)?;
40 let object_id = definition.object_id.ok_or_else(|| {
41 SQLError::Internal(format!(
42 "routine `{old_name}` has no catalog object identity"
43 ))
44 })?;
45 Ok(RoutineRenameTarget {
46 old_name: old_name.clone(),
47 new_name,
48 position,
49 binding: FunctionBinding {
50 object_id: Some(object_id),
51 name: old_name,
52 argument_types: signature,
53 builtin: false,
54 dispatch: None,
55 invocation: None,
56 composite_field: None,
57 resolution_error: None,
58 },
59 })
60}
61
62fn routine_rename_destination(
63 stmt: &RenameRoutineStmt,
64 old_identity: &RelationIdentity,
65 signature: &[String],
66 registry: &BTreeMap<String, Vec<Arc<SQLUserFunction>>>,
67) -> Result<String, SQLError> {
68 let (new_schema, new_local_name) =
69 RelationIdentity::parse_reference(&stmt.new_name).map_err(|error| SQLError::Routine {
70 sqlstate: "42602".into(),
71 message: format!("invalid routine name `{}`: {error}", stmt.new_name),
72 })?;
73 if new_schema.is_some() {
74 return Err(SQLError::Routine {
75 sqlstate: "42601".into(),
76 message: "ALTER ROUTINE RENAME TO requires an unqualified new name".into(),
77 });
78 }
79 let new_name = RelationIdentity::new(&old_identity.schema, new_local_name).qualified_name();
80 if registry.get(&new_name).is_some_and(|overloads| {
81 overloads
82 .iter()
83 .any(|function| routine_signature_types(&function.def) == signature)
84 }) {
85 return Err(SQLError::Routine {
86 sqlstate: "42723".into(),
87 message: format!(
88 "function \"{}\" already exists with same argument types",
89 RelationIdentity::from_legacy_name(&new_name)
90 .map_or_else(|_| new_name.clone(), |identity| identity.name)
91 ),
92 });
93 }
94 Ok(new_name)
95}
96
97pub fn move_routine_registry_entry(
98 mut registry: BTreeMap<String, Vec<Arc<SQLUserFunction>>>,
99 target: &RoutineRenameTarget,
100) -> Result<BTreeMap<String, Vec<Arc<SQLUserFunction>>>, SQLError> {
101 let old_overloads = registry.get_mut(&target.old_name).ok_or_else(|| {
102 SQLError::Internal(format!(
103 "resolved ALTER routine registry entry `{}` disappeared before rename",
104 target.old_name
105 ))
106 })?;
107 let renamed = old_overloads.remove(target.position);
108 if old_overloads.is_empty() {
109 registry.remove(&target.old_name);
110 }
111 let mut renamed_definition = renamed.def.clone();
112 renamed_definition.name.clone_from(&target.new_name);
113 let new_overloads = registry.entry(target.new_name.clone()).or_default();
114 new_overloads.push(Arc::new(SQLUserFunction::new(
115 renamed_definition,
116 renamed.body.clone(),
117 )));
118 new_overloads.sort_by(|left, right| {
119 routine_signature_types(&left.def)
120 .cmp(&routine_signature_types(&right.def))
121 .then_with(|| left.def.is_procedure.cmp(&right.def.is_procedure))
122 });
123 Ok(registry)
124}
125
126pub fn rewrite_routine_owned_dependency_identity(
127 def: &mut CreateFunction,
128 target: &FunctionBinding,
129 new_name: &str,
130) -> Result<bool, SQLError> {
131 let mut changed = false;
132 for default in def
133 .params
134 .iter_mut()
135 .filter_map(|parameter| parameter.default.as_mut())
136 {
137 changed |= crate::catalog::stored_ast::rewrite_expression_routine_identity(
138 default, target, new_name,
139 )?;
140 }
141 if let FunctionBody::Statements(statements) = &mut def.body {
142 for statement in statements {
143 changed |= crate::catalog::stored_ast::rewrite_statement_routine_identity(
144 statement, target, new_name,
145 )?;
146 }
147 }
148 Ok(changed)
149}