1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.
//! Fuses a sequence of `Map` operators in to one `Map` operator.
//!
//! This transform introduces the complexity that max expressions can
//! refer to the results of prior map expressions. This is an important
//! detail that is often overlooked and leads to bugs. However, it is
//! important to coalesce these operators so that we can more easily
//! move them around other operators together.
//!
//! Also removes empty `Map` operators.
use std::mem;
use mz_expr::MirRelationExpr;
use crate::TransformCtx;
/// Fuses a sequence of `Map` operators in to one `Map` operator.
#[derive(Debug)]
pub struct Map;
impl crate::Transform for Map {
#[mz_ore::instrument(
target = "optimizer",
level = "debug",
fields(path.segment = "map_fusion")
)]
fn transform(
&self,
relation: &mut MirRelationExpr,
_: &mut TransformCtx,
) -> Result<(), crate::TransformError> {
relation.visit_pre_mut(Self::action);
mz_repr::explain::trace_plan(&*relation);
Ok(())
}
}
impl Map {
/// Fuses a sequence of `Map` operators into one `Map` operator.
/// Remove the map operator if it is empty.
pub fn action(relation: &mut MirRelationExpr) {
if let MirRelationExpr::Map { input, scalars } = relation {
while let MirRelationExpr::Map {
input: inner_input,
scalars: inner_scalars,
} = &mut **input
{
inner_scalars.append(scalars);
mem::swap(scalars, inner_scalars);
**input = inner_input.take_dangerous();
}
if scalars.is_empty() {
*relation = input.take_dangerous();
}
}
}
}