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
12/// Upgrade stored expression identities and compound range predicates before a restored view can be planned or evaluated.
13pub fn upgrade_legacy_view_expressions(plan: &mut QueryPlan) -> Result<bool, crate::SQLError> {
14    let dispatches = upgrade_legacy_view_dispatches(plan);
15    Ok(crate::type_resolution::between::restore_query(plan)? || dispatches)
16}
17
18pub fn upgrade_legacy_view_dispatches(plan: &mut QueryPlan) -> bool {
19    let mut changed = false;
20    plan.rewrite_scalar_expressions(&mut |expression| {
21        let crate::ScalarExpr::Func { name, binding, .. } = expression else {
22            return;
23        };
24        changed |= FunctionBinding::upgrade_legacy_serialized_dispatch(name, binding);
25    });
26    plan.visit_sources_mut(&mut |source| match source {
27        crate::plan::SourcePlan::Function { binding, args, .. } => {
28            changed |= crate::semantics::upgrade_legacy_table_function_binding(binding, args.len());
29        }
30        crate::plan::SourcePlan::FunctionGroup { functions, .. } => {
31            for function in functions {
32                changed |= crate::semantics::upgrade_legacy_table_function_binding(
33                    &mut function.binding,
34                    function.args.len(),
35                );
36            }
37        }
38        _ => {}
39    });
40    changed
41}
42
43pub fn bind_stored_view_relations(
44    plan: &mut QueryPlan,
45    relations: &std::collections::BTreeSet<RelationIdentity>,
46) -> Result<(), String> {
47    bind_query_plan_relations(plan, &std::collections::BTreeSet::new(), &mut |reference| {
48        if let Some(canonical) = canonical_virtual_relation_reference(reference) {
49            return Ok(canonical);
50        }
51        let (schema, local_name) = RelationIdentity::parse_reference(reference)
52            .map_err(|error| format!("invalid stored view source `{reference}`: {error}"))?;
53        if let Some(schema) = schema {
54            let candidate = RelationIdentity::new(schema, local_name);
55            if relations.contains(&candidate) {
56                return Ok(candidate.qualified_name());
57            }
58        } else {
59            let candidates = relations
60                .iter()
61                .filter(|candidate| candidate.name == local_name)
62                .map(RelationIdentity::qualified_name)
63                .collect::<Vec<_>>();
64            match candidates.as_slice() {
65                [candidate] => return Ok(candidate.clone()),
66                [] => {}
67                _ => {
68                    return Err(format!(
69                        "ambiguous stored view source `{reference}` matches {}",
70                        candidates.join(", ")
71                    ));
72                }
73            }
74        }
75        Err(format!(
76            "stored view source relation `{reference}` does not exist"
77        ))
78    })
79}
80
81#[cfg(test)]
82mod tests;