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