Skip to main content

datafusion_expr/logical_plan/
tree_node.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//!  [`TreeNode`] based visiting and rewriting for [`LogicalPlan`]s
19//!
20//! Visiting (read only) APIs
21//! * [`LogicalPlan::visit`]: recursively visit the node and all of its inputs
22//! * [`LogicalPlan::visit_with_subqueries`]: recursively visit the node and all of its inputs, including subqueries
23//! * [`LogicalPlan::apply_children`]: recursively visit all inputs of this node
24//! * [`LogicalPlan::apply_expressions`]: (non recursively) visit all expressions of this node
25//! * [`LogicalPlan::apply_subqueries`]: (non recursively) visit all subqueries of this node
26//! * [`LogicalPlan::apply_with_subqueries`]: recursively visit all inputs and embedded subqueries.
27//!
28//! Rewriting (update) APIs:
29//! * [`LogicalPlan::exists`]: search for an expression in a plan
30//! * [`LogicalPlan::rewrite`]: recursively rewrite the node and all of its inputs
31//! * [`LogicalPlan::map_children`]: recursively rewrite all inputs of this node
32//! * [`LogicalPlan::map_expressions`]: (non recursively) visit all expressions of this node
33//! * [`LogicalPlan::map_subqueries`]: (non recursively) rewrite all subqueries of this node
34//! * [`LogicalPlan::rewrite_with_subqueries`]: recursively rewrite the node and all of its inputs, including subqueries
35//!
36//! (Re)creation APIs (these require substantial cloning and thus are slow):
37//! * [`LogicalPlan::with_new_exprs`]: Create a new plan with different expressions
38//! * [`LogicalPlan::expressions`]: Return a copy of the plan's expressions
39
40use crate::{
41    Aggregate, Analyze, CreateMemoryTable, CreateView, DdlStatement, Distinct,
42    DistinctOn, DmlStatement, Execute, Explain, Expr, Extension, Filter, Join, Limit,
43    LogicalPlan, Partitioning, Prepare, Projection, RecursiveQuery, Repartition, Sort,
44    Statement, Subquery, SubqueryAlias, TableScan, Union, Unnest, UserDefinedLogicalNode,
45    Values, Window, dml::CopyTo,
46};
47use datafusion_common::tree_node::TreeNodeRefContainer;
48
49use crate::expr::{Exists, InSubquery, SetComparison};
50use datafusion_common::tree_node::{
51    Transformed, TreeNode, TreeNodeContainer, TreeNodeIterator, TreeNodeRecursion,
52    TreeNodeRewriter, TreeNodeVisitor,
53};
54use datafusion_common::{Result, internal_err};
55
56impl TreeNode for LogicalPlan {
57    fn apply_children<'n, F: FnMut(&'n Self) -> Result<TreeNodeRecursion>>(
58        &'n self,
59        f: F,
60    ) -> Result<TreeNodeRecursion> {
61        self.inputs().apply_ref_elements(f)
62    }
63
64    /// Applies `f` to each child (input) of this plan node, rewriting them *in place.*
65    ///
66    /// # Notes
67    ///
68    /// Inputs include ONLY direct children, not embedded `LogicalPlan`s for
69    /// subqueries, for example such as are in [`Expr::Exists`].
70    ///
71    /// [`Expr::Exists`]: crate::Expr::Exists
72    fn map_children<F: FnMut(Self) -> Result<Transformed<Self>>>(
73        self,
74        f: F,
75    ) -> Result<Transformed<Self>> {
76        Ok(match self {
77            LogicalPlan::Projection(Projection {
78                expr,
79                input,
80                schema,
81            }) => input.map_elements(f)?.update_data(|input| {
82                LogicalPlan::Projection(Projection {
83                    expr,
84                    input,
85                    schema,
86                })
87            }),
88            LogicalPlan::Filter(Filter { predicate, input }) => input
89                .map_elements(f)?
90                .update_data(|input| LogicalPlan::Filter(Filter { predicate, input })),
91            LogicalPlan::Repartition(Repartition {
92                input,
93                partitioning_scheme,
94            }) => input.map_elements(f)?.update_data(|input| {
95                LogicalPlan::Repartition(Repartition {
96                    input,
97                    partitioning_scheme,
98                })
99            }),
100            LogicalPlan::Window(Window {
101                input,
102                window_expr,
103                schema,
104            }) => input.map_elements(f)?.update_data(|input| {
105                LogicalPlan::Window(Window {
106                    input,
107                    window_expr,
108                    schema,
109                })
110            }),
111            LogicalPlan::Aggregate(Aggregate {
112                input,
113                group_expr,
114                aggr_expr,
115                schema,
116            }) => input.map_elements(f)?.update_data(|input| {
117                LogicalPlan::Aggregate(Aggregate {
118                    input,
119                    group_expr,
120                    aggr_expr,
121                    schema,
122                })
123            }),
124            LogicalPlan::Sort(Sort { expr, input, fetch }) => input
125                .map_elements(f)?
126                .update_data(|input| LogicalPlan::Sort(Sort { expr, input, fetch })),
127            LogicalPlan::Join(Join {
128                left,
129                right,
130                on,
131                filter,
132                join_type,
133                join_constraint,
134                schema,
135                null_equality,
136                null_aware,
137            }) => (left, right).map_elements(f)?.update_data(|(left, right)| {
138                LogicalPlan::Join(Join {
139                    left,
140                    right,
141                    on,
142                    filter,
143                    join_type,
144                    join_constraint,
145                    schema,
146                    null_equality,
147                    null_aware,
148                })
149            }),
150            LogicalPlan::Limit(Limit { skip, fetch, input }) => input
151                .map_elements(f)?
152                .update_data(|input| LogicalPlan::Limit(Limit { skip, fetch, input })),
153            LogicalPlan::Subquery(Subquery {
154                subquery,
155                outer_ref_columns,
156                spans,
157            }) => subquery.map_elements(f)?.update_data(|subquery| {
158                LogicalPlan::Subquery(Subquery {
159                    subquery,
160                    outer_ref_columns,
161                    spans,
162                })
163            }),
164            LogicalPlan::SubqueryAlias(SubqueryAlias {
165                input,
166                alias,
167                schema,
168            }) => input.map_elements(f)?.update_data(|input| {
169                LogicalPlan::SubqueryAlias(SubqueryAlias {
170                    input,
171                    alias,
172                    schema,
173                })
174            }),
175            LogicalPlan::Extension(extension) => rewrite_extension_inputs(extension, f)?
176                .update_data(LogicalPlan::Extension),
177            LogicalPlan::Union(Union { inputs, schema }) => inputs
178                .map_elements(f)?
179                .update_data(|inputs| LogicalPlan::Union(Union { inputs, schema })),
180            LogicalPlan::Distinct(distinct) => match distinct {
181                Distinct::All(input) => input.map_elements(f)?.update_data(Distinct::All),
182                Distinct::On(DistinctOn {
183                    on_expr,
184                    select_expr,
185                    sort_expr,
186                    input,
187                    schema,
188                }) => input.map_elements(f)?.update_data(|input| {
189                    Distinct::On(DistinctOn {
190                        on_expr,
191                        select_expr,
192                        sort_expr,
193                        input,
194                        schema,
195                    })
196                }),
197            }
198            .update_data(LogicalPlan::Distinct),
199            LogicalPlan::Explain(Explain {
200                verbose,
201                explain_format: format,
202                plan,
203                stringified_plans,
204                schema,
205                logical_optimization_succeeded,
206            }) => plan.map_elements(f)?.update_data(|plan| {
207                LogicalPlan::Explain(Explain {
208                    verbose,
209                    explain_format: format,
210                    plan,
211                    stringified_plans,
212                    schema,
213                    logical_optimization_succeeded,
214                })
215            }),
216            LogicalPlan::Analyze(Analyze {
217                verbose,
218                input,
219                schema,
220            }) => input.map_elements(f)?.update_data(|input| {
221                LogicalPlan::Analyze(Analyze {
222                    verbose,
223                    input,
224                    schema,
225                })
226            }),
227            LogicalPlan::Dml(DmlStatement {
228                table_name,
229                target,
230                op,
231                input,
232                output_schema,
233            }) => input.map_elements(f)?.update_data(|input| {
234                LogicalPlan::Dml(DmlStatement {
235                    table_name,
236                    target,
237                    op,
238                    input,
239                    output_schema,
240                })
241            }),
242            LogicalPlan::Copy(CopyTo {
243                input,
244                output_url,
245                partition_by,
246                file_type,
247                options,
248                output_schema,
249            }) => input.map_elements(f)?.update_data(|input| {
250                LogicalPlan::Copy(CopyTo {
251                    input,
252                    output_url,
253                    partition_by,
254                    file_type,
255                    options,
256                    output_schema,
257                })
258            }),
259            LogicalPlan::Ddl(ddl) => {
260                match ddl {
261                    DdlStatement::CreateMemoryTable(CreateMemoryTable {
262                        name,
263                        constraints,
264                        input,
265                        if_not_exists,
266                        or_replace,
267                        column_defaults,
268                        temporary,
269                    }) => input.map_elements(f)?.update_data(|input| {
270                        DdlStatement::CreateMemoryTable(CreateMemoryTable {
271                            name,
272                            constraints,
273                            input,
274                            if_not_exists,
275                            or_replace,
276                            column_defaults,
277                            temporary,
278                        })
279                    }),
280                    DdlStatement::CreateView(CreateView {
281                        name,
282                        input,
283                        or_replace,
284                        definition,
285                        temporary,
286                    }) => input.map_elements(f)?.update_data(|input| {
287                        DdlStatement::CreateView(CreateView {
288                            name,
289                            input,
290                            or_replace,
291                            definition,
292                            temporary,
293                        })
294                    }),
295                    // no inputs in these statements
296                    DdlStatement::CreateExternalTable(_)
297                    | DdlStatement::CreateCatalogSchema(_)
298                    | DdlStatement::CreateCatalog(_)
299                    | DdlStatement::CreateIndex(_)
300                    | DdlStatement::DropTable(_)
301                    | DdlStatement::DropView(_)
302                    | DdlStatement::DropCatalogSchema(_)
303                    | DdlStatement::CreateFunction(_)
304                    | DdlStatement::DropFunction(_) => Transformed::no(ddl),
305                }
306                .update_data(LogicalPlan::Ddl)
307            }
308            LogicalPlan::Unnest(Unnest {
309                input,
310                exec_columns: input_columns,
311                list_type_columns,
312                struct_type_columns,
313                dependency_indices,
314                schema,
315                options,
316            }) => input.map_elements(f)?.update_data(|input| {
317                LogicalPlan::Unnest(Unnest {
318                    input,
319                    exec_columns: input_columns,
320                    list_type_columns,
321                    struct_type_columns,
322                    dependency_indices,
323                    schema,
324                    options,
325                })
326            }),
327            LogicalPlan::RecursiveQuery(RecursiveQuery {
328                name,
329                static_term,
330                recursive_term,
331                is_distinct,
332                schema,
333            }) => (static_term, recursive_term).map_elements(f)?.update_data(
334                |(static_term, recursive_term)| {
335                    // Ordinary child rewrites preserve derived schemas. Call
336                    // `LogicalPlan::recompute_schema` when child schemas should
337                    // be reconciled again.
338                    LogicalPlan::RecursiveQuery(RecursiveQuery {
339                        name,
340                        static_term,
341                        recursive_term,
342                        is_distinct,
343                        schema,
344                    })
345                },
346            ),
347            LogicalPlan::Statement(stmt) => match stmt {
348                Statement::Prepare(p) => p
349                    .input
350                    .map_elements(f)?
351                    .update_data(|input| Statement::Prepare(Prepare { input, ..p })),
352                _ => Transformed::no(stmt),
353            }
354            .update_data(LogicalPlan::Statement),
355            // plans without inputs
356            LogicalPlan::TableScan { .. }
357            | LogicalPlan::EmptyRelation { .. }
358            | LogicalPlan::Values { .. }
359            | LogicalPlan::DescribeTable(_) => Transformed::no(self),
360        })
361    }
362}
363
364/// Rewrites all inputs for an Extension node "in place"
365/// (it currently has to copy values because there are no APIs for in place modification)
366///
367/// Should be removed when we have an API for in place modifications of the
368/// extension to avoid these copies
369fn rewrite_extension_inputs<F: FnMut(LogicalPlan) -> Result<Transformed<LogicalPlan>>>(
370    extension: Extension,
371    f: F,
372) -> Result<Transformed<Extension>> {
373    let Extension { node } = extension;
374
375    node.inputs()
376        .into_iter()
377        .cloned()
378        .map_until_stop_and_collect(f)?
379        .map_data(|new_inputs| {
380            let exprs = node.expressions();
381            Ok(Extension {
382                node: node.with_exprs_and_inputs(exprs, new_inputs)?,
383            })
384        })
385}
386
387/// This macro is used to determine continuation during combined transforming
388/// traversals.
389macro_rules! handle_transform_recursion {
390    ($F_DOWN:expr, $F_CHILD:expr, $F_UP:expr) => {{
391        $F_DOWN?
392            .transform_children(|n| {
393                n.map_subqueries($F_CHILD)?
394                    .transform_sibling(|n| n.map_children($F_CHILD))
395            })?
396            .transform_parent($F_UP)
397    }};
398}
399
400impl LogicalPlan {
401    /// Calls `f` on all expressions in the current `LogicalPlan` node.
402    ///
403    /// # Notes
404    /// * Similar to [`TreeNode::apply`] but for this node's expressions.
405    /// * Does not include expressions in input `LogicalPlan` nodes
406    /// * Visits only the top level expressions (Does not recurse into each expression)
407    pub fn apply_expressions<F: FnMut(&Expr) -> Result<TreeNodeRecursion>>(
408        &self,
409        mut f: F,
410    ) -> Result<TreeNodeRecursion> {
411        match self {
412            LogicalPlan::Projection(Projection { expr, .. }) => expr.apply_elements(f),
413            LogicalPlan::Values(Values { values, .. }) => values.apply_elements(f),
414            LogicalPlan::Filter(Filter { predicate, .. }) => f(predicate),
415            LogicalPlan::Repartition(Repartition {
416                partitioning_scheme,
417                ..
418            }) => match partitioning_scheme {
419                Partitioning::Hash(expr, _) | Partitioning::DistributeBy(expr) => {
420                    expr.apply_elements(f)
421                }
422                Partitioning::RoundRobinBatch(_) => Ok(TreeNodeRecursion::Continue),
423            },
424            LogicalPlan::Window(Window { window_expr, .. }) => {
425                window_expr.apply_elements(f)
426            }
427            LogicalPlan::Aggregate(Aggregate {
428                group_expr,
429                aggr_expr,
430                ..
431            }) => (group_expr, aggr_expr).apply_ref_elements(f),
432            // There are two part of expression for join, equijoin(on) and non-equijoin(filter).
433            // 1. the first part is `on.len()` equijoin expressions, and the struct of each expr is `left-on = right-on`.
434            // 2. the second part is non-equijoin(filter).
435            LogicalPlan::Join(Join { on, filter, .. }) => {
436                (on, filter).apply_ref_elements(f)
437            }
438            LogicalPlan::Sort(Sort { expr, .. }) => expr.apply_elements(f),
439            LogicalPlan::Extension(extension) => {
440                // would be nice to avoid this copy -- maybe can
441                // update extension to just observer Exprs
442                extension.node.expressions().apply_elements(f)
443            }
444            LogicalPlan::TableScan(TableScan { filters, .. }) => {
445                filters.apply_elements(f)
446            }
447            LogicalPlan::Unnest(unnest) => {
448                let exprs = unnest
449                    .exec_columns
450                    .iter()
451                    .cloned()
452                    .map(Expr::Column)
453                    .collect::<Vec<_>>();
454                exprs.apply_elements(f)
455            }
456            LogicalPlan::Distinct(Distinct::On(DistinctOn {
457                on_expr,
458                select_expr,
459                sort_expr,
460                ..
461            })) => (on_expr, select_expr, sort_expr).apply_ref_elements(f),
462            LogicalPlan::Limit(Limit { skip, fetch, .. }) => {
463                (skip, fetch).apply_ref_elements(f)
464            }
465            LogicalPlan::Statement(stmt) => match stmt {
466                Statement::Execute(Execute { parameters, .. }) => {
467                    parameters.apply_elements(f)
468                }
469                _ => Ok(TreeNodeRecursion::Continue),
470            },
471            // plans without expressions
472            LogicalPlan::EmptyRelation(_)
473            | LogicalPlan::RecursiveQuery(_)
474            | LogicalPlan::Subquery(_)
475            | LogicalPlan::SubqueryAlias(_)
476            | LogicalPlan::Analyze(_)
477            | LogicalPlan::Explain(_)
478            | LogicalPlan::Union(_)
479            | LogicalPlan::Distinct(Distinct::All(_))
480            | LogicalPlan::Dml(_)
481            | LogicalPlan::Ddl(_)
482            | LogicalPlan::Copy(_)
483            | LogicalPlan::DescribeTable(_) => Ok(TreeNodeRecursion::Continue),
484        }
485    }
486
487    /// Rewrites all expressions in the current `LogicalPlan` node using `f`.
488    ///
489    /// Returns the current node.
490    ///
491    /// # Notes
492    /// * Similar to [`TreeNode::map_children`] but for this node's expressions.
493    /// * Visits only the top level expressions (Does not recurse into each expression)
494    pub fn map_expressions<F: FnMut(Expr) -> Result<Transformed<Expr>>>(
495        self,
496        mut f: F,
497    ) -> Result<Transformed<Self>> {
498        Ok(match self {
499            LogicalPlan::Projection(Projection {
500                expr,
501                input,
502                schema,
503            }) => expr.map_elements(f)?.update_data(|expr| {
504                LogicalPlan::Projection(Projection {
505                    expr,
506                    input,
507                    schema,
508                })
509            }),
510            LogicalPlan::Values(Values { schema, values }) => values
511                .map_elements(f)?
512                .update_data(|values| LogicalPlan::Values(Values { schema, values })),
513            LogicalPlan::Filter(Filter { predicate, input }) => f(predicate)?
514                .update_data(|predicate| {
515                    LogicalPlan::Filter(Filter { predicate, input })
516                }),
517            LogicalPlan::Repartition(Repartition {
518                input,
519                partitioning_scheme,
520            }) => match partitioning_scheme {
521                Partitioning::Hash(expr, usize) => expr
522                    .map_elements(f)?
523                    .update_data(|expr| Partitioning::Hash(expr, usize)),
524                Partitioning::DistributeBy(expr) => expr
525                    .map_elements(f)?
526                    .update_data(Partitioning::DistributeBy),
527                Partitioning::RoundRobinBatch(_) => Transformed::no(partitioning_scheme),
528            }
529            .update_data(|partitioning_scheme| {
530                LogicalPlan::Repartition(Repartition {
531                    input,
532                    partitioning_scheme,
533                })
534            }),
535            LogicalPlan::Window(Window {
536                input,
537                window_expr,
538                schema,
539            }) => window_expr.map_elements(f)?.update_data(|window_expr| {
540                LogicalPlan::Window(Window {
541                    input,
542                    window_expr,
543                    schema,
544                })
545            }),
546            LogicalPlan::Aggregate(Aggregate {
547                input,
548                group_expr,
549                aggr_expr,
550                schema,
551            }) => (group_expr, aggr_expr).map_elements(f)?.update_data(
552                |(group_expr, aggr_expr)| {
553                    LogicalPlan::Aggregate(Aggregate {
554                        input,
555                        group_expr,
556                        aggr_expr,
557                        schema,
558                    })
559                },
560            ),
561
562            // There are two part of expression for join, equijoin(on) and non-equijoin(filter).
563            // 1. the first part is `on.len()` equijoin expressions, and the struct of each expr is `left-on = right-on`.
564            // 2. the second part is non-equijoin(filter).
565            LogicalPlan::Join(Join {
566                left,
567                right,
568                on,
569                filter,
570                join_type,
571                join_constraint,
572                schema,
573                null_equality,
574                null_aware,
575            }) => (on, filter).map_elements(f)?.update_data(|(on, filter)| {
576                LogicalPlan::Join(Join {
577                    left,
578                    right,
579                    on,
580                    filter,
581                    join_type,
582                    join_constraint,
583                    schema,
584                    null_equality,
585                    null_aware,
586                })
587            }),
588            LogicalPlan::Sort(Sort { expr, input, fetch }) => expr
589                .map_elements(f)?
590                .update_data(|expr| LogicalPlan::Sort(Sort { expr, input, fetch })),
591            LogicalPlan::Extension(Extension { node }) => {
592                let raw_exprs = node.expressions();
593                if raw_exprs.is_empty() {
594                    // No expressions to transform — skip expensive clone of
595                    // all inputs and reconstruction via with_exprs_and_inputs.
596                    Transformed::no(LogicalPlan::Extension(Extension { node }))
597                } else {
598                    // TODO: a more general optimization would be to change
599                    // `UserDefinedLogicalNode::expressions()` to return
600                    // references (`&[Expr]`) instead of cloned `Vec<Expr>`,
601                    // and only clone + rebuild when the transform actually
602                    // modifies an expression. This would avoid the clone +
603                    // `with_exprs_and_inputs` rebuild even for non-empty
604                    // expression lists when the transform is a no-op.
605                    let exprs = raw_exprs.map_elements(f)?;
606                    let plan = LogicalPlan::Extension(Extension {
607                        node: UserDefinedLogicalNode::with_exprs_and_inputs(
608                            node.as_ref(),
609                            exprs.data,
610                            node.inputs().into_iter().cloned().collect::<Vec<_>>(),
611                        )?,
612                    });
613                    Transformed::new(plan, exprs.transformed, exprs.tnr)
614                }
615            }
616            LogicalPlan::TableScan(TableScan {
617                table_name,
618                source,
619                projection,
620                projected_schema,
621                filters,
622                fetch,
623            }) => filters.map_elements(f)?.update_data(|filters| {
624                LogicalPlan::TableScan(TableScan {
625                    table_name,
626                    source,
627                    projection,
628                    projected_schema,
629                    filters,
630                    fetch,
631                })
632            }),
633            LogicalPlan::Distinct(Distinct::On(DistinctOn {
634                on_expr,
635                select_expr,
636                sort_expr,
637                input,
638                schema,
639            })) => (on_expr, select_expr, sort_expr)
640                .map_elements(f)?
641                .update_data(|(on_expr, select_expr, sort_expr)| {
642                    LogicalPlan::Distinct(Distinct::On(DistinctOn {
643                        on_expr,
644                        select_expr,
645                        sort_expr,
646                        input,
647                        schema,
648                    }))
649                }),
650            LogicalPlan::Limit(Limit { skip, fetch, input }) => {
651                (skip, fetch).map_elements(f)?.update_data(|(skip, fetch)| {
652                    LogicalPlan::Limit(Limit { skip, fetch, input })
653                })
654            }
655            LogicalPlan::Statement(stmt) => match stmt {
656                Statement::Execute(e) => {
657                    e.parameters.map_elements(f)?.update_data(|parameters| {
658                        Statement::Execute(Execute { parameters, ..e })
659                    })
660                }
661                _ => Transformed::no(stmt),
662            }
663            .update_data(LogicalPlan::Statement),
664            // plans without expressions
665            LogicalPlan::EmptyRelation(_)
666            | LogicalPlan::Unnest(_)
667            | LogicalPlan::RecursiveQuery(_)
668            | LogicalPlan::Subquery(_)
669            | LogicalPlan::SubqueryAlias(_)
670            | LogicalPlan::Analyze(_)
671            | LogicalPlan::Explain(_)
672            | LogicalPlan::Union(_)
673            | LogicalPlan::Distinct(Distinct::All(_))
674            | LogicalPlan::Dml(_)
675            | LogicalPlan::Ddl(_)
676            | LogicalPlan::Copy(_)
677            | LogicalPlan::DescribeTable(_) => Transformed::no(self),
678        })
679    }
680
681    /// Visits a plan similarly to [`Self::visit`], including subqueries that
682    /// may appear in expressions such as `IN (SELECT ...)`.
683    #[cfg_attr(feature = "recursive_protection", recursive::recursive)]
684    pub fn visit_with_subqueries<V: for<'n> TreeNodeVisitor<'n, Node = Self>>(
685        &self,
686        visitor: &mut V,
687    ) -> Result<TreeNodeRecursion> {
688        visitor
689            .f_down(self)?
690            .visit_children(|| {
691                self.apply_subqueries(|c| c.visit_with_subqueries(visitor))?
692                    .visit_sibling(|| {
693                        self.apply_children(|c| c.visit_with_subqueries(visitor))
694                    })
695            })?
696            .visit_parent(|| visitor.f_up(self))
697    }
698
699    /// Similarly to [`Self::rewrite`], rewrites this node and its inputs using `f`,
700    /// including subqueries that may appear in expressions such as `IN (SELECT
701    /// ...)`.
702    #[cfg_attr(feature = "recursive_protection", recursive::recursive)]
703    pub fn rewrite_with_subqueries<R: TreeNodeRewriter<Node = Self>>(
704        self,
705        rewriter: &mut R,
706    ) -> Result<Transformed<Self>> {
707        handle_transform_recursion!(
708            rewriter.f_down(self),
709            |c| c.rewrite_with_subqueries(rewriter),
710            |n| rewriter.f_up(n)
711        )
712    }
713
714    /// Similarly to [`Self::apply`], calls `f` on this node and all its inputs,
715    /// including subqueries that may appear in expressions such as `IN (SELECT
716    /// ...)`.
717    pub fn apply_with_subqueries<F: FnMut(&Self) -> Result<TreeNodeRecursion>>(
718        &self,
719        mut f: F,
720    ) -> Result<TreeNodeRecursion> {
721        #[cfg_attr(feature = "recursive_protection", recursive::recursive)]
722        fn apply_with_subqueries_impl<
723            F: FnMut(&LogicalPlan) -> Result<TreeNodeRecursion>,
724        >(
725            node: &LogicalPlan,
726            f: &mut F,
727        ) -> Result<TreeNodeRecursion> {
728            f(node)?.visit_children(|| {
729                node.apply_subqueries(|c| apply_with_subqueries_impl(c, f))?
730                    .visit_sibling(|| {
731                        node.apply_children(|c| apply_with_subqueries_impl(c, f))
732                    })
733            })
734        }
735
736        apply_with_subqueries_impl(self, &mut f)
737    }
738
739    /// Similarly to [`Self::transform`], rewrites this node and its inputs using `f`,
740    /// including subqueries that may appear in expressions such as `IN (SELECT
741    /// ...)`.
742    pub fn transform_with_subqueries<F: FnMut(Self) -> Result<Transformed<Self>>>(
743        self,
744        f: F,
745    ) -> Result<Transformed<Self>> {
746        self.transform_up_with_subqueries(f)
747    }
748
749    /// Similarly to [`Self::transform_down`], rewrites this node and its inputs using `f`,
750    /// including subqueries that may appear in expressions such as `IN (SELECT
751    /// ...)`.
752    pub fn transform_down_with_subqueries<F: FnMut(Self) -> Result<Transformed<Self>>>(
753        self,
754        mut f: F,
755    ) -> Result<Transformed<Self>> {
756        #[cfg_attr(feature = "recursive_protection", recursive::recursive)]
757        fn transform_down_with_subqueries_impl<
758            F: FnMut(LogicalPlan) -> Result<Transformed<LogicalPlan>>,
759        >(
760            node: LogicalPlan,
761            f: &mut F,
762        ) -> Result<Transformed<LogicalPlan>> {
763            f(node)?.transform_children(|n| {
764                n.map_subqueries(|c| transform_down_with_subqueries_impl(c, f))?
765                    .transform_sibling(|n| {
766                        n.map_children(|c| transform_down_with_subqueries_impl(c, f))
767                    })
768            })
769        }
770
771        transform_down_with_subqueries_impl(self, &mut f)
772    }
773
774    /// Similarly to [`Self::transform_up`], rewrites this node and its inputs using `f`,
775    /// including subqueries that may appear in expressions such as `IN (SELECT
776    /// ...)`.
777    pub fn transform_up_with_subqueries<F: FnMut(Self) -> Result<Transformed<Self>>>(
778        self,
779        mut f: F,
780    ) -> Result<Transformed<Self>> {
781        #[cfg_attr(feature = "recursive_protection", recursive::recursive)]
782        fn transform_up_with_subqueries_impl<
783            F: FnMut(LogicalPlan) -> Result<Transformed<LogicalPlan>>,
784        >(
785            node: LogicalPlan,
786            f: &mut F,
787        ) -> Result<Transformed<LogicalPlan>> {
788            node.map_subqueries(|c| transform_up_with_subqueries_impl(c, f))?
789                .transform_sibling(|n| {
790                    n.map_children(|c| transform_up_with_subqueries_impl(c, f))
791                })?
792                .transform_parent(f)
793        }
794
795        transform_up_with_subqueries_impl(self, &mut f)
796    }
797
798    /// Similarly to [`Self::transform_down`], rewrites this node and its inputs using `f`,
799    /// including subqueries that may appear in expressions such as `IN (SELECT
800    /// ...)`.
801    pub fn transform_down_up_with_subqueries<
802        FD: FnMut(Self) -> Result<Transformed<Self>>,
803        FU: FnMut(Self) -> Result<Transformed<Self>>,
804    >(
805        self,
806        mut f_down: FD,
807        mut f_up: FU,
808    ) -> Result<Transformed<Self>> {
809        #[cfg_attr(feature = "recursive_protection", recursive::recursive)]
810        fn transform_down_up_with_subqueries_impl<
811            FD: FnMut(LogicalPlan) -> Result<Transformed<LogicalPlan>>,
812            FU: FnMut(LogicalPlan) -> Result<Transformed<LogicalPlan>>,
813        >(
814            node: LogicalPlan,
815            f_down: &mut FD,
816            f_up: &mut FU,
817        ) -> Result<Transformed<LogicalPlan>> {
818            handle_transform_recursion!(
819                f_down(node),
820                |c| transform_down_up_with_subqueries_impl(c, f_down, f_up),
821                f_up
822            )
823        }
824
825        transform_down_up_with_subqueries_impl(self, &mut f_down, &mut f_up)
826    }
827
828    /// Similarly to [`Self::apply`], calls `f` on this node and its inputs,
829    /// including subqueries that may appear in expressions such as `IN (SELECT
830    /// ...)`.
831    pub fn apply_subqueries<F: FnMut(&Self) -> Result<TreeNodeRecursion>>(
832        &self,
833        mut f: F,
834    ) -> Result<TreeNodeRecursion> {
835        self.apply_expressions(|expr| {
836            expr.apply(|expr| match expr {
837                Expr::Exists(Exists { subquery, .. })
838                | Expr::InSubquery(InSubquery { subquery, .. })
839                | Expr::SetComparison(SetComparison { subquery, .. })
840                | Expr::ScalarSubquery(subquery) => {
841                    // Wrap in LogicalPlan::Subquery to match f's signature
842                    f(&LogicalPlan::Subquery(subquery.clone()))
843                }
844                _ => Ok(TreeNodeRecursion::Continue),
845            })
846        })
847    }
848
849    /// Similarly to [`Self::map_children`], rewrites all subqueries that may
850    /// appear in expressions such as `IN (SELECT ...)` using `f`.
851    ///
852    /// Returns the current node.
853    pub fn map_subqueries<F: FnMut(Self) -> Result<Transformed<Self>>>(
854        self,
855        mut f: F,
856    ) -> Result<Transformed<Self>> {
857        self.map_expressions(|expr| {
858            expr.transform_down(|expr| match expr {
859                Expr::Exists(Exists { subquery, negated }) => {
860                    f(LogicalPlan::Subquery(subquery))?.map_data(|s| match s {
861                        LogicalPlan::Subquery(subquery) => {
862                            Ok(Expr::Exists(Exists { subquery, negated }))
863                        }
864                        _ => internal_err!("Transformation should return Subquery"),
865                    })
866                }
867                Expr::InSubquery(InSubquery {
868                    expr,
869                    subquery,
870                    negated,
871                }) => f(LogicalPlan::Subquery(subquery))?.map_data(|s| match s {
872                    LogicalPlan::Subquery(subquery) => Ok(Expr::InSubquery(InSubquery {
873                        expr,
874                        subquery,
875                        negated,
876                    })),
877                    _ => internal_err!("Transformation should return Subquery"),
878                }),
879                Expr::SetComparison(SetComparison {
880                    expr,
881                    subquery,
882                    op,
883                    quantifier,
884                }) => f(LogicalPlan::Subquery(subquery))?.map_data(|s| match s {
885                    LogicalPlan::Subquery(subquery) => {
886                        Ok(Expr::SetComparison(SetComparison {
887                            expr,
888                            subquery,
889                            op,
890                            quantifier,
891                        }))
892                    }
893                    _ => internal_err!("Transformation should return Subquery"),
894                }),
895                Expr::ScalarSubquery(subquery) => f(LogicalPlan::Subquery(subquery))?
896                    .map_data(|s| match s {
897                        LogicalPlan::Subquery(subquery) => {
898                            Ok(Expr::ScalarSubquery(subquery))
899                        }
900                        _ => internal_err!("Transformation should return Subquery"),
901                    }),
902                _ => Ok(Transformed::no(expr)),
903            })
904        })
905    }
906
907    /// Similar to [`Self::map_subqueries`], but only applies `f` to
908    /// uncorrelated subqueries (those with no outer column references).
909    pub fn map_uncorrelated_subqueries<F: FnMut(Self) -> Result<Transformed<Self>>>(
910        self,
911        mut f: F,
912    ) -> Result<Transformed<Self>> {
913        self.map_subqueries(|subquery_plan| match &subquery_plan {
914            LogicalPlan::Subquery(sq) if sq.outer_ref_columns.is_empty() => {
915                f(subquery_plan)
916            }
917            _ => Ok(Transformed::no(subquery_plan)),
918        })
919    }
920}