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 {
22            name,
23            binding,
24            args,
25            ..
26        } = expression
27        else {
28            return;
29        };
30        changed |= FunctionBinding::upgrade_legacy_serialized_dispatch(name, binding);
31        changed |= FunctionBinding::upgrade_legacy_array_slices(binding, args.len(), |index| {
32            matches!(
33                args[index],
34                crate::ScalarExpr::Literal(uqa_core::Value::Null)
35            )
36        });
37    });
38    plan.visit_sources_mut(&mut |source| match source {
39        crate::plan::SourcePlan::Function { binding, args, .. } => {
40            changed |= crate::semantics::upgrade_legacy_table_function_binding(binding, args.len());
41        }
42        crate::plan::SourcePlan::FunctionGroup { functions, .. } => {
43            for function in functions {
44                changed |= crate::semantics::upgrade_legacy_table_function_binding(
45                    &mut function.binding,
46                    function.args.len(),
47                );
48            }
49        }
50        _ => {}
51    });
52    changed
53}
54
55pub fn bind_stored_view_relations(
56    plan: &mut QueryPlan,
57    relations: &std::collections::BTreeSet<RelationIdentity>,
58) -> Result<(), String> {
59    bind_query_plan_relations(plan, &std::collections::BTreeSet::new(), &mut |reference| {
60        if let Some(canonical) = canonical_virtual_relation_reference(reference) {
61            return Ok(canonical);
62        }
63        let (schema, local_name) = RelationIdentity::parse_reference(reference)
64            .map_err(|error| format!("invalid stored view source `{reference}`: {error}"))?;
65        if let Some(schema) = schema {
66            let candidate = RelationIdentity::new(schema, local_name);
67            if relations.contains(&candidate) {
68                return Ok(candidate.qualified_name());
69            }
70        } else {
71            let candidates = relations
72                .iter()
73                .filter(|candidate| candidate.name == local_name)
74                .map(RelationIdentity::qualified_name)
75                .collect::<Vec<_>>();
76            match candidates.as_slice() {
77                [candidate] => return Ok(candidate.clone()),
78                [] => {}
79                _ => {
80                    return Err(format!(
81                        "ambiguous stored view source `{reference}` matches {}",
82                        candidates.join(", ")
83                    ));
84                }
85            }
86        }
87        Err(format!(
88            "stored view source relation `{reference}` does not exist"
89        ))
90    })
91}
92
93#[cfg(test)]
94mod tests;