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::CompositeRow { items, .. }
96 | ScalarExpr::And(items)
97 | ScalarExpr::Or(items) => {
98 for item in items {
99 collect_subquery_ids(item, output);
100 }
101 }
102 ScalarExpr::Func {
103 args,
104 order_by,
105 filter,
106 ..
107 } => {
108 for argument in args {
109 collect_subquery_ids(argument, output);
110 }
111 for order in order_by {
112 collect_subquery_ids(&order.expr, output);
113 }
114 if let Some(filter) = filter {
115 collect_subquery_ids(filter, output);
116 }
117 }
118 ScalarExpr::Binary { lhs, rhs, .. } => {
119 collect_subquery_ids(lhs, output);
120 collect_subquery_ids(rhs, output);
121 }
122 ScalarExpr::Not(inner)
123 | ScalarExpr::UnaryMinus(inner)
124 | ScalarExpr::IsNull { expr: inner, .. }
125 | ScalarExpr::Cast { expr: inner, .. }
126 | ScalarExpr::Collated { expr: inner, .. } => collect_subquery_ids(inner, output),
127 ScalarExpr::Between { expr, low, high } => {
128 collect_subquery_ids(expr, output);
129 collect_subquery_ids(low, output);
130 collect_subquery_ids(high, output);
131 }
132 ScalarExpr::InList { expr, list, .. } => {
133 collect_subquery_ids(expr, output);
134 for item in list {
135 collect_subquery_ids(item, output);
136 }
137 }
138 ScalarExpr::WindowCall {
139 args, spec, filter, ..
140 } => {
141 for argument in args {
142 collect_subquery_ids(argument, output);
143 }
144 if let Some(filter) = filter {
145 collect_subquery_ids(filter, output);
146 }
147 for partition in &spec.partition_by {
148 collect_subquery_ids(partition, output);
149 }
150 for order in &spec.order_by {
151 collect_subquery_ids(&order.expr, output);
152 }
153 if let Some(frame) = &spec.frame {
154 collect_frame_bound_subquery_ids(&frame.start, output);
155 collect_frame_bound_subquery_ids(&frame.end, output);
156 }
157 }
158 ScalarExpr::Case {
159 base,
160 when,
161 else_branch,
162 } => {
163 if let Some(base) = base {
164 collect_subquery_ids(base, output);
165 }
166 for (condition, result) in when {
167 collect_subquery_ids(condition, output);
168 collect_subquery_ids(result, output);
169 }
170 if let Some(branch) = else_branch {
171 collect_subquery_ids(branch, output);
172 }
173 }
174 ScalarExpr::Default
175 | ScalarExpr::Star
176 | ScalarExpr::QualifiedStar(_)
177 | ScalarExpr::Column(_)
178 | ScalarExpr::Position(_)
179 | ScalarExpr::InternalColumn(_)
180 | ScalarExpr::QualifiedColumn { .. }
181 | ScalarExpr::Literal(_)
182 | ScalarExpr::TypedLiteral { .. }
183 | ScalarExpr::Param(_) => {}
184 }
185}
186
187pub fn collect_frame_bound_subquery_ids(
188 bound: &crate::ScalarFrameBound,
189 output: &mut BTreeSet<usize>,
190) {
191 match bound {
192 crate::ScalarFrameBound::Preceding(expression)
193 | crate::ScalarFrameBound::Following(expression) => {
194 collect_subquery_ids(expression, output);
195 }
196 crate::ScalarFrameBound::UnboundedPreceding
197 | crate::ScalarFrameBound::UnboundedFollowing
198 | crate::ScalarFrameBound::CurrentRow => {}
199 }
200}