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) {
331 match self {
332 BoundExpr::Column {
333 source: held, slot, ..
334 } if *held == source => into.add(*slot),
335 BoundExpr::Rowid { source: held } if *held == source => into.rowid = true,
336 BoundExpr::Function {
339 func: crate::function::ScalarFunc::Offset,
340 arguments,
341 ..
342 } if arguments.first().is_some_and(|argument| {
343 matches!(argument, BoundExpr::Column { source: held, .. } if *held == source)
344 }) =>
345 {
346 into.rowid = true;
347 }
348 BoundExpr::Subquery { block, .. } if block.correlations.contains(&source) => {
357 block.gather_columns(source, into, true);
358 }
359 BoundExpr::VirtualFunction {
360 source: held,
361 name,
362 arguments,
363 } if *held == source => into.add_function(name, arguments),
364 _ => {}
365 }
366 for child in self.children() {
367 child.columns_read(source, into);
368 }
369 }
370}
371
372impl BoundExpr {
373 pub fn sources_used(&self, into: &mut Vec<usize>) {
375 match self {
376 BoundExpr::Column { source, .. } | BoundExpr::Rowid { source }
377 if !into.contains(source) =>
378 {
379 into.push(*source);
380 }
381 BoundExpr::Unary { operand, .. }
382 | BoundExpr::Not(operand)
383 | BoundExpr::IsNull { operand, .. }
384 | BoundExpr::Collate { operand, .. }
385 | BoundExpr::Cast { operand, .. }
386 | BoundExpr::Raise {
387 computed: Some(operand),
388 ..
389 } => operand.sources_used(into),
390 BoundExpr::Arithmetic { left, right, .. }
391 | BoundExpr::Compare { left, right, .. }
392 | BoundExpr::Is { left, right, .. }
393 | BoundExpr::And(left, right)
394 | BoundExpr::Or(left, right) => {
395 left.sources_used(into);
396 right.sources_used(into);
397 }
398 BoundExpr::Between {
399 operand, low, high, ..
400 } => {
401 operand.sources_used(into);
402 low.sources_used(into);
403 high.sources_used(into);
404 }
405 BoundExpr::InList { operand, list, .. } => {
406 operand.sources_used(into);
407 for item in list {
408 item.sources_used(into);
409 }
410 }
411 BoundExpr::Case {
412 operand,
413 branches,
414 otherwise,
415 ..
416 } => {
417 if let Some(operand) = operand {
418 operand.sources_used(into);
419 }
420 for (when, then) in branches {
421 when.sources_used(into);
422 then.sources_used(into);
423 }
424 if let Some(otherwise) = otherwise {
425 otherwise.sources_used(into);
426 }
427 }
428 BoundExpr::Pattern {
429 operand,
430 pattern,
431 escape,
432 ..
433 } => {
434 operand.sources_used(into);
435 pattern.sources_used(into);
436 if let Some(escape) = escape {
437 escape.sources_used(into);
438 }
439 }
440 BoundExpr::Function { arguments, .. }
447 | BoundExpr::Math { arguments, .. }
448 | BoundExpr::Time { arguments, .. }
449 | BoundExpr::Json { arguments, .. }
450 | BoundExpr::External { arguments, .. } => {
451 for argument in arguments {
452 argument.sources_used(into);
453 }
454 }
455 BoundExpr::Generated {
456 operand, present, ..
457 } => {
458 operand.sources_used(into);
459 present.sources_used(into);
460 }
461 BoundExpr::VirtualFunction {
462 source, arguments, ..
463 } => {
464 if !into.contains(source) {
465 into.push(*source);
466 }
467 for argument in arguments {
468 argument.sources_used(into);
469 }
470 }
471 BoundExpr::Subquery { operand, block, .. } => {
472 if let Some(operand) = operand {
473 operand.sources_used(into);
474 }
475 for source in &block.correlations {
480 if !into.contains(source) {
481 into.push(*source);
482 }
483 }
484 }
485 _ => {}
486 }
487 }
488}