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.
910//! Fuses multiple `Union` operators into one.
1112use mz_expr::MirRelationExpr;
13use mz_expr::visit::Visit;
1415/// Fuses multiple `Union` operators into one.
16#[derive(Debug)]
17pub struct Union;
1819impl crate::Transform for Union {
20fn name(&self) -> &'static str {
21"UnionFusion"
22}
2324#[mz_ore::instrument(
25 target = "optimizer",
26 level = "debug",
27 fields(path.segment = "union")
28 )]
29fn actually_perform_transform(
30&self,
31 relation: &mut MirRelationExpr,
32_: &mut crate::TransformCtx,
33 ) -> Result<(), crate::TransformError> {
34 relation.visit_mut_post(&mut Self::action)?;
35 mz_repr::explain::trace_plan(&*relation);
36Ok(())
37 }
38}
3940impl Union {
41/// Fuses multiple `Union` operators into one.
42 ///
43 /// The order among children is maintained, and the action should be idempotent.
44 /// This action works best if other operators such as `Negate` and other linear
45 /// operators are pushed down through other `Union` operators.
46pub fn action(relation: &mut MirRelationExpr) {
47if let MirRelationExpr::Union { inputs, .. } = relation {
48let mut list: Vec<MirRelationExpr> = Vec::with_capacity(1 + inputs.len());
49Self::unfold_unions_into(relation.take_dangerous(), &mut list);
50*relation = MirRelationExpr::Union {
51 base: Box::new(list.remove(0)),
52 inputs: list,
53 }
54 }
55 }
5657/// Unfolds `self` and children into a list of expressions that can be unioned.
58fn unfold_unions_into(expr: MirRelationExpr, list: &mut Vec<MirRelationExpr>) {
59let mut stack = vec![expr];
60while let Some(expr) = stack.pop() {
61if let MirRelationExpr::Union { base, inputs } = expr {
62 stack.extend(inputs.into_iter().rev());
63 stack.push(*base);
64 } else {
65 list.push(expr);
66 }
67 }
68 }
69}