mz_transform/fusion/
project.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Fuses Project operators with parent operators when possible.
11
12// TODO(frank): evaluate for redundancy with projection hoisting.
13
14use mz_expr::MirRelationExpr;
15
16use crate::TransformCtx;
17
18/// Fuses Project operators with parent operators when possible.
19#[derive(Debug)]
20pub struct Project;
21
22impl crate::Transform for Project {
23    fn name(&self) -> &'static str {
24        "ProjectFusion"
25    }
26
27    #[mz_ore::instrument(
28        target = "optimizer",
29        level = "debug",
30        fields(path.segment = "project_fusion")
31    )]
32    fn actually_perform_transform(
33        &self,
34        relation: &mut MirRelationExpr,
35        _: &mut TransformCtx,
36    ) -> Result<(), crate::TransformError> {
37        relation.visit_pre_mut(Self::action);
38        mz_repr::explain::trace_plan(&*relation);
39        Ok(())
40    }
41}
42
43impl Project {
44    /// Fuses Project operators with parent operators when possible.
45    pub fn action(relation: &mut MirRelationExpr) {
46        if let MirRelationExpr::Project { input, outputs } = relation {
47            while let MirRelationExpr::Project {
48                input: inner,
49                outputs: outputs2,
50            } = &mut **input
51            {
52                *outputs = outputs.iter().map(|i| outputs2[*i]).collect();
53                **input = inner.take_dangerous();
54            }
55            if outputs.iter().enumerate().all(|(a, b)| a == *b) && outputs.len() == input.arity() {
56                *relation = input.take_dangerous();
57            }
58        }
59    }
60}