Skip to main content

uqa_sql/catalog/stored_view/
dependencies.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Select stored view dependencies and rewrite exact routine identities in their bound plans.
8
9use super::StoredView;
10use crate::{
11    ast::FunctionBinding,
12    binding::view_dependencies::{
13        query_plan_references_function, query_plan_references_relation,
14        query_plan_references_sequence, rewrite_query_plan_routine_identity,
15    },
16};
17use std::collections::{BTreeMap, BTreeSet};
18use uqa_core::RelationIdentity;
19
20/// Canonical bound sources make dependency checks exact; malformed in-memory plans remain conservative to prevent dangling DDL.
21pub fn views_depending_on_relation(
22    views: &BTreeMap<RelationIdentity, StoredView>,
23    target: &RelationIdentity,
24) -> Vec<String> {
25    let empty_ctes = BTreeSet::new();
26    let mut dependents = views
27        .iter()
28        .filter(|(relation, view)| {
29            *relation != target && query_plan_references_relation(&view.query, target, &empty_ctes)
30        })
31        .map(|(relation, _)| relation.qualified_name())
32        .collect::<Vec<_>>();
33    dependents.sort_unstable();
34    dependents
35}
36
37pub fn views_depending_on_sequence(
38    views: &BTreeMap<RelationIdentity, StoredView>,
39    target: &RelationIdentity,
40) -> Vec<String> {
41    let mut dependents = views
42        .iter()
43        .filter(|(_, view)| query_plan_references_sequence(&view.query, target))
44        .map(|(relation, _)| relation.qualified_name())
45        .collect::<Vec<_>>();
46    dependents.sort_unstable();
47    dependents
48}
49
50/// Return type is excluded from the exact non-builtin routine identity.
51pub fn views_depending_on_function(
52    views: &BTreeMap<RelationIdentity, StoredView>,
53    target: &FunctionBinding,
54) -> Vec<String> {
55    let mut dependents = views
56        .iter()
57        .filter(|(_, view)| query_plan_references_function(&view.query, target))
58        .map(|(relation, _)| relation.qualified_name())
59        .collect::<Vec<_>>();
60    dependents.sort_unstable();
61    dependents
62}
63
64/// Give the bound types that views embed, in typed constants and materialized column types, the current name of the user-defined type `oid`. Returns the views that changed.
65pub fn rewrite_view_type_references(
66    views: &mut BTreeMap<RelationIdentity, StoredView>,
67    oid: u32,
68    identity: &RelationIdentity,
69) -> Vec<RelationIdentity> {
70    let mut changed = Vec::new();
71    for (relation, view) in views {
72        let mut view_changed = false;
73        view.query.rewrite_scalar_expressions(&mut |expression| {
74            if let crate::ir::ScalarExpr::TypedLiteral {
75                bound_type: Some(ty),
76                ..
77            }
78            | crate::ir::ScalarExpr::Collated { ty, .. } = expression
79            {
80                view_changed |= ty.rename_user_type(oid, identity);
81            }
82        });
83        for ty in view.materialized_column_types.iter_mut().flatten() {
84            view_changed |= ty.rename_user_type(oid, identity);
85        }
86        if view_changed {
87            changed.push(relation.clone());
88        }
89    }
90    changed
91}
92
93pub fn rewrite_view_routine_identity(
94    views: &mut BTreeMap<RelationIdentity, StoredView>,
95    target: &FunctionBinding,
96    new_name: &str,
97) -> Vec<RelationIdentity> {
98    let mut changed = Vec::new();
99    for (relation, view) in views {
100        if rewrite_query_plan_routine_identity(&mut view.query, target, new_name) {
101            changed.push(relation.clone());
102        }
103    }
104    changed
105}