Skip to main content

mz_adapter/explain/
mir.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//! `EXPLAIN` support for MIR structures.
11//!
12//! The specialized [`Explain`] implementation for an [`MirRelationExpr`]
13//! wrapped in an [`Explainable`] newtype struct allows us to interpret more
14//! [`mz_repr::explain::ExplainConfig`] options. This is the case because
15//! Analysis derivation and Let normalization are defined in [`mz_transform`]
16//! and consequently are not available for the default [`Explain`]
17//! implementation for [`MirRelationExpr`] in [`mz_expr`].
18
19use std::borrow::Cow;
20
21use mz_compute_types::dataflows::DataflowDescription;
22use mz_compute_types::explain::export_ids_for;
23use mz_expr::explain::{
24    ExplainContext, ExplainMultiPlan, ExplainSinglePlan, ExplainSource, enforce_linear_chains,
25};
26use mz_expr::{MirRelationExpr, OptimizedMirRelationExpr};
27use mz_repr::explain::{Explain, ExplainError, UnsupportedFormat};
28use mz_transform::analysis::annotate_plan;
29use mz_transform::normalize_lets::normalize_lets;
30
31use crate::explain::Explainable;
32
33impl<'a> Explain<'a> for Explainable<'a, MirRelationExpr> {
34    type Context = ExplainContext<'a>;
35
36    type Text = ExplainSinglePlan<'a, MirRelationExpr>;
37
38    type Json = ExplainSinglePlan<'a, MirRelationExpr>;
39
40    type Dot = UnsupportedFormat;
41
42    fn explain_text(&'a mut self, context: &'a Self::Context) -> Result<Self::Text, ExplainError> {
43        self.as_explain_single_plan(context)
44    }
45
46    fn explain_json(&'a mut self, context: &'a Self::Context) -> Result<Self::Json, ExplainError> {
47        self.as_explain_single_plan(context)
48    }
49}
50
51impl<'a> Explainable<'a, MirRelationExpr> {
52    fn as_explain_single_plan(
53        &'a mut self,
54        context: &'a ExplainContext<'a>,
55    ) -> Result<ExplainSinglePlan<'a, MirRelationExpr>, ExplainError> {
56        // normalize the representation as linear chains
57        // (this implies !context.config.raw_plans by construction)
58        if context.config.linear_chains {
59            enforce_linear_chains(self.0)?;
60        };
61        // unless raw plans are explicitly requested
62        // normalize the representation of nested Let bindings
63        // and enforce sequential Let binding IDs
64        if !context.config.raw_plans {
65            normalize_lets(self.0, context.features)
66                .map_err(|e| ExplainError::UnknownError(e.to_string()))?;
67        }
68
69        Ok(ExplainSinglePlan {
70            context,
71            plan: annotate_plan(self.0, context)?,
72        })
73    }
74}
75
76impl<'a> Explain<'a> for Explainable<'a, DataflowDescription<OptimizedMirRelationExpr>> {
77    type Context = ExplainContext<'a>;
78
79    type Text = ExplainMultiPlan<'a, MirRelationExpr>;
80
81    type Json = ExplainMultiPlan<'a, MirRelationExpr>;
82
83    type Dot = UnsupportedFormat;
84
85    fn explain_text(&'a mut self, context: &'a Self::Context) -> Result<Self::Text, ExplainError> {
86        self.as_explain_multi_plan(context)
87    }
88
89    fn explain_json(&'a mut self, context: &'a Self::Context) -> Result<Self::Text, ExplainError> {
90        self.as_explain_multi_plan(context)
91    }
92}
93
94impl<'a> Explainable<'a, DataflowDescription<OptimizedMirRelationExpr>> {
95    fn as_explain_multi_plan(
96        &'a mut self,
97        context: &'a ExplainContext<'a>,
98    ) -> Result<ExplainMultiPlan<'a, MirRelationExpr>, ExplainError> {
99        let export_ids = export_ids_for(self.0);
100        let plans = self
101            .0
102            .objects_to_build
103            .iter_mut()
104            .rev()
105            .map(|build_desc| {
106                let plan = build_desc.plan.as_inner_mut();
107
108                // normalize the representation as linear chains
109                // (this implies !context.config.raw_plans by construction)
110                if context.config.linear_chains {
111                    enforce_linear_chains(plan)?;
112                };
113                // unless raw plans are explicitly requested
114                // normalize the representation of nested Let bindings
115                // and enforce sequential Let binding IDs
116                if !context.config.raw_plans {
117                    normalize_lets(plan, context.features)
118                        .map_err(|e| ExplainError::UnknownError(e.to_string()))?;
119                }
120
121                let public_id = export_ids
122                    .get(&build_desc.id)
123                    .unwrap_or(&build_desc.id)
124                    .clone();
125                let id = context
126                    .humanizer
127                    .humanize_id(public_id)
128                    .unwrap_or_else(|| public_id.to_string());
129
130                Ok((id, annotate_plan(plan, context)?))
131            })
132            .collect::<Result<Vec<_>, ExplainError>>()?;
133
134        let sources = self
135            .0
136            .source_imports
137            .iter_mut()
138            .map(|(id, import)| {
139                let op = import.desc.arguments.operators.as_ref().map(Cow::Borrowed);
140                ExplainSource::new(*id, op, context.config.filter_pushdown)
141            })
142            .collect::<Vec<_>>();
143
144        Ok(ExplainMultiPlan {
145            context,
146            sources,
147            plans,
148        })
149    }
150}