uqa_sql/semantics/
source_shape.rs1use super::from_qualifier_set;
10use crate::plan::SourcePlan;
11use crate::ScalarExpr;
12use std::collections::BTreeSet;
13
14pub fn outer_join_nullable_qualifiers(from: &SourcePlan) -> BTreeSet<String> {
22 let SourcePlan::Join {
23 left,
24 right,
25 kind,
26 alias,
27 ..
28 } = from
29 else {
30 return BTreeSet::new();
31 };
32 let left_nullable = outer_join_nullable_qualifiers(left);
33 let right_nullable = outer_join_nullable_qualifiers(right);
34 if let Some(alias) = alias {
35 let nullable = matches!(
36 kind,
37 crate::ast::JoinKind::Left | crate::ast::JoinKind::Right | crate::ast::JoinKind::Full
38 ) || !left_nullable.is_empty()
39 || !right_nullable.is_empty();
40 return if nullable {
41 BTreeSet::from([alias.clone()])
42 } else {
43 BTreeSet::new()
44 };
45 }
46 let mut nullable = left_nullable;
47 nullable.extend(right_nullable);
48 match kind {
49 crate::ast::JoinKind::Left => nullable.extend(from_qualifier_set(right)),
50 crate::ast::JoinKind::Right => nullable.extend(from_qualifier_set(left)),
51 crate::ast::JoinKind::Full => {
52 nullable.extend(from_qualifier_set(left));
53 nullable.extend(from_qualifier_set(right));
54 }
55 crate::ast::JoinKind::Inner | crate::ast::JoinKind::Cross => {}
56 }
57 nullable
58}
59
60pub fn collect_from_qualifiers(from: &SourcePlan, out: &mut Vec<String>) {
61 match from {
62 SourcePlan::Join {
63 left, right, alias, ..
64 } => {
65 if let Some(alias) = alias {
66 out.push(alias.clone());
67 } else {
68 collect_from_qualifiers(left, out);
69 collect_from_qualifiers(right, out);
70 }
71 }
72 SourcePlan::Table { .. }
73 | SourcePlan::Values { .. }
74 | SourcePlan::Function { .. }
75 | SourcePlan::FunctionGroup { .. }
76 | SourcePlan::Subquery { .. } => {
77 if let Some(qualifier) = from.visible_qualifier() {
78 out.push(qualifier.to_string());
79 }
80 }
81 }
82}
83
84pub fn collect_subquery_ids(expression: &ScalarExpr, output: &mut BTreeSet<usize>) {
85 match expression {
86 ScalarExpr::ScalarSubquery(id) | ScalarExpr::Exists { subquery: id, .. } => {
87 output.insert(*id);
88 }
89 ScalarExpr::InSubquery { expr, subquery, .. } => {
90 collect_subquery_ids(expr, output);
91 output.insert(*subquery);
92 }
93 ScalarExpr::Array(items)
94 | ScalarExpr::Row(items)
95 | ScalarExpr::And(items)
96 | ScalarExpr::Or(items) => {
97 for item in items {
98 collect_subquery_ids(item, output);
99 }
100 }
101 ScalarExpr::Func {
102 args,
103 order_by,
104 filter,
105 ..
106 } => {
107 for argument in args {
108 collect_subquery_ids(argument, output);
109 }
110 for order in order_by {
111 collect_subquery_ids(&order.expr, output);
112 }
113 if let Some(filter) = filter {
114 collect_subquery_ids(filter, output);
115 }
116 }
117 ScalarExpr::Binary { lhs, rhs, .. } => {
118 collect_subquery_ids(lhs, output);
119 collect_subquery_ids(rhs, output);
120 }
121 ScalarExpr::Not(inner)
122 | ScalarExpr::UnaryMinus(inner)
123 | ScalarExpr::IsNull { expr: inner, .. }
124 | ScalarExpr::Cast { expr: inner, .. } => collect_subquery_ids(inner, output),
125 ScalarExpr::Between { expr, low, high } => {
126 collect_subquery_ids(expr, output);
127 collect_subquery_ids(low, output);
128 collect_subquery_ids(high, output);
129 }
130 ScalarExpr::InList { expr, list, .. } => {
131 collect_subquery_ids(expr, output);
132 for item in list {
133 collect_subquery_ids(item, output);
134 }
135 }
136 ScalarExpr::WindowCall { args, spec, .. } => {
137 for argument in args {
138 collect_subquery_ids(argument, output);
139 }
140 for partition in &spec.partition_by {
141 collect_subquery_ids(partition, output);
142 }
143 for order in &spec.order_by {
144 collect_subquery_ids(&order.expr, output);
145 }
146 if let Some(frame) = &spec.frame {
147 collect_frame_bound_subquery_ids(&frame.start, output);
148 collect_frame_bound_subquery_ids(&frame.end, output);
149 }
150 }
151 ScalarExpr::Case {
152 base,
153 when,
154 else_branch,
155 } => {
156 if let Some(base) = base {
157 collect_subquery_ids(base, output);
158 }
159 for (condition, result) in when {
160 collect_subquery_ids(condition, output);
161 collect_subquery_ids(result, output);
162 }
163 if let Some(branch) = else_branch {
164 collect_subquery_ids(branch, output);
165 }
166 }
167 ScalarExpr::Default
168 | ScalarExpr::Star
169 | ScalarExpr::QualifiedStar(_)
170 | ScalarExpr::Column(_)
171 | ScalarExpr::Position(_)
172 | ScalarExpr::InternalColumn(_)
173 | ScalarExpr::QualifiedColumn { .. }
174 | ScalarExpr::Literal(_)
175 | ScalarExpr::TypedLiteral { .. }
176 | ScalarExpr::Param(_) => {}
177 }
178}
179
180pub fn collect_frame_bound_subquery_ids(
181 bound: &crate::ScalarFrameBound,
182 output: &mut BTreeSet<usize>,
183) {
184 match bound {
185 crate::ScalarFrameBound::Preceding(expression)
186 | crate::ScalarFrameBound::Following(expression) => {
187 collect_subquery_ids(expression, output);
188 }
189 crate::ScalarFrameBound::UnboundedPreceding
190 | crate::ScalarFrameBound::UnboundedFollowing
191 | crate::ScalarFrameBound::CurrentRow => {}
192 }
193}