uqa_sql/schema/
dependencies.rs1#[expect(
10 clippy::too_many_lines,
11 reason = "one traversal covers every stored expression child"
12)]
13pub fn walk_schema_expr_mut(
14 expression: &mut crate::ast::Expr,
15 visit: &mut impl FnMut(&mut crate::ast::Expr) -> Result<(), String>,
16) -> Result<(), String> {
17 use crate::ast::{Expr, FrameBound};
18
19 visit(expression)?;
20 match expression {
21 Expr::Func {
22 args,
23 order_by,
24 filter,
25 ..
26 } => {
27 for argument in args {
28 walk_schema_expr_mut(argument, visit)?;
29 }
30 for order in order_by {
31 walk_schema_expr_mut(&mut order.expr, visit)?;
32 }
33 if let Some(filter) = filter {
34 walk_schema_expr_mut(filter, visit)?;
35 }
36 }
37 Expr::Array(items)
38 | Expr::Row(items)
39 | Expr::CompositeRow { items, .. }
40 | Expr::And(items)
41 | Expr::Or(items) => {
42 for item in items {
43 walk_schema_expr_mut(item, visit)?;
44 }
45 }
46 Expr::Binary { lhs, rhs, .. } => {
47 walk_schema_expr_mut(lhs, visit)?;
48 walk_schema_expr_mut(rhs, visit)?;
49 }
50 Expr::Not(inner)
51 | Expr::UnaryMinus(inner)
52 | Expr::IsNull { expr: inner, .. }
53 | Expr::Cast { expr: inner, .. } => {
54 walk_schema_expr_mut(inner, visit)?;
55 }
56 Expr::Between { expr, low, high } => {
57 walk_schema_expr_mut(expr, visit)?;
58 walk_schema_expr_mut(low, visit)?;
59 walk_schema_expr_mut(high, visit)?;
60 }
61 Expr::InList { expr, list, .. } => {
62 walk_schema_expr_mut(expr, visit)?;
63 for item in list {
64 walk_schema_expr_mut(item, visit)?;
65 }
66 }
67 Expr::WindowCall {
68 args, spec, filter, ..
69 } => {
70 for expression in args
71 .iter_mut()
72 .chain(filter.as_deref_mut())
73 .chain(&mut spec.partition_by)
74 .chain(spec.order_by.iter_mut().map(|order| &mut order.expr))
75 {
76 walk_schema_expr_mut(expression, visit)?;
77 }
78 for bound in spec
79 .frame
80 .iter_mut()
81 .flat_map(|frame| [&mut frame.start, &mut frame.end])
82 {
83 if let FrameBound::Preceding(expression) | FrameBound::Following(expression) = bound
84 {
85 walk_schema_expr_mut(expression, visit)?;
86 }
87 }
88 }
89 Expr::Case {
90 base,
91 when,
92 else_branch,
93 } => {
94 if let Some(base) = base {
95 walk_schema_expr_mut(base, visit)?;
96 }
97 for (condition, result) in when {
98 walk_schema_expr_mut(condition, visit)?;
99 walk_schema_expr_mut(result, visit)?;
100 }
101 if let Some(else_branch) = else_branch {
102 walk_schema_expr_mut(else_branch, visit)?;
103 }
104 }
105 Expr::ScalarSubquery(_) | Expr::Exists { .. } | Expr::InSubquery { .. } => {
106 return Err(
107 "schema expression contains a subquery whose dependencies cannot be rewritten safely"
108 .into(),
109 );
110 }
111 Expr::Default
112 | Expr::Star
113 | Expr::QualifiedStar(_)
114 | Expr::Column(_)
115 | Expr::QualifiedColumn { .. }
116 | Expr::InternalColumn(_)
117 | Expr::Literal(_)
118 | Expr::TypedLiteral { .. }
119 | Expr::Param(_) => {}
120 }
121 Ok(())
122}
123
124pub fn schema_expr_references_column(expression: &crate::ast::Expr, column: &str) -> bool {
125 let mut expression = expression.clone();
126 let mut referenced = false;
127 let result = walk_schema_expr_mut(&mut expression, &mut |node| {
128 referenced |= match node {
129 crate::ast::Expr::Star | crate::ast::Expr::QualifiedStar(_) => true,
130 crate::ast::Expr::Column(name)
131 | crate::ast::Expr::QualifiedColumn { column: name, .. } => name == column,
132 _ => false,
133 };
134 Ok(())
135 });
136 result.is_err() || referenced
137}
138
139pub mod oid_alias;
140pub mod regclass;
141pub mod registration;
142pub mod rewrites;