Skip to main content

uqa_sql/binding/view_dependencies/
restoration.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Restore legacy view source names and scalar dispatches from explicit catalog identities.
8use super::{bind_query_plan_relations, canonical_virtual_relation_reference};
9use crate::{ast::FunctionBinding, plan::QueryPlan};
10use uqa_core::RelationIdentity;
11
12pub fn upgrade_legacy_view_dispatches(plan: &mut QueryPlan) -> bool {
13    let mut changed = false;
14    plan.rewrite_scalar_expressions(&mut |expression| {
15        let crate::ScalarExpr::Func { name, binding, .. } = expression else {
16            return;
17        };
18        changed |= FunctionBinding::upgrade_legacy_serialized_dispatch(name, binding);
19    });
20    plan.visit_sources_mut(&mut |source| match source {
21        crate::plan::SourcePlan::Function { binding, args, .. } => {
22            changed |= crate::semantics::upgrade_legacy_table_function_binding(binding, args.len());
23        }
24        crate::plan::SourcePlan::FunctionGroup { functions, .. } => {
25            for function in functions {
26                changed |= crate::semantics::upgrade_legacy_table_function_binding(
27                    &mut function.binding,
28                    function.args.len(),
29                );
30            }
31        }
32        _ => {}
33    });
34    changed
35}
36
37pub fn bind_stored_view_relations(
38    plan: &mut QueryPlan,
39    relations: &std::collections::BTreeSet<RelationIdentity>,
40) -> Result<(), String> {
41    bind_query_plan_relations(plan, &std::collections::BTreeSet::new(), &mut |reference| {
42        if let Some(canonical) = canonical_virtual_relation_reference(reference) {
43            return Ok(canonical);
44        }
45        let (schema, local_name) = RelationIdentity::parse_reference(reference)
46            .map_err(|error| format!("invalid stored view source `{reference}`: {error}"))?;
47        if let Some(schema) = schema {
48            let candidate = RelationIdentity::new(schema, local_name);
49            if relations.contains(&candidate) {
50                return Ok(candidate.qualified_name());
51            }
52        } else {
53            let candidates = relations
54                .iter()
55                .filter(|candidate| candidate.name == local_name)
56                .map(RelationIdentity::qualified_name)
57                .collect::<Vec<_>>();
58            match candidates.as_slice() {
59                [candidate] => return Ok(candidate.clone()),
60                [] => {}
61                _ => {
62                    return Err(format!(
63                        "ambiguous stored view source `{reference}` matches {}",
64                        candidates.join(", ")
65                    ));
66                }
67            }
68        }
69        Err(format!(
70            "stored view source relation `{reference}` does not exist"
71        ))
72    })
73}
74
75#[cfg(test)]
76mod tests;