MCPcopy Create free account
hub / github.com/apache/datafusion / f_up

Method f_up

datafusion/sql/src/utils.rs:562–624  ·  view source on GitHub ↗

The rewriting only happens when the traversal has reached the top-most unnest expr within a sequence of consecutive unnest exprs node For example an expr of **unnest(unnest(column1)) + unnest(unnest(unnest(column2))) ```text ┌──────────────────┐ │ binaryexpr │ │ │ └──────────────────┘ f_down / / │ │ / / f_up │ │ / / f_down│ │f_up unnest

(&mut self, expr: Expr)

Source from the content-addressed store, hash-verified

560 /// column2
561 /// ```
562 fn f_up(&mut self, expr: Expr) -> Result<Transformed<Expr>> {
563 if let Expr::Unnest(ref traversing_unnest) = expr {
564 if traversing_unnest == self.top_most_unnest.as_ref().unwrap() {
565 self.top_most_unnest = None;
566 }
567 // Find inside consecutive_unnest, the sequence of continuous unnest exprs
568
569 // Get the latest consecutive unnest exprs
570 // and check if current upward traversal is the returning to the root expr
571 // for example given a expr `unnest(unnest(col))` then the traversal happens like:
572 // down(unnest) -> down(unnest) -> down(col) -> up(col) -> up(unnest) -> up(unnest)
573 // the result of such traversal is unnest(col, depth:=2)
574 let unnest_stack = self.get_latest_consecutive_unnest();
575
576 // This traversal has reached the top most unnest again
577 // e.g Unnest(top) -> Unnest(2nd) -> Column(bottom)
578 // -> Unnest(2nd) -> Unnest(top) a.k.a here
579 // Thus
580 // Unnest(Unnest(some_col)) is rewritten into Unnest(some_col, depth:=2)
581 if traversing_unnest == unnest_stack.last().unwrap() {
582 let most_inner = unnest_stack.first().unwrap();
583 let inner_expr = most_inner.expr.as_ref();
584 // unnest(unnest(struct_arr_col)) is not allow to be done recursively
585 // it needs to be split into multiple unnest logical plan
586 // unnest(struct_arr)
587 // unnest(struct_arr_col) as struct_arr
588 // instead of unnest(struct_arr_col, depth = 2)
589
590 let unnest_recursion = unnest_stack.len();
591 let struct_allowed =
592 self.is_at_struct_allowed_root(&expr) && unnest_recursion == 1;
593
594 let mut transformed_exprs = self.transform(
595 unnest_recursion,
596 expr.schema_name().to_string(),
597 inner_expr,
598 struct_allowed,
599 )?;
600 // Only set transformed_root_exprs for struct unnest (which returns multiple expressions).
601 // For list unnest (single expression), we let the normal rewrite handle the alias.
602 if struct_allowed && transformed_exprs.len() > 1 {
603 self.transformed_root_exprs = Some(transformed_exprs.clone());
604 }
605 return Ok(Transformed::new(
606 transformed_exprs.swap_remove(0),
607 true,
608 TreeNodeRecursion::Continue,
609 ));
610 }
611 } else {
612 self.consecutive_unnest.push(None);
613 }
614
615 // For column exprs that are not descendants of any unnest node
616 // retain their projection
617 // e.g given expr tree unnest(col_a) + col_b, we have to retain projection of col_b
618 // this condition can be checked by maintaining an Option<top most unnest>
619 if matches!(&expr, Expr::Column(_)) && self.top_most_unnest.is_none() {

Callers

nothing calls this directly

Calls 14

newFunction · 0.85
push_projection_deduplFunction · 0.85
lastMethod · 0.80
is_noneMethod · 0.80
as_refMethod · 0.45
firstMethod · 0.45
lenMethod · 0.45
transformMethod · 0.45
to_stringMethod · 0.45
schema_nameMethod · 0.45

Tested by

no test coverage detected