uqa_sql/routines/lifecycle/
names.rs1use crate::catalog::roles::RoleReference;
10use crate::{catalog::security::BoundSchemaSecurity, SQLError};
11use uqa_core::RelationIdentity;
12
13pub trait RoutineNameCatalog {
14 fn schema_security(&self, schema: &str) -> Option<BoundSchemaSecurity>;
15 fn current_role(&self) -> RoleReference;
16 fn search_path(&self) -> Vec<String>;
17 fn require_schema_usage(&self, schema: &str, role: &RoleReference) -> Result<(), SQLError>;
18 fn schema_has_usage(&self, schema: &str, role: &RoleReference) -> bool;
19}
20
21pub fn routine_lookup_keys(
22 catalog: &dyn RoutineNameCatalog,
23 name: &str,
24) -> Result<Vec<String>, SQLError> {
25 let (schema, local_name) =
26 RelationIdentity::parse_reference(name).map_err(|error| SQLError::Routine {
27 sqlstate: "42602".into(),
28 message: format!("invalid routine name `{name}`: {error}"),
29 })?;
30 if let Some(schema) = schema {
31 if catalog.schema_security(&schema).is_none() {
32 return Err(SQLError::Routine {
33 sqlstate: "3F000".into(),
34 message: format!("schema \"{schema}\" does not exist"),
35 });
36 }
37 catalog.require_schema_usage(&schema, &catalog.current_role())?;
38 return Ok(vec![
39 RelationIdentity::new(schema, local_name).qualified_name()
40 ]);
41 }
42 let current_user = catalog.current_role();
43 let search_path = catalog.search_path();
44 Ok(search_path
45 .into_iter()
46 .filter(|schema| {
47 catalog.schema_security(schema).is_some()
48 && catalog.schema_has_usage(schema, ¤t_user)
49 })
50 .map(|schema| RelationIdentity::new(schema, &local_name).qualified_name())
51 .collect())
52}
53
54pub fn routine_lookup_keys_for_analysis(
56 catalog: &dyn RoutineNameCatalog,
57 name: &str,
58) -> Result<Option<Vec<String>>, SQLError> {
59 match routine_lookup_keys(catalog, name) {
60 Err(error) if crate::routines::is_routine_namespace_lookup_error(&error) => Ok(None),
61 result => result.map(Some),
62 }
63}