1use super::*;
9
10impl BoundExpr {
11 pub fn affinity(&self) -> Option<Affinity> {
17 match self {
18 BoundExpr::Column { affinity, .. } => Some(*affinity),
19 BoundExpr::Cast { affinity, .. } => Some(*affinity),
20 BoundExpr::Generated { affinity, .. } => Some(*affinity),
21 BoundExpr::Rowid { .. } => Some(Affinity::Integer),
22 BoundExpr::Collate { operand, .. } => operand.affinity(),
23 BoundExpr::Subquery {
27 kind: SubqueryKind::Scalar,
28 block,
29 ..
30 } => block.scalar_affinity(),
31 _ => None,
32 }
33 }
34
35 pub fn is_constant(&self) -> bool {
37 match self {
38 BoundExpr::Null
39 | BoundExpr::Integer(_)
40 | BoundExpr::Real(_)
41 | BoundExpr::Text(_)
42 | BoundExpr::Blob(_)
43 | BoundExpr::Parameter(_) => true,
44 BoundExpr::Raise { .. }
47 | BoundExpr::Column { .. }
48 | BoundExpr::Generated { .. }
49 | BoundExpr::Rowid { .. }
50 | BoundExpr::External { .. }
51 | BoundExpr::VirtualFunction { .. }
52 | BoundExpr::Aggregate { .. }
53 | BoundExpr::WindowRef { .. }
54 | BoundExpr::SorterColumn { .. } => false,
55 BoundExpr::Unary { operand, .. } => operand.is_constant(),
56 BoundExpr::Collate { operand, .. } => operand.is_constant(),
57 BoundExpr::Json { arguments, .. } => arguments.iter().all(BoundExpr::is_constant),
58 BoundExpr::Not(operand) => operand.is_constant(),
59 BoundExpr::IsNull { operand, .. } => operand.is_constant(),
60 BoundExpr::Cast { operand, .. } => operand.is_constant(),
61 BoundExpr::Arithmetic { left, right, .. }
62 | BoundExpr::Compare { left, right, .. }
63 | BoundExpr::Is { left, right, .. } => left.is_constant() && right.is_constant(),
64 BoundExpr::And(left, right) | BoundExpr::Or(left, right) => {
65 left.is_constant() && right.is_constant()
66 }
67 BoundExpr::Between {
68 operand, low, high, ..
69 } => operand.is_constant() && low.is_constant() && high.is_constant(),
70 BoundExpr::InList { operand, list, .. } => {
71 operand.is_constant() && list.iter().all(BoundExpr::is_constant)
72 }
73 BoundExpr::Case {
74 operand,
75 branches,
76 otherwise,
77 ..
78 } => {
79 operand.as_ref().is_none_or(|e| e.is_constant())
80 && branches
81 .iter()
82 .all(|(when, then)| when.is_constant() && then.is_constant())
83 && otherwise.as_ref().is_none_or(|e| e.is_constant())
84 }
85 BoundExpr::Pattern {
86 operand,
87 pattern,
88 escape,
89 ..
90 } => {
91 operand.is_constant()
92 && pattern.is_constant()
93 && escape.as_ref().is_none_or(|e| e.is_constant())
94 }
95 BoundExpr::Function { arguments, .. }
96 | BoundExpr::Math { arguments, .. }
97 | BoundExpr::Time { arguments, .. } => arguments.iter().all(BoundExpr::is_constant),
98 BoundExpr::Subquery { .. } => false,
103 }
104 }
105
106 pub fn columns_used(&self, into: &mut Vec<u16>) {
112 if let BoundExpr::Column { column, .. } = self {
113 if !into.contains(column) {
114 into.push(*column);
115 }
116 }
117 for child in self.children() {
118 child.columns_used(into);
119 }
120 }
121
122 pub fn children(&self) -> Vec<&BoundExpr> {
135 match self {
136 BoundExpr::Null
137 | BoundExpr::Integer(_)
138 | BoundExpr::Real(_)
139 | BoundExpr::Text(_)
140 | BoundExpr::Blob(_)
141 | BoundExpr::Parameter(_)
142 | BoundExpr::Raise { computed: None, .. }
143 | BoundExpr::Column { .. }
144 | BoundExpr::Rowid { .. }
145 | BoundExpr::WindowRef { .. }
146 | BoundExpr::Aggregate { .. }
147 | BoundExpr::SorterColumn { .. } => Vec::new(),
148 BoundExpr::Unary { operand, .. }
149 | BoundExpr::Not(operand)
150 | BoundExpr::IsNull { operand, .. }
151 | BoundExpr::Collate { operand, .. }
152 | BoundExpr::Cast { operand, .. }
153 | BoundExpr::Raise {
154 computed: Some(operand),
155 ..
156 } => vec![operand],
157 BoundExpr::Arithmetic { left, right, .. }
158 | BoundExpr::Compare { left, right, .. }
159 | BoundExpr::Is { left, right, .. }
160 | BoundExpr::And(left, right)
161 | BoundExpr::Or(left, right) => vec![left, right],
162 BoundExpr::Generated {
163 operand, present, ..
164 } => vec![operand, present],
165 BoundExpr::Between {
166 operand, low, high, ..
167 } => vec![operand, low, high],
168 BoundExpr::InList { operand, list, .. } => {
169 let mut found: Vec<&BoundExpr> = vec![operand];
170 found.extend(list.iter());
171 found
172 }
173 BoundExpr::Case {
174 operand,
175 branches,
176 otherwise,
177 ..
178 } => {
179 let mut found: Vec<&BoundExpr> = Vec::new();
180 if let Some(operand) = operand {
181 found.push(operand);
182 }
183 for (when, then) in branches {
184 found.push(when);
185 found.push(then);
186 }
187 if let Some(otherwise) = otherwise {
188 found.push(otherwise);
189 }
190 found
191 }
192 BoundExpr::Pattern {
193 operand,
194 pattern,
195 escape,
196 ..
197 } => {
198 let mut found: Vec<&BoundExpr> = vec![operand, pattern];
199 if let Some(escape) = escape {
200 found.push(escape);
201 }
202 found
203 }
204 BoundExpr::External { arguments, .. }
205 | BoundExpr::VirtualFunction { arguments, .. }
206 | BoundExpr::Function { arguments, .. }
207 | BoundExpr::Math { arguments, .. }
208 | BoundExpr::Json { arguments, .. }
209 | BoundExpr::Time { arguments, .. } => arguments.iter().collect(),
210 BoundExpr::Subquery { operand, .. } => operand.iter().map(|held| &**held).collect(),
211 }
212 }
213
214 pub fn children_mut(&mut self) -> Vec<&mut BoundExpr> {
229 match self {
230 BoundExpr::Null
231 | BoundExpr::Integer(_)
232 | BoundExpr::Real(_)
233 | BoundExpr::Text(_)
234 | BoundExpr::Blob(_)
235 | BoundExpr::Parameter(_)
236 | BoundExpr::Raise { computed: None, .. }
237 | BoundExpr::Column { .. }
238 | BoundExpr::Rowid { .. }
239 | BoundExpr::WindowRef { .. }
240 | BoundExpr::Aggregate { .. }
241 | BoundExpr::SorterColumn { .. } => Vec::new(),
242 BoundExpr::Unary { operand, .. }
243 | BoundExpr::Not(operand)
244 | BoundExpr::IsNull { operand, .. }
245 | BoundExpr::Collate { operand, .. }
246 | BoundExpr::Cast { operand, .. }
247 | BoundExpr::Raise {
248 computed: Some(operand),
249 ..
250 } => vec![operand],
251 BoundExpr::Arithmetic { left, right, .. }
252 | BoundExpr::Compare { left, right, .. }
253 | BoundExpr::Is { left, right, .. }
254 | BoundExpr::And(left, right)
255 | BoundExpr::Or(left, right) => vec![left, right],
256 BoundExpr::Generated {
257 operand, present, ..
258 } => vec![operand, present],
259 BoundExpr::Between {
260 operand, low, high, ..
261 } => vec![operand, low, high],
262 BoundExpr::InList { operand, list, .. } => {
263 let mut found: Vec<&mut BoundExpr> = vec![operand];
264 found.extend(list.iter_mut());
265 found
266 }
267 BoundExpr::Case {
268 operand,
269 branches,
270 otherwise,
271 ..
272 } => {
273 let mut found: Vec<&mut BoundExpr> = Vec::new();
274 if let Some(operand) = operand {
275 found.push(operand);
276 }
277 for (when, then) in branches {
278 found.push(when);
279 found.push(then);
280 }
281 if let Some(otherwise) = otherwise {
282 found.push(otherwise);
283 }
284 found
285 }
286 BoundExpr::Pattern {
287 operand,
288 pattern,
289 escape,
290 ..
291 } => {
292 let mut found: Vec<&mut BoundExpr> = vec![operand, pattern];
293 if let Some(escape) = escape {
294 found.push(escape);
295 }
296 found
297 }
298 BoundExpr::External { arguments, .. }
299 | BoundExpr::VirtualFunction { arguments, .. }
300 | BoundExpr::Function { arguments, .. }
301 | BoundExpr::Math { arguments, .. }
302 | BoundExpr::Json { arguments, .. }
303 | BoundExpr::Time { arguments, .. } => arguments.iter_mut().collect(),
304 BoundExpr::Subquery { operand, .. } => {
305 operand.iter_mut().map(|held| &mut **held).collect()
306 }
307 }
308 }
309
310 pub fn block_mut(&mut self) -> Option<&mut BoundSelect> {
316 match self {
317 BoundExpr::Subquery { block, .. } => Some(block),
318 _ => None,
319 }
320 }
321
322 pub fn columns_read(&self, source: usize, into: &mut ColumnUse) {
330 match self {
331 BoundExpr::Column {
332 source: held, slot, ..
333 } if *held == source => into.add(*slot),
334 BoundExpr::Rowid { source: held } if *held == source => into.rowid = true,
335 BoundExpr::Subquery { block, .. } if block.correlations.contains(&source) => {
336 into.opaque = true;
337 }
338 BoundExpr::VirtualFunction {
339 source: held,
340 name,
341 arguments,
342 } if *held == source => into.add_function(name, arguments),
343 _ => {}
344 }
345 for child in self.children() {
346 child.columns_read(source, into);
347 }
348 }
349}
350
351impl BoundExpr {
352 pub fn sources_used(&self, into: &mut Vec<usize>) {
354 match self {
355 BoundExpr::Column { source, .. } | BoundExpr::Rowid { source }
356 if !into.contains(source) =>
357 {
358 into.push(*source);
359 }
360 BoundExpr::Unary { operand, .. }
361 | BoundExpr::Not(operand)
362 | BoundExpr::IsNull { operand, .. }
363 | BoundExpr::Collate { operand, .. }
364 | BoundExpr::Cast { operand, .. }
365 | BoundExpr::Raise {
366 computed: Some(operand),
367 ..
368 } => operand.sources_used(into),
369 BoundExpr::Arithmetic { left, right, .. }
370 | BoundExpr::Compare { left, right, .. }
371 | BoundExpr::Is { left, right, .. }
372 | BoundExpr::And(left, right)
373 | BoundExpr::Or(left, right) => {
374 left.sources_used(into);
375 right.sources_used(into);
376 }
377 BoundExpr::Between {
378 operand, low, high, ..
379 } => {
380 operand.sources_used(into);
381 low.sources_used(into);
382 high.sources_used(into);
383 }
384 BoundExpr::InList { operand, list, .. } => {
385 operand.sources_used(into);
386 for item in list {
387 item.sources_used(into);
388 }
389 }
390 BoundExpr::Case {
391 operand,
392 branches,
393 otherwise,
394 ..
395 } => {
396 if let Some(operand) = operand {
397 operand.sources_used(into);
398 }
399 for (when, then) in branches {
400 when.sources_used(into);
401 then.sources_used(into);
402 }
403 if let Some(otherwise) = otherwise {
404 otherwise.sources_used(into);
405 }
406 }
407 BoundExpr::Pattern {
408 operand,
409 pattern,
410 escape,
411 ..
412 } => {
413 operand.sources_used(into);
414 pattern.sources_used(into);
415 if let Some(escape) = escape {
416 escape.sources_used(into);
417 }
418 }
419 BoundExpr::Function { arguments, .. }
426 | BoundExpr::Math { arguments, .. }
427 | BoundExpr::Time { arguments, .. }
428 | BoundExpr::Json { arguments, .. }
429 | BoundExpr::External { arguments, .. } => {
430 for argument in arguments {
431 argument.sources_used(into);
432 }
433 }
434 BoundExpr::Generated {
435 operand, present, ..
436 } => {
437 operand.sources_used(into);
438 present.sources_used(into);
439 }
440 BoundExpr::VirtualFunction {
441 source, arguments, ..
442 } => {
443 if !into.contains(source) {
444 into.push(*source);
445 }
446 for argument in arguments {
447 argument.sources_used(into);
448 }
449 }
450 BoundExpr::Subquery { operand, block, .. } => {
451 if let Some(operand) = operand {
452 operand.sources_used(into);
453 }
454 for source in &block.correlations {
459 if !into.contains(source) {
460 into.push(*source);
461 }
462 }
463 }
464 _ => {}
465 }
466 }
467}