uqa_sql/schema/domains/
dependencies.rs1use crate::catalog::domain::DomainCatalog;
10use crate::expr::composites::{descriptor, CompositeTypeCatalog};
11use crate::{ColumnType, SQLError};
12use std::collections::BTreeSet;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum DomainColumnDependency {
16 None,
17 Direct,
19 Container,
21}
22
23pub fn column_domain_dependency(
25 ty: &ColumnType,
26 target: u32,
27 domains: &dyn DomainCatalog,
28 composites: &dyn CompositeTypeCatalog,
29) -> Result<DomainColumnDependency, SQLError> {
30 Dependencies {
31 target,
32 domains,
33 composites,
34 visited: BTreeSet::new(),
35 }
36 .classify(ty)
37}
38
39struct Dependencies<'a> {
40 target: u32,
41 domains: &'a dyn DomainCatalog,
42 composites: &'a dyn CompositeTypeCatalog,
43 visited: BTreeSet<u32>,
44}
45
46impl Dependencies<'_> {
47 fn classify(&mut self, ty: &ColumnType) -> Result<DomainColumnDependency, SQLError> {
48 match ty {
49 ColumnType::Domain { oid, .. } => {
50 if *oid == self.target {
51 return Ok(DomainColumnDependency::Direct);
52 }
53 if !self.visited.insert(*oid) {
54 return Ok(DomainColumnDependency::None);
55 }
56 let domain = self.domains.domain_by_oid(*oid).ok_or_else(|| {
57 SQLError::Internal(format!(
58 "domain type OID {oid} is not available in the statement catalog"
59 ))
60 })?;
61 self.classify(&domain.definition.base)
62 }
63 ColumnType::Array(element) => self.container(element),
64 ColumnType::Composite(reference) => {
65 if !self.visited.insert(reference.oid) {
66 return Ok(DomainColumnDependency::None);
67 }
68 let descriptor = descriptor(Some(self.composites), reference.oid)?;
69 for attribute in &descriptor.attributes {
70 if self.container(&attribute.ty)? == DomainColumnDependency::Container {
71 return Ok(DomainColumnDependency::Container);
72 }
73 }
74 Ok(DomainColumnDependency::None)
75 }
76 _ => Ok(DomainColumnDependency::None),
77 }
78 }
79
80 fn container(&mut self, ty: &ColumnType) -> Result<DomainColumnDependency, SQLError> {
81 self.classify(ty).map(|dependency| match dependency {
82 DomainColumnDependency::None => DomainColumnDependency::None,
83 DomainColumnDependency::Direct | DomainColumnDependency::Container => {
84 DomainColumnDependency::Container
85 }
86 })
87 }
88}
89
90#[cfg(test)]
91mod tests;