1use super::stored_routines::BoundRoutineReference;
10use crate::plan::CommandPlan;
11use crate::plan::{CtePlanBody, ExpressionPlan, QueryPlan, RelationalPlan, SourcePlan};
12use crate::{SQLError, ScalarExpr, ScalarFrameBound};
13use uqa_core::Value;
14
15#[derive(Debug, Clone, PartialEq)]
17pub enum ValueSite {
18 DiscardCollation,
20 RowDistinct,
22 Membership { array_items: Vec<usize> },
24 Cast(String),
26 CompositeRow(crate::ast::CompositeRowBinding),
28 Literal,
30 Constant { value: Value, ty: String },
32 Relabel(String),
34 FunctionOrder(crate::ast::FunctionOrderSyntax),
36 Node,
38}
39
40fn cast_depth(expression: &ScalarExpr) -> usize {
42 let mut depth = 0;
43 let mut node = expression;
44 while let ScalarExpr::Cast { expr, .. } = node {
45 depth += 1;
46 node = expr;
47 }
48 depth
49}
50
51#[derive(Debug, Default)]
53pub struct SyntaxSites {
54 pub routines: Vec<BoundRoutineReference>,
56 pub values: Vec<ValueSite>,
58}
59
60pub fn expression_syntax_sites(
62 lowered: &ExpressionPlan,
63 bound: &ExpressionPlan,
64) -> Result<SyntaxSites, SQLError> {
65 let mut walk = Walk::default();
66 walk.scalar(
67 &lowered.scalar,
68 &bound.scalar,
69 (&lowered.subqueries, &bound.subqueries),
70 )?;
71 Ok(walk.sites)
72}
73
74pub fn query_syntax_sites(lowered: &QueryPlan, bound: &QueryPlan) -> Result<SyntaxSites, SQLError> {
76 let mut walk = Walk::default();
77 walk.query(lowered, bound, false)?;
78 Ok(walk.sites)
79}
80
81pub(super) fn command_query_syntax_sites(
83 lowered: &QueryPlan,
84 bound: &QueryPlan,
85) -> Result<SyntaxSites, SQLError> {
86 let mut walk = Walk::default();
87 walk.query(lowered, bound, true)?;
88 Ok(walk.sites)
89}
90
91fn syntax_projections(
92 projections: &[crate::plan::ProjectionPlan],
93 command_root: bool,
94) -> Result<&[crate::plan::ProjectionPlan], SQLError> {
95 if command_root {
96 projections
97 .split_last()
98 .map(|(_, syntax)| syntax)
99 .ok_or_else(|| shape_error("command output"))
100 } else {
101 Ok(projections)
102 }
103}
104
105type Subqueries<'a> = (&'a [QueryPlan], &'a [QueryPlan]);
106
107fn shape_error(what: &str) -> SQLError {
108 SQLError::Internal(format!("bound stored syntax no longer matches its {what}"))
109}
110
111fn pairs<'a, T>(
112 lowered: &'a [T],
113 bound: &'a [T],
114 what: &str,
115) -> Result<impl Iterator<Item = (&'a T, &'a T)>, SQLError> {
116 if lowered.len() != bound.len() {
117 return Err(shape_error(what));
118 }
119 Ok(lowered.iter().zip(bound))
120}
121
122fn optional_pair<'a, T>(
123 lowered: Option<&'a T>,
124 bound: Option<&'a T>,
125 what: &str,
126) -> Result<Option<(&'a T, &'a T)>, SQLError> {
127 match (lowered, bound) {
128 (Some(lowered), Some(bound)) => Ok(Some((lowered, bound))),
129 (None, None) => Ok(None),
130 _ => Err(shape_error(what)),
131 }
132}
133
134#[derive(Default)]
135struct Walk {
136 sites: SyntaxSites,
137}
138
139impl Walk {
140 fn query(
141 &mut self,
142 lowered: &QueryPlan,
143 bound: &QueryPlan,
144 command_root: bool,
145 ) -> Result<(), SQLError> {
146 for (lowered, bound) in pairs(&lowered.ctes, &bound.ctes, "common table expressions")? {
147 self.cte_body(&lowered.body, &bound.body)?;
148 if let Some((lowered, bound)) =
149 optional_pair(lowered.cycle.as_ref(), bound.cycle.as_ref(), "CYCLE clause")?
150 {
151 self.scalar(&lowered.mark_value, &bound.mark_value, (&[], &[]))?;
152 self.scalar(&lowered.mark_default, &bound.mark_default, (&[], &[]))?;
153 }
154 }
155 match (&lowered.root, &bound.root) {
156 (RelationalPlan::QueryBlock(lowered), RelationalPlan::QueryBlock(bound)) => {
157 let subqueries = (&lowered.subqueries[..], &bound.subqueries[..]);
158 if let Some((lowered, bound)) =
159 optional_pair(lowered.from.as_ref(), bound.from.as_ref(), "FROM clause")?
160 {
161 self.source(lowered, bound, subqueries)?;
162 }
163 for (lowered, bound) in pairs(
164 syntax_projections(&lowered.projections, command_root)?,
165 syntax_projections(&bound.projections, command_root)?,
166 "select list",
167 )? {
168 self.scalar(&lowered.expr, &bound.expr, subqueries)?;
169 }
170 self.optional(lowered.r#where.as_ref(), bound.r#where.as_ref(), subqueries)?;
171 self.scalars(&lowered.group_by, &bound.group_by, subqueries)?;
172 if lowered.grouping_sets.len() != bound.grouping_sets.len() {
173 return Err(shape_error("grouping sets"));
174 }
175 for (lowered, bound) in lowered.grouping_sets.iter().zip(&bound.grouping_sets) {
176 self.scalars(lowered, bound, subqueries)?;
177 }
178 self.optional(lowered.having.as_ref(), bound.having.as_ref(), subqueries)?;
179 for (lowered, bound) in pairs(&lowered.order_by, &bound.order_by, "ORDER BY")? {
180 self.scalar(&lowered.expr, &bound.expr, subqueries)?;
181 }
182 self.optional(lowered.limit.as_ref(), bound.limit.as_ref(), subqueries)?;
183 self.optional(lowered.offset.as_ref(), bound.offset.as_ref(), subqueries)?;
184 self.scalars(&lowered.distinct_on, &bound.distinct_on, subqueries)?;
185 for (lowered, bound) in
186 pairs(&lowered.windows, &bound.windows, "WINDOW definitions")?
187 {
188 if lowered.name != bound.name || lowered.inherited != bound.inherited {
189 return Err(shape_error("WINDOW identity"));
190 }
191 let lowered: Vec<_> = lowered.spec.expressions().collect();
192 let bound: Vec<_> = bound.spec.expressions().collect();
193 for (lowered, bound) in pairs(&lowered, &bound, "WINDOW expressions")? {
194 self.scalar(lowered, bound, subqueries)?;
195 }
196 }
197 Ok(())
198 }
199 (
200 RelationalPlan::SetOp {
201 left,
202 right,
203 order_by,
204 limit,
205 offset,
206 subqueries,
207 ..
208 },
209 RelationalPlan::SetOp {
210 left: bound_left,
211 right: bound_right,
212 order_by: bound_order,
213 limit: bound_limit,
214 offset: bound_offset,
215 subqueries: bound_subqueries,
216 ..
217 },
218 ) => {
219 self.query(left, bound_left, false)?;
220 self.query(right, bound_right, false)?;
221 let subqueries = (&subqueries[..], &bound_subqueries[..]);
222 for (lowered, bound) in pairs(order_by, bound_order, "ORDER BY")? {
223 self.scalar(&lowered.expr, &bound.expr, subqueries)?;
224 }
225 self.optional(limit.as_deref(), bound_limit.as_deref(), subqueries)?;
226 self.optional(offset.as_deref(), bound_offset.as_deref(), subqueries)
227 }
228 (
229 RelationalPlan::Values { rows, subqueries },
230 RelationalPlan::Values {
231 rows: bound_rows,
232 subqueries: bound_subqueries,
233 },
234 ) => {
235 let subqueries = (&subqueries[..], &bound_subqueries[..]);
236 for (lowered, bound) in pairs(rows, bound_rows, "VALUES list")? {
237 self.scalars(lowered, bound, subqueries)?;
238 }
239 Ok(())
240 }
241 _ => Err(shape_error("query")),
242 }
243 }
244
245 fn cte_body(&mut self, lowered: &CtePlanBody, bound: &CtePlanBody) -> Result<(), SQLError> {
247 match (lowered, bound) {
248 (CtePlanBody::Query(lowered), CtePlanBody::Query(bound)) => {
249 self.query(lowered, bound, false)
250 }
251 (CtePlanBody::Command(lowered), CtePlanBody::Command(bound)) => {
252 self.command(lowered, bound)
253 }
254 _ => Err(shape_error("WITH query")),
255 }
256 }
257
258 fn command(&mut self, lowered: &CommandPlan, bound: &CommandPlan) -> Result<(), SQLError> {
259 for (lowered, bound) in pairs(lowered.ctes(), bound.ctes(), "common table expressions")? {
260 self.cte_body(&lowered.body, &bound.body)?;
261 if let Some((lowered, bound)) =
262 optional_pair(lowered.cycle.as_ref(), bound.cycle.as_ref(), "CYCLE clause")?
263 {
264 self.scalar(&lowered.mark_value, &bound.mark_value, (&[], &[]))?;
265 self.scalar(&lowered.mark_default, &bound.mark_default, (&[], &[]))?;
266 }
267 }
268 let subqueries = (lowered.scalar_subqueries(), bound.scalar_subqueries());
269 match (lowered, bound) {
270 (CommandPlan::Insert(lowered), CommandPlan::Insert(bound)) => {
271 if let Some((lowered, bound)) = optional_pair(
272 lowered.source.as_deref(),
273 bound.source.as_deref(),
274 "INSERT source",
275 )? {
276 self.query(lowered, bound, false)?;
277 }
278 }
279 (CommandPlan::Update(_), CommandPlan::Update(_))
280 | (CommandPlan::Delete(_), CommandPlan::Delete(_))
281 | (CommandPlan::Merge(_), CommandPlan::Merge(_)) => {
282 if let Some((lowered, bound)) = optional_pair(
283 lowered.source_input(),
284 bound.source_input(),
285 "command source",
286 )? {
287 self.source(lowered, bound, subqueries)?;
288 }
289 }
290 _ => return Err(shape_error("WITH command")),
291 }
292 let lowered = syntax_expressions(lowered);
293 let bound = syntax_expressions(bound);
294 for (lowered, bound) in pairs(&lowered, &bound, "command expressions")? {
295 self.scalar(lowered, bound, subqueries)?;
296 }
297 Ok(())
298 }
299
300 fn source(
301 &mut self,
302 lowered: &SourcePlan,
303 bound: &SourcePlan,
304 subqueries: Subqueries<'_>,
305 ) -> Result<(), SQLError> {
306 match (lowered, bound) {
307 (SourcePlan::Table { .. }, SourcePlan::Table { .. }) => Ok(()),
308 (
309 SourcePlan::Join {
310 left, right, on, ..
311 },
312 SourcePlan::Join {
313 left: bound_left,
314 right: bound_right,
315 on: bound_on,
316 ..
317 },
318 ) => {
319 self.source(left, bound_left, subqueries)?;
320 self.source(right, bound_right, subqueries)?;
321 self.optional(on.as_ref(), bound_on.as_ref(), subqueries)
322 }
323 (
324 SourcePlan::Values { rows, .. },
325 SourcePlan::Values {
326 rows: bound_rows, ..
327 },
328 ) => {
329 for (lowered, bound) in pairs(rows, bound_rows, "VALUES list")? {
330 self.scalars(lowered, bound, subqueries)?;
331 }
332 Ok(())
333 }
334 (
335 SourcePlan::Function { args, .. },
336 SourcePlan::Function {
337 name,
338 binding,
339 args: bound_args,
340 ..
341 },
342 ) => {
343 self.sites.routines.push(BoundRoutineReference {
344 name: name.clone(),
345 binding: binding.clone(),
346 });
347 self.scalars(args, bound_args, subqueries)
348 }
349 (
350 SourcePlan::FunctionGroup { functions, .. },
351 SourcePlan::FunctionGroup {
352 functions: bound_functions,
353 ..
354 },
355 ) => {
356 for (lowered, bound) in pairs(functions, bound_functions, "ROWS FROM list")? {
357 self.sites.routines.push(BoundRoutineReference {
358 name: bound.name.clone(),
359 binding: bound.binding.clone(),
360 });
361 self.scalars(&lowered.args, &bound.args, subqueries)?;
362 }
363 Ok(())
364 }
365 (SourcePlan::Subquery { body, .. }, SourcePlan::Subquery { body: bound, .. }) => {
366 self.query(body, bound, false)
367 }
368 _ => Err(shape_error("FROM item")),
369 }
370 }
371
372 fn optional(
373 &mut self,
374 lowered: Option<&ScalarExpr>,
375 bound: Option<&ScalarExpr>,
376 subqueries: Subqueries<'_>,
377 ) -> Result<(), SQLError> {
378 if let Some((lowered, bound)) = optional_pair(lowered, bound, "clause")? {
379 self.scalar(lowered, bound, subqueries)?;
380 }
381 Ok(())
382 }
383
384 fn scalars(
385 &mut self,
386 lowered: &[ScalarExpr],
387 bound: &[ScalarExpr],
388 subqueries: Subqueries<'_>,
389 ) -> Result<(), SQLError> {
390 for (lowered, bound) in pairs(lowered, bound, "expression list")? {
391 self.scalar(lowered, bound, subqueries)?;
392 }
393 Ok(())
394 }
395
396 fn subquery(
397 &mut self,
398 index: usize,
399 bound_index: usize,
400 subqueries: Subqueries<'_>,
401 ) -> Result<(), SQLError> {
402 match (subqueries.0.get(index), subqueries.1.get(bound_index)) {
403 (Some(lowered), Some(bound)) => self.query(lowered, bound, false),
404 _ => Err(SQLError::Internal(format!(
405 "stored syntax cannot resolve subquery slot {index}"
406 ))),
407 }
408 }
409
410 #[expect(
411 clippy::too_many_lines,
412 reason = "one syntax-order walk covers every scalar variant"
413 )]
414 fn scalar(
415 &mut self,
416 lowered: &ScalarExpr,
417 bound: &ScalarExpr,
418 subqueries: Subqueries<'_>,
419 ) -> Result<(), SQLError> {
420 let mut bound = bound;
421 while let ScalarExpr::Collated { expr, .. } = bound {
422 bound = expr;
423 }
424 if let Some(clause) = crate::catalog::collations::expression::scalar_clause(lowered)? {
425 let mut operand = bound;
426 while let ScalarExpr::Cast { expr, .. } = operand {
427 operand = expr;
428 }
429 if crate::catalog::collations::expression::scalar_clause(operand)?.is_none() {
430 self.sites.values.push(ValueSite::DiscardCollation);
431 return self.scalar(clause.argument, bound, subqueries);
432 }
433 }
434 if crate::type_resolution::row_distinct::expanded(lowered, bound) {
435 let mut rewritten = lowered.clone();
436 crate::type_resolution::row_distinct::rewrite_scalar(&mut rewritten)?;
437 self.sites.values.push(ValueSite::RowDistinct);
438 return self.scalar(&rewritten, bound, subqueries);
439 }
440 if let ScalarExpr::CompositeRow { items, binding, .. } = bound {
441 let mut source = match lowered {
442 ScalarExpr::Cast { expr, .. } => expr.as_ref(),
443 expression => expression,
444 };
445 while let ScalarExpr::Cast { expr, ty, .. } = source {
446 if crate::ColumnType::from_sql_name(ty).ok() != Some(crate::ColumnType::Record) {
447 break;
448 }
449 source = expr;
450 }
451 if let ScalarExpr::Row(original)
452 | ScalarExpr::CompositeRow {
453 items: original, ..
454 } = source
455 {
456 self.sites
457 .values
458 .push(ValueSite::CompositeRow(binding.clone()));
459 return self.scalars(original, items, subqueries);
460 }
461 }
462 if let Some(shape) = crate::type_resolution::membership::stored_shape(lowered, bound) {
463 let ScalarExpr::InList {
464 expr,
465 list,
466 negated,
467 } = lowered
468 else {
469 unreachable!()
470 };
471 self.sites.values.push(ValueSite::Membership {
472 array_items: shape.array_items.clone(),
473 });
474 let rewritten = crate::type_resolution::membership::rewrite(
475 expr.clone(),
476 list.clone(),
477 *negated,
478 &shape,
479 &uqa_core::memory::ProductionControl::uncontrolled(),
480 )?;
481 return self.scalar(&rewritten, bound, subqueries);
482 }
483 for _ in 0..cast_depth(bound).saturating_sub(cast_depth(lowered)) {
485 let ScalarExpr::Cast { expr, ty, .. } = bound else {
486 return Err(shape_error("relabel"));
487 };
488 self.sites.values.push(ValueSite::Relabel(ty.clone()));
489 bound = expr;
490 }
491 match lowered {
492 ScalarExpr::Literal(Value::Str(_) | Value::Null) => {
493 self.sites.values.push(match bound {
494 ScalarExpr::TypedLiteral { value, ty, .. } => ValueSite::Constant {
495 value: value.clone(),
496 ty: ty.clone(),
497 },
498 ScalarExpr::Literal(Value::Str(_) | Value::Null) => ValueSite::Literal,
499 _ => return Err(shape_error("literal")),
500 });
501 return Ok(());
502 }
503 ScalarExpr::Cast { .. } => {
504 let ScalarExpr::Cast { ty, .. } = bound else {
505 return Err(shape_error("cast"));
506 };
507 self.sites.values.push(ValueSite::Cast(ty.clone()));
508 }
509 ScalarExpr::Func { order_syntax, .. } => {
510 let ScalarExpr::Func {
511 order_syntax: bound,
512 ..
513 } = bound
514 else {
515 return Err(shape_error("function ordering"));
516 };
517 if !order_syntax.is_legacy() && order_syntax != bound {
518 return Err(shape_error("function ordering"));
519 }
520 self.sites.values.push(ValueSite::FunctionOrder(*bound));
521 }
522 _ => self.sites.values.push(ValueSite::Node),
523 }
524 match (lowered, bound) {
525 (
526 ScalarExpr::Func {
527 args,
528 order_by,
529 filter,
530 ..
531 },
532 ScalarExpr::Func {
533 name,
534 binding,
535 args: bound_args,
536 order_by: bound_order,
537 filter: bound_filter,
538 ..
539 },
540 ) => {
541 self.scalars(args, bound_args, subqueries)?;
542 for (lowered, bound) in pairs(order_by, bound_order, "aggregate ORDER BY")? {
543 self.scalar(&lowered.expr, &bound.expr, subqueries)?;
544 }
545 self.optional(filter.as_deref(), bound_filter.as_deref(), subqueries)?;
546 self.sites.routines.push(BoundRoutineReference {
547 name: name.clone(),
548 binding: binding.clone(),
549 });
550 Ok(())
551 }
552 (ScalarExpr::Array(items), ScalarExpr::Array(bound))
553 | (ScalarExpr::Row(items), ScalarExpr::Row(bound))
554 | (ScalarExpr::And(items), ScalarExpr::And(bound))
555 | (ScalarExpr::Or(items), ScalarExpr::Or(bound)) => {
556 self.scalars(items, bound, subqueries)
557 }
558 (
559 ScalarExpr::Binary { lhs, rhs, .. },
560 ScalarExpr::Binary {
561 lhs: bound_lhs,
562 rhs: bound_rhs,
563 ..
564 },
565 ) => {
566 self.scalar(lhs, bound_lhs, subqueries)?;
567 self.scalar(rhs, bound_rhs, subqueries)
568 }
569 (ScalarExpr::UnaryMinus(inner), ScalarExpr::UnaryMinus(bound))
570 | (ScalarExpr::Not(inner), ScalarExpr::Not(bound))
571 | (ScalarExpr::IsNull { expr: inner, .. }, ScalarExpr::IsNull { expr: bound, .. })
572 | (ScalarExpr::Cast { expr: inner, .. }, ScalarExpr::Cast { expr: bound, .. }) => {
573 self.scalar(inner, bound, subqueries)
574 }
575 (
576 ScalarExpr::Between { expr, low, high },
577 ScalarExpr::Between {
578 expr: bound_expr,
579 low: bound_low,
580 high: bound_high,
581 },
582 ) => {
583 self.scalar(expr, bound_expr, subqueries)?;
584 self.scalar(low, bound_low, subqueries)?;
585 self.scalar(high, bound_high, subqueries)
586 }
587 (
588 ScalarExpr::InList { expr, list, .. },
589 ScalarExpr::InList {
590 expr: bound_expr,
591 list: bound_list,
592 ..
593 },
594 ) => {
595 self.scalar(expr, bound_expr, subqueries)?;
596 self.scalars(list, bound_list, subqueries)
597 }
598 (
599 ScalarExpr::WindowCall {
600 args, spec, filter, ..
601 },
602 ScalarExpr::WindowCall {
603 name,
604 args: bound_args,
605 spec: bound_spec,
606 filter: bound_filter,
607 ..
608 },
609 ) => {
610 self.scalars(args, bound_args, subqueries)?;
611 if let Some((lowered, bound)) =
612 optional_pair(filter.as_deref(), bound_filter.as_deref(), "window FILTER")?
613 {
614 self.scalar(lowered, bound, subqueries)?;
615 }
616 self.scalars(&spec.partition_by, &bound_spec.partition_by, subqueries)?;
617 for (lowered, bound) in
618 pairs(&spec.order_by, &bound_spec.order_by, "window ORDER BY")?
619 {
620 self.scalar(&lowered.expr, &bound.expr, subqueries)?;
621 }
622 if let Some((lowered, bound)) = optional_pair(
623 spec.frame.as_ref(),
624 bound_spec.frame.as_ref(),
625 "window frame",
626 )? {
627 self.frame_bound(&lowered.start, &bound.start, subqueries)?;
628 self.frame_bound(&lowered.end, &bound.end, subqueries)?;
629 }
630 self.sites.routines.push(BoundRoutineReference {
631 name: name.clone(),
632 binding: None,
633 });
634 Ok(())
635 }
636 (
637 ScalarExpr::Case {
638 base,
639 when,
640 else_branch,
641 },
642 ScalarExpr::Case {
643 base: bound_base,
644 when: bound_when,
645 else_branch: bound_else,
646 },
647 ) => {
648 self.optional(base.as_deref(), bound_base.as_deref(), subqueries)?;
649 for ((condition, result), (bound_condition, bound_result)) in
650 pairs(when, bound_when, "CASE arms")?
651 {
652 self.scalar(condition, bound_condition, subqueries)?;
653 self.scalar(result, bound_result, subqueries)?;
654 }
655 self.optional(else_branch.as_deref(), bound_else.as_deref(), subqueries)
656 }
657 (ScalarExpr::ScalarSubquery(index), ScalarExpr::ScalarSubquery(bound))
658 | (
659 ScalarExpr::Exists {
660 subquery: index, ..
661 },
662 ScalarExpr::Exists {
663 subquery: bound, ..
664 },
665 ) => self.subquery(*index, *bound, subqueries),
666 (
667 ScalarExpr::InSubquery {
668 expr,
669 subquery: index,
670 ..
671 },
672 ScalarExpr::InSubquery {
673 expr: bound_expr,
674 subquery: bound,
675 ..
676 },
677 ) => {
678 self.scalar(expr, bound_expr, subqueries)?;
679 self.subquery(*index, *bound, subqueries)
680 }
681 (
683 ScalarExpr::Star
684 | ScalarExpr::QualifiedStar(_)
685 | ScalarExpr::Default
686 | ScalarExpr::Column(_)
687 | ScalarExpr::Position(_)
688 | ScalarExpr::InternalColumn(_)
689 | ScalarExpr::QualifiedColumn { .. }
690 | ScalarExpr::Literal(_)
691 | ScalarExpr::TypedLiteral { .. }
692 | ScalarExpr::Param(_),
693 _,
694 ) => Ok(()),
695 _ => Err(shape_error("expression")),
696 }
697 }
698
699 fn frame_bound(
700 &mut self,
701 lowered: &ScalarFrameBound,
702 bound: &ScalarFrameBound,
703 subqueries: Subqueries<'_>,
704 ) -> Result<(), SQLError> {
705 match (lowered, bound) {
706 (ScalarFrameBound::Preceding(lowered), ScalarFrameBound::Preceding(bound))
707 | (ScalarFrameBound::Following(lowered), ScalarFrameBound::Following(bound)) => {
708 self.scalar(lowered, bound, subqueries)
709 }
710 (
711 ScalarFrameBound::UnboundedPreceding
712 | ScalarFrameBound::UnboundedFollowing
713 | ScalarFrameBound::CurrentRow,
714 _,
715 ) => Ok(()),
716 _ => Err(shape_error("window frame")),
717 }
718 }
719}
720
721fn syntax_expressions(command: &CommandPlan) -> Vec<&ScalarExpr> {
723 use crate::plan::{ConflictActionPlan, MergeWhenPlan};
724 let mut expressions = Vec::new();
725 match command {
726 CommandPlan::Insert(plan) => {
727 expressions.extend(
728 plan.columns
729 .iter()
730 .flat_map(crate::ast::AssignmentTarget::expressions),
731 );
732 expressions.extend(plan.rows.iter().flatten());
733 if let Some(conflict) = &plan.on_conflict {
734 expressions.extend(&conflict.expressions);
735 expressions.extend(conflict.predicate.as_deref());
736 if let ConflictActionPlan::Update {
737 assignments,
738 predicate,
739 } = &conflict.action
740 {
741 expressions.extend(
742 assignments
743 .iter()
744 .flat_map(crate::plan::AssignmentPlan::expressions),
745 );
746 expressions.extend(predicate.as_deref());
747 }
748 }
749 expressions.extend(plan.returning.iter().map(|projection| &projection.expr));
750 }
751 CommandPlan::Update(plan) => {
752 expressions.extend(
753 plan.assignments
754 .iter()
755 .flat_map(crate::plan::AssignmentPlan::expressions),
756 );
757 expressions.extend(plan.predicate.as_ref());
758 expressions.extend(plan.returning.iter().map(|projection| &projection.expr));
759 }
760 CommandPlan::Delete(plan) => {
761 expressions.extend(plan.predicate.as_ref());
762 expressions.extend(plan.returning.iter().map(|projection| &projection.expr));
763 }
764 CommandPlan::Merge(plan) => {
765 expressions.push(&plan.join_condition);
766 for clause in &plan.when_clauses {
767 match clause {
768 MergeWhenPlan::UpdateMatched {
769 condition,
770 assignments,
771 }
772 | MergeWhenPlan::UpdateNotMatchedBySource {
773 condition,
774 assignments,
775 } => {
776 expressions.extend(condition.as_ref());
777 expressions.extend(
778 assignments
779 .iter()
780 .flat_map(crate::plan::AssignmentPlan::expressions),
781 );
782 }
783 MergeWhenPlan::InsertNotMatched {
784 condition,
785 columns,
786 values,
787 ..
788 } => {
789 expressions.extend(condition.as_ref());
790 expressions.extend(
791 columns
792 .iter()
793 .flat_map(crate::ast::AssignmentTarget::expressions),
794 );
795 expressions.extend(values.iter());
796 }
797 MergeWhenPlan::DeleteMatched { condition }
798 | MergeWhenPlan::DeleteNotMatchedBySource { condition }
799 | MergeWhenPlan::NothingMatched { condition }
800 | MergeWhenPlan::NothingNotMatched { condition }
801 | MergeWhenPlan::NothingNotMatchedBySource { condition } => {
802 expressions.extend(condition.as_ref());
803 }
804 }
805 }
806 expressions.extend(plan.returning.iter().map(|projection| &projection.expr));
807 }
808 _ => {}
809 }
810 expressions
811}