This downward traversal needs to keep track of: - Whether or not some unnest expr has been visited from the top until the current node - If some unnest expr has been visited, maintain a stack of such information, this is used to detect if some recursive unnest expr exists (e.g **unnest(unnest(unnest(3d column))))
(&mut self, expr: Expr)
| 504 | /// - If some unnest expr has been visited, maintain a stack of such information, this |
| 505 | /// is used to detect if some recursive unnest expr exists (e.g **unnest(unnest(unnest(3d column))))** |
| 506 | fn f_down(&mut self, expr: Expr) -> Result<Transformed<Expr>> { |
| 507 | if let Expr::Unnest(ref unnest_expr) = expr { |
| 508 | let field = unnest_expr.expr.to_field(self.input_schema)?.1; |
| 509 | let data_type = field.data_type(); |
| 510 | self.consecutive_unnest.push(Some(unnest_expr.clone())); |
| 511 | // if expr inside unnest is a struct, do not consider |
| 512 | // the next unnest as consecutive unnest (if any) |
| 513 | // meaning unnest(unnest(struct_arr_col)) can't |
| 514 | // be interpreted as unnest(struct_arr_col, depth:=2) |
| 515 | // but has to be split into multiple unnest logical plan instead |
| 516 | // a.k.a: |
| 517 | // - unnest(struct_col) |
| 518 | // unnest(struct_arr_col) as struct_col |
| 519 | |
| 520 | if let DataType::Struct(_) = data_type { |
| 521 | self.consecutive_unnest.push(None); |
| 522 | } |
| 523 | if self.top_most_unnest.is_none() { |
| 524 | self.top_most_unnest = Some(unnest_expr.clone()); |
| 525 | } |
| 526 | |
| 527 | Ok(Transformed::no(expr)) |
| 528 | } else { |
| 529 | self.consecutive_unnest.push(None); |
| 530 | Ok(Transformed::no(expr)) |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | /// The rewriting only happens when the traversal has reached the top-most unnest expr |
| 535 | /// within a sequence of consecutive unnest exprs node |