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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
// 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 multiple `Union` operators into one.
//!
//! Nested negated unions are merged into the parent one by pushing
//! the Negate to all their branches.
use std::iter;
use crate::TransformArgs;
use expr::MirRelationExpr;
use repr::RelationType;
/// Fuses multiple `Union` operators into one.
#[derive(Debug)]
pub struct Union;
impl crate::Transform for Union {
fn transform(
&self,
relation: &mut MirRelationExpr,
_: TransformArgs,
) -> Result<(), crate::TransformError> {
relation.try_visit_mut_post(&mut |e| Ok(self.action(e)))
}
}
impl Union {
/// Fuses multiple `Union` operators into one.
/// Nested negated unions are merged into the parent one by pushing
/// the Negate to all their branches.
pub fn action(&self, relation: &mut MirRelationExpr) {
if let MirRelationExpr::Union { base, inputs } = relation {
let can_fuse = iter::once(&**base).chain(&*inputs).any(|input| -> bool {
match input {
MirRelationExpr::Union { .. } => true,
MirRelationExpr::Negate { input: inner_input } => {
if let MirRelationExpr::Union { .. } = **inner_input {
true
} else {
false
}
}
_ => false,
}
});
if can_fuse {
let mut new_inputs: Vec<MirRelationExpr> = vec![];
for input in iter::once(&mut **base).chain(inputs) {
let outer_input = input.take_dangerous();
match outer_input {
MirRelationExpr::Union { base, inputs } => {
new_inputs.push(*base);
new_inputs.extend(inputs);
}
MirRelationExpr::Negate {
input: ref inner_input,
} => {
if let MirRelationExpr::Union { base, inputs } = &**inner_input {
new_inputs.push(base.to_owned().negate());
new_inputs.extend(inputs.into_iter().map(|x| x.clone().negate()));
} else {
new_inputs.push(outer_input);
}
}
_ => new_inputs.push(outer_input),
}
}
// A valid relation type is only needed for empty unions, but an existing union
// is guaranteed to be non-empty given that it always has at least a base branch.
assert!(!new_inputs.is_empty());
*relation = MirRelationExpr::union_many(new_inputs, RelationType::empty());
}
}
}
}