This function continues the surgery that `implement_arrangements` started. (In theory, this function could be merged into `implement_arrangements`, but it would be a bit painful, because we need to access the join's `implementation` after `implement_arrangements`, which would be somewhat convoluted after what `install_lifted_mfp` does.) The given MFP should be the merged MFP from all the lifted
(new_join: &mut MirRelationExpr, mfp: MapFilterProject)
| 941 | /// - Canonicalizes scalar expressions in maps and filters with respect to the join equivalences. |
| 942 | /// See inline comment for more details. |
| 943 | fn install_lifted_mfp(new_join: &mut MirRelationExpr, mfp: MapFilterProject) { |
| 944 | if !mfp.is_identity() { |
| 945 | let (mut map, mut filter, project) = mfp.as_map_filter_project(); |
| 946 | if let MirRelationExpr::Join { equivalences, .. } = new_join { |
| 947 | for equivalence in equivalences.iter_mut() { |
| 948 | for expr in equivalence.iter_mut() { |
| 949 | // permute `equivalences` in light of the project being lifted |
| 950 | expr.permute(&project); |
| 951 | // if column references refer to mapped expressions that have been |
| 952 | // lifted, replace the column reference with the mapped expression. |
| 953 | expr.visit_mut_pre(&mut |e| { |
| 954 | // This has to be a loop! This is because it can happen that the new |
| 955 | // expression is again a column reference, in which case the visitor |
| 956 | // wouldn't be called on it again. (The visitation continues with the |
| 957 | // children of the new expression, but won't visit the new expression |
| 958 | // itself again.) |
| 959 | while let MirScalarExpr::Column(c, _) = e { |
| 960 | if *c >= mfp.input_arity { |
| 961 | *e = map[*c - mfp.input_arity].clone(); |
| 962 | } else { |
| 963 | break; |
| 964 | } |
| 965 | } |
| 966 | }); |
| 967 | } |
| 968 | } |
| 969 | // Canonicalize scalar expressions in maps and filters with respect to the join |
| 970 | // equivalences. This often makes some filters identical, which are then removed. |
| 971 | // The identical filters come from either |
| 972 | // - lifting several predicates that originally were pushed down by localizing to more |
| 973 | // than one inputs; |
| 974 | // - individual IS NOT NULL filters on each of the inputs, which become identical |
| 975 | // when rewritten using the join equivalences. |
| 976 | // (This allows for almost the same optimizations as when `Demand` |
| 977 | // used to insert Projections that were marking some columns to be |
| 978 | // identical, when Demand used to run after `JoinImplementation`.) |
| 979 | let canonicalizer_map = mz_expr::canonicalize::get_canonicalizer_map(equivalences); |
| 980 | for expr in map.iter_mut().chain(filter.iter_mut()) { |
| 981 | expr.visit_mut_post(&mut |e| { |
| 982 | if let Some(canonical_expr) = canonicalizer_map.get(e) { |
| 983 | *e = canonical_expr.clone(); |
| 984 | } |
| 985 | }) |
| 986 | } |
| 987 | } |
| 988 | *new_join = new_join.clone().map(map).filter(filter).project(project); |
| 989 | } |
| 990 | } |
| 991 | |
| 992 | /// Permute the keys in `order` to compensate for projections being lifted from inputs. |
| 993 | /// `lifted_projections` has an optional projection for each input. |
no test coverage detected