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::Function {
28 func: ScalarFunc::UsingCoalesce,
29 arguments,
30 ..
31 } => arguments.first().and_then(BoundExpr::affinity),
32 BoundExpr::Subquery {
36 kind: SubqueryKind::Scalar,
37 block,
38 ..
39 } => block.scalar_affinity(),
40 _ => None,
41 }
42 }
43
44 pub fn is_constant(&self) -> bool {
46 match self {
47 BoundExpr::Null
48 | BoundExpr::Integer(_)
49 | BoundExpr::Real(_)
50 | BoundExpr::Text(_)
51 | BoundExpr::Blob(_)
52 | BoundExpr::Parameter(_) => true,
53 BoundExpr::Raise { .. }
56 | BoundExpr::Column { .. }
57 | BoundExpr::Generated { .. }
58 | BoundExpr::Rowid { .. }
59 | BoundExpr::External { .. }
60 | BoundExpr::VirtualFunction { .. }
61 | BoundExpr::Aggregate { .. }
62 | BoundExpr::WindowRef { .. }
63 | BoundExpr::SorterColumn { .. } => false,
64 BoundExpr::Unary { operand, .. } => operand.is_constant(),
65 BoundExpr::Collate { operand, .. } => operand.is_constant(),
66 BoundExpr::Json { arguments, .. } => arguments.iter().all(BoundExpr::is_constant),
67 BoundExpr::Not(operand) => operand.is_constant(),
68 BoundExpr::IsNull { operand, .. } => operand.is_constant(),
69 BoundExpr::Cast { operand, .. } => operand.is_constant(),
70 BoundExpr::Arithmetic { left, right, .. }
71 | BoundExpr::Compare { left, right, .. }
72 | BoundExpr::Is { left, right, .. } => left.is_constant() && right.is_constant(),
73 BoundExpr::And(left, right) | BoundExpr::Or(left, right) => {
74 left.is_constant() && right.is_constant()
75 }
76 BoundExpr::Between {
77 operand, low, high, ..
78 } => operand.is_constant() && low.is_constant() && high.is_constant(),
79 BoundExpr::InList { operand, list, .. } => {
80 operand.is_constant() && list.iter().all(BoundExpr::is_constant)
81 }
82 BoundExpr::Case {
83 operand,
84 branches,
85 otherwise,
86 ..
87 } => {
88 operand.as_ref().is_none_or(|e| e.is_constant())
89 && branches
90 .iter()
91 .all(|(when, then)| when.is_constant() && then.is_constant())
92 && otherwise.as_ref().is_none_or(|e| e.is_constant())
93 }
94 BoundExpr::Pattern {
95 operand,
96 pattern,
97 escape,
98 ..
99 } => {
100 operand.is_constant()
101 && pattern.is_constant()
102 && escape.as_ref().is_none_or(|e| e.is_constant())
103 }
104 BoundExpr::Function { arguments, .. }
105 | BoundExpr::Math { arguments, .. }
106 | BoundExpr::Time { arguments, .. } => arguments.iter().all(BoundExpr::is_constant),
107 BoundExpr::Subquery { .. } => false,
112 }
113 }
114
115 pub fn columns_used(&self, into: &mut Vec<u16>) {
121 if let BoundExpr::Column { column, .. } = self {
122 if !into.contains(column) {
123 into.push(*column);
124 }
125 }
126 for child in self.children() {
127 child.columns_used(into);
128 }
129 }
130
131 pub fn children(&self) -> Vec<&BoundExpr> {
144 match self {
145 BoundExpr::Null
146 | BoundExpr::Integer(_)
147 | BoundExpr::Real(_)
148 | BoundExpr::Text(_)
149 | BoundExpr::Blob(_)
150 | BoundExpr::Parameter(_)
151 | BoundExpr::Raise { computed: None, .. }
152 | BoundExpr::Column { .. }
153 | BoundExpr::Rowid { .. }
154 | BoundExpr::WindowRef { .. }
155 | BoundExpr::Aggregate { .. }
156 | BoundExpr::SorterColumn { .. } => Vec::new(),
157 BoundExpr::Unary { operand, .. }
158 | BoundExpr::Not(operand)
159 | BoundExpr::IsNull { operand, .. }
160 | BoundExpr::Collate { operand, .. }
161 | BoundExpr::Cast { operand, .. }
162 | BoundExpr::Raise {
163 computed: Some(operand),
164 ..
165 } => vec![operand],
166 BoundExpr::Arithmetic { left, right, .. }
167 | BoundExpr::Compare { left, right, .. }
168 | BoundExpr::Is { left, right, .. }
169 | BoundExpr::And(left, right)
170 | BoundExpr::Or(left, right) => vec![left, right],
171 BoundExpr::Generated {
172 operand, present, ..
173 } => vec![operand, present],
174 BoundExpr::Between {
175 operand, low, high, ..
176 } => vec![operand, low, high],
177 BoundExpr::InList { operand, list, .. } => {
178 let mut found: Vec<&BoundExpr> = vec![operand];
179 found.extend(list.iter());
180 found
181 }
182 BoundExpr::Case {
183 operand,
184 branches,
185 otherwise,
186 ..
187 } => {
188 let mut found: Vec<&BoundExpr> = Vec::new();
189 if let Some(operand) = operand {
190 found.push(operand);
191 }
192 for (when, then) in branches {
193 found.push(when);
194 found.push(then);
195 }
196 if let Some(otherwise) = otherwise {
197 found.push(otherwise);
198 }
199 found
200 }
201 BoundExpr::Pattern {
202 operand,
203 pattern,
204 escape,
205 ..
206 } => {
207 let mut found: Vec<&BoundExpr> = vec![operand, pattern];
208 if let Some(escape) = escape {
209 found.push(escape);
210 }
211 found
212 }
213 BoundExpr::External { arguments, .. }
214 | BoundExpr::VirtualFunction { arguments, .. }
215 | BoundExpr::Function { arguments, .. }
216 | BoundExpr::Math { arguments, .. }
217 | BoundExpr::Json { arguments, .. }
218 | BoundExpr::Time { arguments, .. } => arguments.iter().collect(),
219 BoundExpr::Subquery { operand, .. } => operand.iter().map(|held| &**held).collect(),
220 }
221 }
222
223 pub fn children_mut(&mut self) -> Vec<&mut BoundExpr> {
238 match self {
239 BoundExpr::Null
240 | BoundExpr::Integer(_)
241 | BoundExpr::Real(_)
242 | BoundExpr::Text(_)
243 | BoundExpr::Blob(_)
244 | BoundExpr::Parameter(_)
245 | BoundExpr::Raise { computed: None, .. }
246 | BoundExpr::Column { .. }
247 | BoundExpr::Rowid { .. }
248 | BoundExpr::WindowRef { .. }
249 | BoundExpr::Aggregate { .. }
250 | BoundExpr::SorterColumn { .. } => Vec::new(),
251 BoundExpr::Unary { operand, .. }
252 | BoundExpr::Not(operand)
253 | BoundExpr::IsNull { operand, .. }
254 | BoundExpr::Collate { operand, .. }
255 | BoundExpr::Cast { operand, .. }
256 | BoundExpr::Raise {
257 computed: Some(operand),
258 ..
259 } => vec![operand],
260 BoundExpr::Arithmetic { left, right, .. }
261 | BoundExpr::Compare { left, right, .. }
262 | BoundExpr::Is { left, right, .. }
263 | BoundExpr::And(left, right)
264 | BoundExpr::Or(left, right) => vec![left, right],
265 BoundExpr::Generated {
266 operand, present, ..
267 } => vec![operand, present],
268 BoundExpr::Between {
269 operand, low, high, ..
270 } => vec![operand, low, high],
271 BoundExpr::InList { operand, list, .. } => {
272 let mut found: Vec<&mut BoundExpr> = vec![operand];
273 found.extend(list.iter_mut());
274 found
275 }
276 BoundExpr::Case {
277 operand,
278 branches,
279 otherwise,
280 ..
281 } => {
282 let mut found: Vec<&mut BoundExpr> = Vec::new();
283 if let Some(operand) = operand {
284 found.push(operand);
285 }
286 for (when, then) in branches {
287 found.push(when);
288 found.push(then);
289 }
290 if let Some(otherwise) = otherwise {
291 found.push(otherwise);
292 }
293 found
294 }
295 BoundExpr::Pattern {
296 operand,
297 pattern,
298 escape,
299 ..
300 } => {
301 let mut found: Vec<&mut BoundExpr> = vec![operand, pattern];
302 if let Some(escape) = escape {
303 found.push(escape);
304 }
305 found
306 }
307 BoundExpr::External { arguments, .. }
308 | BoundExpr::VirtualFunction { arguments, .. }
309 | BoundExpr::Function { arguments, .. }
310 | BoundExpr::Math { arguments, .. }
311 | BoundExpr::Json { arguments, .. }
312 | BoundExpr::Time { arguments, .. } => arguments.iter_mut().collect(),
313 BoundExpr::Subquery { operand, .. } => {
314 operand.iter_mut().map(|held| &mut **held).collect()
315 }
316 }
317 }
318
319 pub fn block_mut(&mut self) -> Option<&mut BoundSelect> {
325 match self {
326 BoundExpr::Subquery { block, .. } => Some(block),
327 _ => None,
328 }
329 }
330
331 pub fn columns_read(&self, source: usize, into: &mut ColumnUse) {
340 match self {
341 BoundExpr::Column {
342 source: held, slot, ..
343 } if *held == source => into.add(*slot),
344 BoundExpr::Rowid { source: held } if *held == source => into.rowid = true,
345 BoundExpr::Function {
348 func: crate::function::ScalarFunc::Offset,
349 arguments,
350 ..
351 } if arguments.first().is_some_and(|argument| {
352 matches!(argument, BoundExpr::Column { source: held, .. } if *held == source)
353 }) =>
354 {
355 into.rowid = true;
356 }
357 BoundExpr::Subquery { block, .. } if block.correlations.contains(&source) => {
366 block.gather_columns(source, into, true);
367 }
368 BoundExpr::VirtualFunction {
369 source: held,
370 name,
371 arguments,
372 } if *held == source => into.add_function(name, arguments),
373 _ => {}
374 }
375 for child in self.children() {
376 child.columns_read(source, into);
377 }
378 }
379}
380
381impl BoundExpr {
382 pub fn sources_used(&self, into: &mut Vec<usize>) {
384 match self {
385 BoundExpr::Column { source, .. } | BoundExpr::Rowid { source }
386 if !into.contains(source) =>
387 {
388 into.push(*source);
389 }
390 BoundExpr::Unary { operand, .. }
391 | BoundExpr::Not(operand)
392 | BoundExpr::IsNull { operand, .. }
393 | BoundExpr::Collate { operand, .. }
394 | BoundExpr::Cast { operand, .. }
395 | BoundExpr::Raise {
396 computed: Some(operand),
397 ..
398 } => operand.sources_used(into),
399 BoundExpr::Arithmetic { left, right, .. }
400 | BoundExpr::Compare { left, right, .. }
401 | BoundExpr::Is { left, right, .. }
402 | BoundExpr::And(left, right)
403 | BoundExpr::Or(left, right) => {
404 left.sources_used(into);
405 right.sources_used(into);
406 }
407 BoundExpr::Between {
408 operand, low, high, ..
409 } => {
410 operand.sources_used(into);
411 low.sources_used(into);
412 high.sources_used(into);
413 }
414 BoundExpr::InList { operand, list, .. } => {
415 operand.sources_used(into);
416 for item in list {
417 item.sources_used(into);
418 }
419 }
420 BoundExpr::Case {
421 operand,
422 branches,
423 otherwise,
424 ..
425 } => {
426 if let Some(operand) = operand {
427 operand.sources_used(into);
428 }
429 for (when, then) in branches {
430 when.sources_used(into);
431 then.sources_used(into);
432 }
433 if let Some(otherwise) = otherwise {
434 otherwise.sources_used(into);
435 }
436 }
437 BoundExpr::Pattern {
438 operand,
439 pattern,
440 escape,
441 ..
442 } => {
443 operand.sources_used(into);
444 pattern.sources_used(into);
445 if let Some(escape) = escape {
446 escape.sources_used(into);
447 }
448 }
449 BoundExpr::Function { arguments, .. }
456 | BoundExpr::Math { arguments, .. }
457 | BoundExpr::Time { arguments, .. }
458 | BoundExpr::Json { arguments, .. }
459 | BoundExpr::External { arguments, .. } => {
460 for argument in arguments {
461 argument.sources_used(into);
462 }
463 }
464 BoundExpr::Generated {
465 operand, present, ..
466 } => {
467 operand.sources_used(into);
468 present.sources_used(into);
469 }
470 BoundExpr::VirtualFunction {
471 source, arguments, ..
472 } => {
473 if !into.contains(source) {
474 into.push(*source);
475 }
476 for argument in arguments {
477 argument.sources_used(into);
478 }
479 }
480 BoundExpr::Subquery { operand, block, .. } => {
481 if let Some(operand) = operand {
482 operand.sources_used(into);
483 }
484 for source in &block.correlations {
489 if !into.contains(source) {
490 into.push(*source);
491 }
492 }
493 }
494 _ => {}
495 }
496 }
497}