1use crate::ast::FunctionBinding;
10use crate::{
11 plan::{QueryPlan, RelationalPlan, SourcePlan},
12 ScalarExpr,
13};
14use uqa_core::{RelationIdentity, Value};
15
16pub fn canonical_virtual_relation_reference(reference: &str) -> Option<String> {
17 crate::catalog::resolve_virtual_relation(&[], reference)
18 .map(crate::catalog::VirtualRelation::qualified_name)
19}
20
21pub fn sequence_function_reference_mut(expression: &mut ScalarExpr) -> Option<&mut String> {
22 let ScalarExpr::Func { name, args, .. } = expression else {
23 return None;
24 };
25 let lower = name.to_ascii_lowercase();
26 let local = lower.strip_prefix("pg_catalog.").unwrap_or(&lower);
27 if !matches!(local, "nextval" | "currval" | "setval")
28 || (lower.contains('.') && !lower.starts_with("pg_catalog."))
29 {
30 return None;
31 }
32 regclass_literal_mut(args.first_mut()?)
33}
34
35pub fn regclass_literal_mut(expression: &mut ScalarExpr) -> Option<&mut String> {
36 match expression {
37 ScalarExpr::Literal(Value::Str(reference)) => Some(reference),
38 ScalarExpr::Cast { expr, ty, .. }
39 if ty.eq_ignore_ascii_case("regclass")
40 || ty.eq_ignore_ascii_case("pg_catalog.regclass") =>
41 {
42 regclass_literal_mut(expr)
43 }
44 _ => None,
45 }
46}
47
48pub fn bind_query_plan_sequence_references<E>(
49 plan: &mut QueryPlan,
50 resolve: &mut impl FnMut(&str) -> Result<String, E>,
51) -> Result<(), E> {
52 let mut error = None;
53 plan.rewrite_scalar_expressions(&mut |expression| {
54 if error.is_some() {
55 return;
56 }
57 let Some(reference) = sequence_function_reference_mut(expression) else {
58 return;
59 };
60 match resolve(reference) {
61 Ok(canonical) => *reference = canonical,
62 Err(binding_error) => error = Some(binding_error),
63 }
64 });
65 error.map_or(Ok(()), Err)
66}
67
68pub fn bind_query_plan_relations<E>(
69 plan: &mut QueryPlan,
70 inherited_ctes: &std::collections::BTreeSet<String>,
71 resolve: &mut impl FnMut(&str) -> Result<String, E>,
72) -> Result<(), E> {
73 bind_query_plan_relation_targets(plan, inherited_ctes, &mut |name, _| resolve(name))
74}
75
76pub fn bind_query_plan_relation_targets<E>(
78 plan: &mut QueryPlan,
79 inherited_ctes: &std::collections::BTreeSet<String>,
80 resolve: &mut impl FnMut(&str, bool) -> Result<String, E>,
81) -> Result<(), E> {
82 let mut visible_ctes = inherited_ctes.clone();
84 let recursive_ctes = plan.ctes.iter().any(|cte| cte.recursive).then(|| {
85 plan.ctes
86 .iter()
87 .map(|cte| cte.name.clone())
88 .collect::<std::collections::BTreeSet<_>>()
89 });
90 for cte in &mut plan.ctes {
91 let body_ctes = recursive_ctes.as_ref().map_or_else(
92 || visible_ctes.clone(),
93 |ctes| inherited_ctes.union(ctes).cloned().collect(),
94 );
95 bind_cte_relation_targets(&mut cte.body, &body_ctes, resolve)?;
96 visible_ctes.insert(cte.name.clone());
97 }
98 bind_relational_targets(&mut plan.root, &visible_ctes, resolve)?;
99 plan.relations_bound = true;
100 Ok(())
101}
102
103pub fn bind_relational_plan_relations<E>(
104 plan: &mut RelationalPlan,
105 visible_ctes: &std::collections::BTreeSet<String>,
106 resolve: &mut impl FnMut(&str) -> Result<String, E>,
107) -> Result<(), E> {
108 bind_relational_targets(plan, visible_ctes, &mut |name, _| resolve(name))
109}
110
111fn bind_relational_targets<E>(
112 plan: &mut RelationalPlan,
113 visible_ctes: &std::collections::BTreeSet<String>,
114 resolve: &mut impl FnMut(&str, bool) -> Result<String, E>,
115) -> Result<(), E> {
116 match plan {
117 RelationalPlan::QueryBlock(block) => {
118 if let Some(source) = &mut block.from {
119 bind_source_targets(source, visible_ctes, resolve)?;
120 }
121 for subquery in &mut block.subqueries {
122 bind_query_plan_relation_targets(subquery, visible_ctes, resolve)?;
123 }
124 }
125 RelationalPlan::SetOp {
126 left,
127 right,
128 subqueries,
129 ..
130 } => {
131 bind_query_plan_relation_targets(left, visible_ctes, resolve)?;
132 bind_query_plan_relation_targets(right, visible_ctes, resolve)?;
133 for subquery in subqueries {
134 bind_query_plan_relation_targets(subquery, visible_ctes, resolve)?;
135 }
136 }
137 RelationalPlan::Values { subqueries, .. } => {
138 for subquery in subqueries {
139 bind_query_plan_relation_targets(subquery, visible_ctes, resolve)?;
140 }
141 }
142 }
143 Ok(())
144}
145
146pub fn bind_source_plan_relations<E>(
147 source: &mut SourcePlan,
148 visible_ctes: &std::collections::BTreeSet<String>,
149 resolve: &mut impl FnMut(&str) -> Result<String, E>,
150) -> Result<(), E> {
151 bind_source_targets(source, visible_ctes, &mut |name, _| resolve(name))
152}
153
154fn bind_source_targets<E>(
155 source: &mut SourcePlan,
156 visible_ctes: &std::collections::BTreeSet<String>,
157 resolve: &mut impl FnMut(&str, bool) -> Result<String, E>,
158) -> Result<(), E> {
159 match source {
160 SourcePlan::Table {
161 name,
162 qualifier,
163 include_descendants,
164 ..
165 } => {
166 if qualifier.is_empty() {
167 *qualifier = RelationIdentity::parse_reference(name)
168 .map_or_else(|_| name.clone(), |(_, relation)| relation);
169 }
170 let is_cte = RelationIdentity::parse_reference(name).is_ok_and(|(schema, relation)| {
171 schema.is_none() && visible_ctes.contains(&relation)
172 });
173 if !is_cte {
174 *name = resolve(name, *include_descendants)?;
175 }
176 }
177 SourcePlan::Join { left, right, .. } => {
178 bind_source_targets(left, visible_ctes, resolve)?;
179 bind_source_targets(right, visible_ctes, resolve)?;
180 }
181 SourcePlan::Subquery { body, .. } => {
182 bind_query_plan_relation_targets(body, visible_ctes, resolve)?;
183 }
184 SourcePlan::Function {
185 name,
186 output_name,
187 relations,
188 ..
189 } => {
190 if output_name.is_empty() {
191 *output_name = RelationIdentity::parse_reference(name)
192 .map_or_else(|_| name.clone(), |(_, function)| function);
193 }
194 if let Some(relations) = relations {
195 relations.left = resolve(&relations.left, false)?;
196 relations.right = resolve(&relations.right, false)?;
197 }
198 }
199 SourcePlan::FunctionGroup { functions, .. } => {
200 for function in functions {
201 if function.output_name.is_empty() {
202 function.output_name = RelationIdentity::parse_reference(&function.name)
203 .map_or_else(|_| function.name.clone(), |(_, name)| name);
204 }
205 if let Some(relations) = &mut function.relations {
206 relations.left = resolve(&relations.left, false)?;
207 relations.right = resolve(&relations.right, false)?;
208 }
209 }
210 }
211 SourcePlan::Values { .. } => {}
212 }
213 Ok(())
214}
215
216pub fn relation_reference_matches(reference: &str, target: &RelationIdentity) -> bool {
217 match RelationIdentity::parse_reference(reference) {
218 Ok((Some(schema), name)) => schema == target.schema && name == target.name,
219 Ok((None, name)) => name == target.name,
220 Err(_) => true,
223 }
224}
225
226pub fn source_plan_references_relation(
227 source: &crate::plan::SourcePlan,
228 target: &RelationIdentity,
229 ctes: &std::collections::BTreeSet<String>,
230) -> bool {
231 match source {
232 crate::plan::SourcePlan::Table { name, .. } => {
233 let is_cte = RelationIdentity::parse_reference(name)
234 .is_ok_and(|(schema, relation)| schema.is_none() && ctes.contains(&relation));
235 !is_cte && relation_reference_matches(name, target)
236 }
237 crate::plan::SourcePlan::Join { left, right, .. } => {
238 source_plan_references_relation(left, target, ctes)
239 || source_plan_references_relation(right, target, ctes)
240 }
241 crate::plan::SourcePlan::Subquery { body, .. } => {
242 query_plan_references_relation(body, target, ctes)
243 }
244 crate::plan::SourcePlan::Function { relations, .. } => {
245 relations.as_ref().is_some_and(|relations| {
246 relation_reference_matches(&relations.left, target)
247 || relation_reference_matches(&relations.right, target)
248 })
249 }
250 crate::plan::SourcePlan::FunctionGroup { functions, .. } => {
251 functions.iter().any(|function| {
252 function.relations.as_ref().is_some_and(|relations| {
253 relation_reference_matches(&relations.left, target)
254 || relation_reference_matches(&relations.right, target)
255 })
256 })
257 }
258 crate::plan::SourcePlan::Values { .. } => false,
259 }
260}
261
262pub fn query_plan_references_relation(
263 query: &crate::plan::QueryPlan,
264 target: &RelationIdentity,
265 inherited_ctes: &std::collections::BTreeSet<String>,
266) -> bool {
267 let mut ctes = inherited_ctes.clone();
268 ctes.extend(query.ctes.iter().map(|cte| cte.name.clone()));
269 if query
270 .ctes
271 .iter()
272 .any(|cte| cte_plan_references_relation(&cte.body, target, &ctes))
273 {
274 return true;
275 }
276 match &query.root {
277 crate::plan::RelationalPlan::QueryBlock(block) => {
278 block
279 .from
280 .as_ref()
281 .is_some_and(|source| source_plan_references_relation(source, target, &ctes))
282 || block
283 .subqueries
284 .iter()
285 .any(|query| query_plan_references_relation(query, target, &ctes))
286 }
287 crate::plan::RelationalPlan::SetOp {
288 left,
289 right,
290 subqueries,
291 ..
292 } => {
293 query_plan_references_relation(left, target, &ctes)
294 || query_plan_references_relation(right, target, &ctes)
295 || subqueries
296 .iter()
297 .any(|query| query_plan_references_relation(query, target, &ctes))
298 }
299 crate::plan::RelationalPlan::Values { subqueries, .. } => subqueries
300 .iter()
301 .any(|query| query_plan_references_relation(query, target, &ctes)),
302 }
303}
304
305pub fn query_plan_references_sequence(plan: &QueryPlan, target: &RelationIdentity) -> bool {
306 let mut plan = plan.clone();
307 let mut referenced = false;
308 plan.rewrite_scalar_expressions(&mut |expression| {
309 if let Some(reference) = sequence_function_reference_mut(expression) {
310 referenced |= relation_reference_matches(reference, target);
311 }
312 });
313 referenced
314}
315
316pub use crate::routines::function_binding_matches;
317
318fn function_binding_needs_object_identity(binding: &FunctionBinding) -> bool {
319 !binding.builtin
320 && binding.dispatch.is_none()
321 && binding.resolution_error.is_none()
322 && binding.object_id.is_none()
323}
324
325fn source_plan_has_legacy_routine_identity(source: &SourcePlan) -> bool {
326 match source {
327 SourcePlan::Table { .. } | SourcePlan::Values { .. } => false,
328 SourcePlan::Join { left, right, .. } => {
329 source_plan_has_legacy_routine_identity(left)
330 || source_plan_has_legacy_routine_identity(right)
331 }
332 SourcePlan::Subquery { body, .. } => query_plan_sources_have_legacy_routine_identity(body),
333 SourcePlan::Function { binding, .. } => binding
334 .as_ref()
335 .is_some_and(function_binding_needs_object_identity),
336 SourcePlan::FunctionGroup { functions, .. } => functions.iter().any(|function| {
337 function
338 .binding
339 .as_ref()
340 .is_some_and(function_binding_needs_object_identity)
341 }),
342 }
343}
344
345fn relational_plan_has_legacy_routine_identity(plan: &RelationalPlan) -> bool {
346 match plan {
347 RelationalPlan::QueryBlock(block) => {
348 block
349 .from
350 .as_ref()
351 .is_some_and(source_plan_has_legacy_routine_identity)
352 || block
353 .subqueries
354 .iter()
355 .any(query_plan_sources_have_legacy_routine_identity)
356 }
357 RelationalPlan::SetOp {
358 left,
359 right,
360 subqueries,
361 ..
362 } => {
363 query_plan_sources_have_legacy_routine_identity(left)
364 || query_plan_sources_have_legacy_routine_identity(right)
365 || subqueries
366 .iter()
367 .any(query_plan_sources_have_legacy_routine_identity)
368 }
369 RelationalPlan::Values { subqueries, .. } => subqueries
370 .iter()
371 .any(query_plan_sources_have_legacy_routine_identity),
372 }
373}
374
375fn query_plan_sources_have_legacy_routine_identity(plan: &QueryPlan) -> bool {
376 plan.ctes.iter().any(|cte| {
377 cte_relational_inputs_any(
378 &cte.body,
379 &query_plan_sources_have_legacy_routine_identity,
380 &source_plan_has_legacy_routine_identity,
381 )
382 }) || relational_plan_has_legacy_routine_identity(&plan.root)
383}
384
385pub fn query_plan_has_legacy_routine_identity(plan: &QueryPlan) -> bool {
386 let mut scalar_plan = plan.clone();
387 let mut legacy = false;
388 scalar_plan.rewrite_scalar_expressions(&mut |expression| {
389 if let ScalarExpr::Func {
390 name,
391 binding,
392 order_syntax,
393 order_by,
394 ..
395 } = expression
396 {
397 legacy |= binding
398 .as_ref()
399 .is_some_and(function_binding_needs_object_identity);
400 legacy |= *order_syntax == crate::ast::FunctionOrderSyntax::Legacy
403 && super::ordered_calls::uses_ordered_arguments(
404 *order_syntax,
405 name,
406 binding.as_ref(),
407 order_by.len(),
408 );
409 }
410 });
411 legacy || query_plan_sources_have_legacy_routine_identity(plan)
412}
413
414fn source_plan_references_function(source: &SourcePlan, target: &FunctionBinding) -> bool {
415 match source {
416 SourcePlan::Table { .. } | SourcePlan::Values { .. } => false,
417 SourcePlan::Join { left, right, .. } => {
418 source_plan_references_function(left, target)
419 || source_plan_references_function(right, target)
420 }
421 SourcePlan::Subquery { body, .. } => query_plan_sources_reference_function(body, target),
422 SourcePlan::Function { binding, .. } => binding
423 .as_ref()
424 .is_some_and(|binding| function_binding_matches(binding, target)),
425 SourcePlan::FunctionGroup { functions, .. } => functions.iter().any(|function| {
426 function
427 .binding
428 .as_ref()
429 .is_some_and(|binding| function_binding_matches(binding, target))
430 }),
431 }
432}
433
434fn relational_plan_references_function(plan: &RelationalPlan, target: &FunctionBinding) -> bool {
435 match plan {
436 RelationalPlan::QueryBlock(block) => {
437 block
438 .from
439 .as_ref()
440 .is_some_and(|source| source_plan_references_function(source, target))
441 || block
442 .subqueries
443 .iter()
444 .any(|query| query_plan_sources_reference_function(query, target))
445 }
446 RelationalPlan::SetOp {
447 left,
448 right,
449 subqueries,
450 ..
451 } => {
452 query_plan_sources_reference_function(left, target)
453 || query_plan_sources_reference_function(right, target)
454 || subqueries
455 .iter()
456 .any(|query| query_plan_sources_reference_function(query, target))
457 }
458 RelationalPlan::Values { subqueries, .. } => subqueries
459 .iter()
460 .any(|query| query_plan_sources_reference_function(query, target)),
461 }
462}
463
464fn query_plan_sources_reference_function(plan: &QueryPlan, target: &FunctionBinding) -> bool {
465 plan.ctes.iter().any(|cte| {
466 cte_relational_inputs_any(
467 &cte.body,
468 &|query| query_plan_sources_reference_function(query, target),
469 &|source| source_plan_references_function(source, target),
470 )
471 }) || relational_plan_references_function(&plan.root, target)
472}
473
474pub fn query_plan_references_function(plan: &QueryPlan, target: &FunctionBinding) -> bool {
475 let mut scalar_plan = plan.clone();
476 let mut referenced = false;
477 scalar_plan.rewrite_scalar_expressions(&mut |expression| {
478 if let ScalarExpr::Func {
479 binding: Some(binding),
480 ..
481 } = expression
482 {
483 referenced |= function_binding_matches(binding, target);
484 }
485 });
486 referenced || query_plan_sources_reference_function(plan, target)
487}
488
489fn rewrite_source_plan_routine_identity(
490 source: &mut SourcePlan,
491 target: &FunctionBinding,
492 new_name: &str,
493) -> bool {
494 match source {
495 SourcePlan::Table { .. } | SourcePlan::Values { .. } => false,
496 SourcePlan::Join { left, right, .. } => {
497 rewrite_source_plan_routine_identity(left, target, new_name)
498 | rewrite_source_plan_routine_identity(right, target, new_name)
499 }
500 SourcePlan::Subquery { body, .. } => {
501 rewrite_query_source_routine_identity(body, target, new_name)
502 }
503 SourcePlan::Function { name, binding, .. } => {
504 let Some(binding) = binding.as_mut() else {
505 return false;
506 };
507 if !function_binding_matches(binding, target) {
508 return false;
509 }
510 *name = new_name.to_string();
511 binding.name = new_name.to_string();
512 true
513 }
514 SourcePlan::FunctionGroup { functions, .. } => {
515 let mut changed = false;
516 for function in functions {
517 let Some(binding) = function.binding.as_mut() else {
518 continue;
519 };
520 if function_binding_matches(binding, target) {
521 function.name = new_name.to_string();
522 binding.name = new_name.to_string();
523 changed = true;
524 }
525 }
526 changed
527 }
528 }
529}
530
531fn rewrite_relational_plan_source_routine_identity(
532 plan: &mut RelationalPlan,
533 target: &FunctionBinding,
534 new_name: &str,
535) -> bool {
536 match plan {
537 RelationalPlan::QueryBlock(block) => {
538 let mut changed = block.from.as_mut().is_some_and(|source| {
539 rewrite_source_plan_routine_identity(source, target, new_name)
540 });
541 for subquery in &mut block.subqueries {
542 changed |= rewrite_query_source_routine_identity(subquery, target, new_name);
543 }
544 changed
545 }
546 RelationalPlan::SetOp {
547 left,
548 right,
549 subqueries,
550 ..
551 } => {
552 let mut changed = rewrite_query_source_routine_identity(left, target, new_name)
553 | rewrite_query_source_routine_identity(right, target, new_name);
554 for subquery in subqueries {
555 changed |= rewrite_query_source_routine_identity(subquery, target, new_name);
556 }
557 changed
558 }
559 RelationalPlan::Values { subqueries, .. } => {
560 let mut changed = false;
561 for subquery in subqueries {
562 changed |= rewrite_query_source_routine_identity(subquery, target, new_name);
563 }
564 changed
565 }
566 }
567}
568
569fn rewrite_query_source_routine_identity(
570 plan: &mut QueryPlan,
571 target: &FunctionBinding,
572 new_name: &str,
573) -> bool {
574 let mut changed = false;
575 for cte in &mut plan.ctes {
576 changed |= rewrite_cte_source_routine_identity(&mut cte.body, target, new_name);
577 }
578 changed | rewrite_relational_plan_source_routine_identity(&mut plan.root, target, new_name)
579}
580
581pub fn rewrite_query_plan_routine_identity(
582 plan: &mut QueryPlan,
583 target: &FunctionBinding,
584 new_name: &str,
585) -> bool {
586 let mut changed = false;
587 plan.rewrite_scalar_expressions(&mut |expression| {
588 let ScalarExpr::Func {
589 name,
590 binding: Some(binding),
591 ..
592 } = expression
593 else {
594 return;
595 };
596 if function_binding_matches(binding, target) {
597 *name = new_name.to_string();
598 binding.name = new_name.to_string();
599 changed = true;
600 }
601 });
602 changed | rewrite_query_source_routine_identity(plan, target, new_name)
603}
604
605pub fn bind_cte_plan_relations<E>(
606 body: &mut crate::plan::CtePlanBody,
607 inherited: &std::collections::BTreeSet<String>,
608 resolve: &mut impl FnMut(&str) -> Result<String, E>,
609) -> Result<(), E> {
610 bind_cte_relation_targets(body, inherited, &mut |name, _| resolve(name))
611}
612
613fn bind_cte_relation_targets<E>(
614 body: &mut crate::plan::CtePlanBody,
615 inherited: &std::collections::BTreeSet<String>,
616 resolve: &mut impl FnMut(&str, bool) -> Result<String, E>,
617) -> Result<(), E> {
618 let crate::plan::CtePlanBody::Command(command) = body else {
619 let crate::plan::CtePlanBody::Query(query) = body else {
620 unreachable!()
621 };
622 return bind_query_plan_relation_targets(query, inherited, resolve);
623 };
624 let include_descendants = match command.as_ref() {
625 crate::plan::CommandPlan::Update(plan) => plan.include_descendants,
626 crate::plan::CommandPlan::Delete(plan) => plan.include_descendants,
627 _ => false,
628 };
629 if let Some(target) = command.mutation_target_mut() {
630 *target = resolve(target, include_descendants)?;
631 }
632 match command.as_mut() {
633 crate::plan::CommandPlan::Insert(plan) => {
634 plan.target_relation_bound = true;
635 plan.relations_bound = true;
636 }
637 crate::plan::CommandPlan::Update(plan) => {
638 plan.target_relation_bound = true;
639 plan.relations_bound = true;
640 }
641 crate::plan::CommandPlan::Delete(plan) => {
642 plan.target_relation_bound = true;
643 plan.relations_bound = true;
644 }
645 _ => {}
646 }
647 let mut visible = inherited.clone();
648 if let Some(ctes) = command.ctes_mut() {
649 let recursive = ctes.iter().any(|cte| cte.recursive).then(|| {
650 ctes.iter()
651 .map(|cte| cte.name.clone())
652 .collect::<std::collections::BTreeSet<_>>()
653 });
654 for cte in ctes {
655 let scope = recursive.as_ref().map_or_else(
656 || visible.clone(),
657 |names| inherited.union(names).cloned().collect(),
658 );
659 bind_cte_relation_targets(&mut cte.body, &scope, resolve)?;
660 visible.insert(cte.name.clone());
661 }
662 }
663 if let Some(source) = command.source_input_mut() {
664 bind_source_targets(source, &visible, resolve)?;
665 }
666 for query in command.query_inputs_mut() {
667 bind_query_plan_relation_targets(query, &visible, resolve)?;
668 }
669 Ok(())
670}
671
672fn cte_plan_references_relation(
673 body: &crate::plan::CtePlanBody,
674 target: &RelationIdentity,
675 inherited: &std::collections::BTreeSet<String>,
676) -> bool {
677 match body {
678 crate::plan::CtePlanBody::Query(query) => {
679 query_plan_references_relation(query, target, inherited)
680 }
681 crate::plan::CtePlanBody::Command(command) => {
682 let mut visible = inherited.clone();
683 visible.extend(command.ctes().iter().map(|cte| cte.name.clone()));
684 command
685 .mutation_target()
686 .is_some_and(|name| relation_reference_matches(name, target))
687 || command
688 .ctes()
689 .iter()
690 .any(|cte| cte_plan_references_relation(&cte.body, target, &visible))
691 || command
692 .source_input()
693 .is_some_and(|source| source_plan_references_relation(source, target, &visible))
694 || command
695 .query_inputs()
696 .iter()
697 .any(|query| query_plan_references_relation(query, target, &visible))
698 }
699 }
700}
701
702fn cte_relational_inputs_any(
703 body: &crate::plan::CtePlanBody,
704 query: &dyn Fn(&QueryPlan) -> bool,
705 source: &dyn Fn(&crate::plan::SourcePlan) -> bool,
706) -> bool {
707 match body {
708 crate::plan::CtePlanBody::Query(plan) => query(plan),
709 crate::plan::CtePlanBody::Command(command) => {
710 command
711 .ctes()
712 .iter()
713 .any(|cte| cte_relational_inputs_any(&cte.body, query, source))
714 || command.query_inputs().iter().any(|plan| query(plan))
715 || command.source_input().is_some_and(source)
716 }
717 }
718}
719
720fn rewrite_cte_source_routine_identity(
721 body: &mut crate::plan::CtePlanBody,
722 target: &FunctionBinding,
723 new_name: &str,
724) -> bool {
725 match body {
726 crate::plan::CtePlanBody::Query(query) => {
727 rewrite_query_source_routine_identity(query, target, new_name)
728 }
729 crate::plan::CtePlanBody::Command(command) => {
730 let mut changed = false;
731 if let Some(ctes) = command.ctes_mut() {
732 for cte in ctes {
733 changed |= rewrite_cte_source_routine_identity(&mut cte.body, target, new_name);
734 }
735 }
736 if let Some(source) = command.source_input_mut() {
737 changed |= rewrite_source_plan_routine_identity(source, target, new_name);
738 }
739 for query in command.query_inputs_mut() {
740 changed |= rewrite_query_source_routine_identity(query, target, new_name);
741 }
742 changed
743 }
744 }
745}
746
747pub mod restoration;