Skip to main content

uqa_sql/routines/lifecycle/
lookup.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Lookup exact stored routine identities and visible or unshadowed overload candidates.
8
9use super::RoutineRegistry;
10use crate::{
11    ast::FunctionBinding,
12    routines::{routine_signature_types, SQLUserFunction},
13};
14use std::{collections::BTreeSet, sync::Arc};
15
16pub fn lookup_sql_functions_by_keys(
17    registry: &RoutineRegistry,
18    keys: impl IntoIterator<Item = String>,
19) -> Option<Vec<Arc<SQLUserFunction>>> {
20    let mut visible = Vec::new();
21    let mut seen = BTreeSet::new();
22    for key in keys {
23        let Some(overloads) = registry.get(&key) else {
24            continue;
25        };
26        for function in overloads {
27            let identity = (
28                routine_signature_types(&function.def),
29                function.def.is_procedure,
30            );
31            if seen.insert(identity) {
32                visible.push(function.clone());
33            }
34        }
35    }
36    (!visible.is_empty()).then_some(visible)
37}
38
39pub fn lookup_bound_sql_functions_by_binding(
40    registry: &RoutineRegistry,
41    binding: &FunctionBinding,
42) -> Option<Vec<Arc<SQLUserFunction>>> {
43    let Some(object_id) = binding.object_id else {
44        return lookup_sql_functions_by_keys(registry, std::iter::once(binding.name.clone()));
45    };
46    let matches = registry
47        .values()
48        .flat_map(|overloads| overloads.iter())
49        .filter(|function| function.def.object_id == Some(object_id))
50        .cloned()
51        .collect::<Vec<_>>();
52    (!matches.is_empty()).then_some(matches)
53}
54
55/// Named notation needs candidates before later schemas are hidden by equal declared signatures.
56pub fn lookup_sql_routine_candidates_by_keys(
57    registry: &RoutineRegistry,
58    keys: impl IntoIterator<Item = String>,
59) -> Option<Vec<Arc<SQLUserFunction>>> {
60    let candidates = keys
61        .into_iter()
62        .filter_map(|key| registry.get(&key))
63        .flat_map(|overloads| overloads.iter().cloned())
64        .collect::<Vec<_>>();
65    (!candidates.is_empty()).then_some(candidates)
66}
67
68pub fn lookup_bound_sql_routine_candidates_by_binding(
69    registry: &RoutineRegistry,
70    binding: &FunctionBinding,
71) -> Option<Vec<Arc<SQLUserFunction>>> {
72    if binding.object_id.is_some() {
73        lookup_bound_sql_functions_by_binding(registry, binding)
74    } else {
75        lookup_sql_routine_candidates_by_keys(registry, std::iter::once(binding.name.clone()))
76    }
77}