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