The function projects / unprojects an expression with respect to set of projection expressions. See also [`ProjectionExprs::unproject_expr`] and [`ProjectionExprs::project_expr`] 1) When `unproject` is `true`: Rewrites an expression with respect to the projection expressions, effectively "unprojecting" it to reference the original input columns. For example, given the expressions `a@1 + b@2` a
(
expr: &Arc<dyn PhysicalExpr>,
projected_exprs: &[ProjectionExpr],
unproject: bool,
)
| 936 | /// |
| 937 | /// In this case, `a@3` references index 3, which is out of bounds for `projected_exprs` (which has length 2). |
| 938 | pub fn update_expr( |
| 939 | expr: &Arc<dyn PhysicalExpr>, |
| 940 | projected_exprs: &[ProjectionExpr], |
| 941 | unproject: bool, |
| 942 | ) -> Result<Option<Arc<dyn PhysicalExpr>>> { |
| 943 | #[derive(Debug, PartialEq)] |
| 944 | enum RewriteState { |
| 945 | /// The expression is unchanged. |
| 946 | Unchanged, |
| 947 | /// Some part of the expression has been rewritten |
| 948 | RewrittenValid, |
| 949 | /// Some part of the expression has been rewritten, but some column |
| 950 | /// references could not be. |
| 951 | RewrittenInvalid, |
| 952 | } |
| 953 | |
| 954 | let mut state = RewriteState::Unchanged; |
| 955 | |
| 956 | let new_expr = Arc::clone(expr) |
| 957 | .transform_up(|expr| { |
| 958 | if state == RewriteState::RewrittenInvalid { |
| 959 | return Ok(Transformed::no(expr)); |
| 960 | } |
| 961 | |
| 962 | let Some(column) = expr.downcast_ref::<Column>() else { |
| 963 | return Ok(Transformed::no(expr)); |
| 964 | }; |
| 965 | if unproject { |
| 966 | state = RewriteState::RewrittenValid; |
| 967 | // Update the index of `column`: |
| 968 | let projected_expr = projected_exprs.get(column.index()).ok_or_else(|| { |
| 969 | internal_datafusion_err!( |
| 970 | "Column index {} out of bounds for projected expressions of length {}", |
| 971 | column.index(), |
| 972 | projected_exprs.len() |
| 973 | ) |
| 974 | })?; |
| 975 | Ok(Transformed::yes(Arc::clone(&projected_expr.expr))) |
| 976 | } else { |
| 977 | // default to invalid, in case we can't find the relevant column |
| 978 | state = RewriteState::RewrittenInvalid; |
| 979 | // Determine how to update `column` to accommodate `projected_exprs` |
| 980 | projected_exprs |
| 981 | .iter() |
| 982 | .enumerate() |
| 983 | .find_map(|(index, proj_expr)| { |
| 984 | proj_expr.expr.downcast_ref::<Column>().and_then( |
| 985 | |projected_column| { |
| 986 | (column.name().eq(projected_column.name()) |
| 987 | && column.index() == projected_column.index()) |
| 988 | .then(|| { |
| 989 | state = RewriteState::RewrittenValid; |
| 990 | Arc::new(Column::new(&proj_expr.alias, index)) as _ |
| 991 | }) |
| 992 | }, |
| 993 | ) |
| 994 | }) |
| 995 | .map_or_else( |
searching dependent graphs…