uqa_sql/prepared/
dependencies.rs1use crate::{ast::FunctionBinding, ColumnType, ScalarExpr};
10use std::{
11 any::Any,
12 collections::{BTreeMap, BTreeSet},
13 fmt,
14 sync::Arc,
15};
16use uqa_core::Value;
17
18#[derive(Clone, Debug, Default, PartialEq, Eq)]
20pub struct PreparedAnalysisDependencies {
21 pub relations: BTreeSet<u32>,
22 pub routines: BTreeSet<[u8; 16]>,
23}
24
25#[derive(Clone)]
27pub struct PreparedDependencyRevision(Arc<dyn RevisionEquality>);
28
29trait RevisionEquality: Send + Sync {
30 fn as_any(&self) -> &dyn Any;
31 fn equals(&self, other: &dyn RevisionEquality) -> bool;
32}
33
34impl<T: Eq + Send + Sync + 'static> RevisionEquality for T {
35 fn as_any(&self) -> &dyn Any {
36 self
37 }
38
39 fn equals(&self, other: &dyn RevisionEquality) -> bool {
40 other.as_any().downcast_ref::<Self>() == Some(self)
41 }
42}
43
44impl PreparedDependencyRevision {
45 #[must_use]
46 pub fn new<T: Eq + Send + Sync + 'static>(revision: T) -> Self {
47 Self(Arc::new(revision))
48 }
49}
50
51impl PartialEq for PreparedDependencyRevision {
52 fn eq(&self, other: &Self) -> bool {
53 Arc::ptr_eq(&self.0, &other.0) || self.0.equals(other.0.as_ref())
54 }
55}
56
57impl Eq for PreparedDependencyRevision {}
58
59impl fmt::Debug for PreparedDependencyRevision {
60 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61 formatter
62 .debug_struct("PreparedDependencyRevision")
63 .finish_non_exhaustive()
64 }
65}
66
67#[derive(Clone, Debug, Default, PartialEq, Eq)]
69pub struct PreparedDependencySnapshot {
70 pub global_catalog: Option<PreparedDependencyRevision>,
72 pub relations: BTreeMap<u32, Option<PreparedDependencyRevision>>,
73 pub routines: BTreeMap<[u8; 16], Option<PreparedDependencyRevision>>,
74}
75
76impl PreparedAnalysisDependencies {
77 pub(crate) fn include_routine(&mut self, binding: &FunctionBinding) {
78 if !binding.builtin {
79 if let Some(identity) = binding.object_id {
80 self.routines.insert(identity);
81 }
82 }
83 }
84
85 pub(crate) fn include_expression(&mut self, expression: &ScalarExpr) {
87 expression.visit(&mut |expression| match expression {
88 ScalarExpr::TypedLiteral {
89 value: Value::Int(oid),
90 ty,
91 bound_type,
92 parameter_index: None,
93 } => {
94 let parsed;
95 let ty = if let Some(ty) = bound_type.as_ref() {
96 Some(ty)
97 } else {
98 parsed = ColumnType::from_sql_name(ty).ok();
99 parsed.as_ref()
100 };
101 if matches!(ty, Some(ColumnType::Regclass | ColumnType::Oid)) {
102 if let Ok(oid) = u32::try_from(*oid) {
103 self.relations.insert(oid);
104 }
105 }
106 }
107 ScalarExpr::Func {
108 binding: Some(binding),
109 ..
110 } => self.include_routine(binding),
111 _ => {}
112 });
113 }
114}
115
116#[cfg(test)]
117mod tests;