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 84
// 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.
//! Turns `FlatMap` into `Map` if only one row is produced by flatmap.
//!
use mz_expr::visit::Visit;
use mz_expr::{MirRelationExpr, TableFunc};
use crate::TransformCtx;
/// Turns `FlatMap` into `Map` if only one row is produced by flatmap.
#[derive(Debug)]
pub struct FlatMapToMap;
impl crate::Transform for FlatMapToMap {
fn name(&self) -> &'static str {
"FlatMapToMap"
}
#[mz_ore::instrument(
target = "optimizer",
level = "debug",
fields(path.segment = "flatmap_to_map")
)]
fn actually_perform_transform(
&self,
relation: &mut MirRelationExpr,
_: &mut TransformCtx,
) -> Result<(), crate::TransformError> {
relation.visit_mut_post(&mut Self::action)?;
mz_repr::explain::trace_plan(&*relation);
Ok(())
}
}
impl FlatMapToMap {
/// Turns `FlatMap` into `Map` if only one row is produced by flatmap.
pub fn action(relation: &mut MirRelationExpr) {
if let MirRelationExpr::FlatMap { func, exprs, input } = relation {
if let TableFunc::Wrap { width, .. } = func {
if *width >= exprs.len() {
*relation = input.take_dangerous().map(std::mem::take(exprs));
}
} else if is_supported_unnest(func) {
let func = func.clone();
let exprs = exprs.clone();
use mz_expr::MirScalarExpr;
use mz_repr::RowArena;
if let MirScalarExpr::Literal(Ok(row), ..) = &exprs[0] {
let temp_storage = RowArena::default();
if let Ok(mut iter) = func.eval(&[row.iter().next().unwrap()], &temp_storage) {
match (iter.next(), iter.next()) {
(None, _) => {
// If there are no elements in the literal argument, no output.
relation.take_safely();
}
(Some((row, 1)), None) => {
*relation =
input.take_dangerous().map(vec![MirScalarExpr::Literal(
Ok(row),
func.output_type().column_types[0].clone(),
)]);
}
_ => {}
}
};
}
}
}
}
}
/// Returns `true` for `unnest_~` variants supported by [`FlatMapToMap`].
fn is_supported_unnest(func: &TableFunc) -> bool {
use TableFunc::*;
matches!(func, UnnestArray { .. } | UnnestList { .. })
}