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