Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an EXPLAIN option to show the Equivalences Analysis #30690

Merged
merged 3 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/adapter/src/explain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ where
/// In the long term, this method and [`explain_dataflow`] should be unified. In
/// order to do that, however, we first need to generalize the role
/// [`DataflowMetainfo`] as a carrier of metainformation for the optimization
/// pass in general, and not for a specific strucutre representing an
/// pass in general, and not for a specific structure representing an
/// intermediate result.
pub(crate) fn explain_plan<T>(
mut plan: T,
Expand Down
4 changes: 2 additions & 2 deletions src/adapter/src/explain/mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
//! The specialized [`Explain`] implementation for an [`MirRelationExpr`]
//! wrapped in an [`Explainable`] newtype struct allows us to interpret more
//! [`mz_repr::explain::ExplainConfig`] options. This is the case because
//! attribute derivation and let normalization are defined in [`mz_transform`]
//! and conssequently are not available for the default [`Explain`]
//! Analysis derivation and Let normalization are defined in [`mz_transform`]
//! and consequently are not available for the default [`Explain`]
//! implementation for [`MirRelationExpr`] in [`mz_expr`].

use mz_compute_types::dataflows::DataflowDescription;
Expand Down
44 changes: 22 additions & 22 deletions src/expr-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,12 @@ mod relation {
let constant = input.parse::<kw::Constant>()?;

let parse_typ = |input: ParseStream| -> syn::Result<RelationType> {
let attrs = attributes::parse_attributes(input)?;
let Some(column_types) = attrs.types else {
let msg = "Missing expected `types` attribute for Constant line";
let analyses = analyses::parse_analyses(input)?;
let Some(column_types) = analyses.types else {
let msg = "Missing expected `types` analyses for Constant line";
Err(Error::new(input.span(), msg))?
};
let keys = attrs.keys.unwrap_or_default();
let keys = analyses.keys.unwrap_or_default();
Ok(RelationType { column_types, keys })
};

Expand Down Expand Up @@ -200,13 +200,13 @@ mod relation {

if recursive {
let (mut ids, mut values, mut limits) = (vec![], vec![], vec![]);
for (id, attrs, value) in ctes.into_iter().rev() {
for (id, analyses, value) in ctes.into_iter().rev() {
let typ = {
let Some(column_types) = attrs.types else {
let msg = format!("`let {}` needs a `types` attribute", id);
let Some(column_types) = analyses.types else {
let msg = format!("`let {}` needs a `types` analyses", id);
Err(Error::new(with.span(), msg))?
};
let keys = attrs.keys.unwrap_or_default();
let keys = analyses.keys.unwrap_or_default();
RelationType { column_types, keys }
};

Expand Down Expand Up @@ -251,20 +251,20 @@ mod relation {
fn parse_cte(
ctx: CtxRef,
input: ParseStream,
) -> syn::Result<(LocalId, attributes::Attributes, MirRelationExpr)> {
) -> syn::Result<(LocalId, analyses::Analyses, MirRelationExpr)> {
let cte = input.parse::<kw::cte>()?;

let ident = input.parse::<syn::Ident>()?;
let id = parse_local_id(ident)?;

input.parse::<syn::Token![=]>()?;

let attrs = attributes::parse_attributes(input)?;
let analyses = analyses::parse_analyses(input)?;

let parse_value = ParseChildren::new(input, cte.span().start());
let value = parse_value.parse_one(ctx, parse_expr)?;

Ok((id, attrs, value))
Ok((id, analyses, value))
}

fn parse_project(ctx: CtxRef, input: ParseStream) -> Result {
Expand Down Expand Up @@ -953,7 +953,7 @@ mod scalar {
let typ = if input.eat(kw::null) {
packer.push(Datum::Null);
input.parse::<syn::Token![::]>()?;
attributes::parse_scalar_type(input)?.nullable(true)
analyses::parse_scalar_type(input)?.nullable(true)
} else {
match input.parse::<syn::Lit>()? {
syn::Lit::Str(l) => {
Expand Down Expand Up @@ -1237,21 +1237,21 @@ mod row {
}
}

mod attributes {
mod analyses {
use mz_repr::{ColumnType, ScalarType};

use super::*;

#[derive(Default)]
pub struct Attributes {
pub struct Analyses {
pub types: Option<Vec<ColumnType>>,
pub keys: Option<Vec<Vec<usize>>>,
}

pub fn parse_attributes(input: ParseStream) -> syn::Result<Attributes> {
let mut attributes = Attributes::default();
pub fn parse_analyses(input: ParseStream) -> syn::Result<Analyses> {
let mut analyses = Analyses::default();

// Attributes are optional, appearing after a `//` at the end of the
// Analyses are optional, appearing after a `//` at the end of the
// line. However, since the syn lexer eats comments, we assume that `//`
// was replaced with `::` upfront.
if input.eat(syn::Token![::]) {
Expand All @@ -1260,7 +1260,7 @@ mod attributes {

let (start, end) = (inner.span().start(), inner.span().end());
if start.line != end.line {
let msg = "attributes should not span more than one line".to_string();
let msg = "analyses should not span more than one line".to_string();
Err(Error::new(inner.span(), msg))?
}

Expand All @@ -1270,17 +1270,17 @@ mod attributes {
"types" => {
inner.parse::<syn::Token![:]>()?;
let value = inner.parse::<syn::LitStr>()?.value();
attributes.types = Some(parse_types.parse_str(&value)?);
analyses.types = Some(parse_types.parse_str(&value)?);
}
// TODO: support keys
key => {
let msg = format!("unexpected attribute type `{}`", key);
let msg = format!("unexpected analysis type `{}`", key);
Err(Error::new(inner.span(), msg))?;
}
}
}
}
Ok(attributes)
Ok(analyses)
}

fn parse_types(input: ParseStream) -> syn::Result<Vec<ColumnType>> {
Expand Down Expand Up @@ -1394,7 +1394,7 @@ mod def {
input.parse::<syn::Token![-]>()?;
let column_name = input.parse::<syn::Ident>()?.to_string();
input.parse::<syn::Token![:]>()?;
let column_type = attributes::parse_column_type(input)?;
let column_type = analyses::parse_column_type(input)?;
Ok((column_name, column_type))
}

Expand Down
64 changes: 34 additions & 30 deletions src/expr/src/explain/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use mz_ore::soft_assert_eq_or_log;
use mz_ore::str::{closure_to_display, separated, Indent, IndentLike, StrExt};
use mz_repr::explain::text::DisplayText;
use mz_repr::explain::{
CompactScalars, ExprHumanizer, HumanizedAttributes, IndexUsageType, Indices,
CompactScalars, ExprHumanizer, HumanizedAnalyses, IndexUsageType, Indices,
PlanRenderingContext, RenderingContext, ScalarOps,
};
use mz_repr::{Datum, Diff, GlobalId, Row};
Expand Down Expand Up @@ -46,8 +46,10 @@ where

if let Some(finishing) = &self.context.finishing {
if ctx.config.humanized_exprs {
let attrs = ctx.annotations.get(&self.plan.plan);
let cols = attrs.map(|attrs| attrs.column_names.clone()).flatten();
let analyses = ctx.annotations.get(&self.plan.plan);
let cols = analyses
.map(|analyses| analyses.column_names.clone())
.flatten();
mode.expr(finishing, cols.as_ref()).fmt_text(f, &mut ctx)?;
} else {
mode.expr(finishing, None).fmt_text(f, &mut ctx)?;
Expand Down Expand Up @@ -112,8 +114,10 @@ where
// If present, a RowSetFinishing always applies to the first rendered plan.
Some(finishing) if no == 0 => {
if ctx.config.humanized_exprs {
let attrs = ctx.annotations.get(plan.plan);
let cols = attrs.map(|attrs| attrs.column_names.clone()).flatten();
let analyses = ctx.annotations.get(plan.plan);
let cols = analyses
.map(|analyses| analyses.column_names.clone())
.flatten();
mode.expr(finishing, cols.as_ref()).fmt_text(f, ctx)?;
} else {
mode.expr(finishing, None).fmt_text(f, ctx)?;
Expand Down Expand Up @@ -295,7 +299,7 @@ impl MirRelationExpr {
Ok(rows) => {
if !rows.is_empty() {
write!(f, "{}Constant", ctx.indent)?;
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
ctx.indented(|ctx| {
fmt_text_constant_rows(
f,
Expand All @@ -306,7 +310,7 @@ impl MirRelationExpr {
})?;
} else {
write!(f, "{}Constant <empty>", ctx.indent)?;
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
}
}
Err(err) => {
Expand Down Expand Up @@ -338,11 +342,11 @@ impl MirRelationExpr {
Ok(())
})?;
write!(f, "{}Return", ctx.indent)?;
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
ctx.indented(|ctx| head.fmt_text(f, ctx))?;
} else {
write!(f, "{}Return", ctx.indent)?;
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
ctx.indented(|ctx| head.fmt_text(f, ctx))?;
writeln!(f, "{}With", ctx.indent)?;
ctx.indented(|ctx| {
Expand Down Expand Up @@ -379,7 +383,7 @@ impl MirRelationExpr {
unreachable!(); // We exclude this case in `as_explain_single_plan`.
} else {
write!(f, "{}Return", ctx.indent)?;
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
ctx.indented(|ctx| head.fmt_text(f, ctx))?;
write!(f, "{}With Mutually Recursive", ctx.indent)?;
if let Some(limit) = all_limits_same {
Expand Down Expand Up @@ -475,15 +479,15 @@ impl MirRelationExpr {
}
}
}
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
}
Project { outputs, input } => {
FmtNode {
fmt_root: |f, ctx| {
let outputs = mode.seq(outputs, self.column_names(ctx));
let outputs = CompactScalars(outputs);
write!(f, "{}Project ({})", ctx.indent, outputs)?;
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand All @@ -495,7 +499,7 @@ impl MirRelationExpr {
let scalars = mode.seq(scalars, self.column_names(ctx));
let scalars = CompactScalars(scalars);
write!(f, "{}Map ({})", ctx.indent, scalars)?;
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand All @@ -507,7 +511,7 @@ impl MirRelationExpr {
let exprs = mode.seq(exprs, input.column_names(ctx));
let exprs = CompactScalars(exprs);
write!(f, "{}FlatMap {}({})", ctx.indent, func, exprs)?;
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand All @@ -524,7 +528,7 @@ impl MirRelationExpr {
let predicates = separated(" AND ", predicates);
write!(f, "{}Filter {}", ctx.indent, predicates)?;
}
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand Down Expand Up @@ -557,7 +561,7 @@ impl MirRelationExpr {
write!(f, " type={}", name)?;
}

self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;

if ctx.config.join_impls {
let input_name = &|pos: usize| -> String {
Expand Down Expand Up @@ -712,7 +716,7 @@ impl MirRelationExpr {
Some(literal_constraints.clone()),
cse_id,
)?;
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
}
Reduce {
group_key,
Expand Down Expand Up @@ -749,7 +753,7 @@ impl MirRelationExpr {
if let Some(expected_group_size) = expected_group_size {
write!(f, " exp_group_size={}", expected_group_size)?;
}
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand Down Expand Up @@ -794,7 +798,7 @@ impl MirRelationExpr {
if let Some(expected_group_size) = expected_group_size {
write!(f, " exp_group_size={}", expected_group_size)?;
}
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand All @@ -804,7 +808,7 @@ impl MirRelationExpr {
FmtNode {
fmt_root: |f, ctx| {
write!(f, "{}Negate", ctx.indent)?;
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand All @@ -814,15 +818,15 @@ impl MirRelationExpr {
FmtNode {
fmt_root: |f, ctx| {
write!(f, "{}Threshold", ctx.indent)?;
self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
.render(f, ctx)?;
}
Union { base, inputs } => {
write!(f, "{}Union", ctx.indent)?;
self.fmt_attributes(f, ctx)?;
self.fmt_analyses(f, ctx)?;
ctx.indented(|ctx| {
base.fmt_text(f, ctx)?;
for input in inputs.iter() {
Expand All @@ -843,7 +847,7 @@ impl MirRelationExpr {
let keys = separated("], [", keys);
write!(f, " keys=[[{}]]", keys)?;

self.fmt_attributes(f, ctx)
self.fmt_analyses(f, ctx)
},
fmt_children: |f, ctx| input.fmt_text(f, ctx),
}
Expand All @@ -854,16 +858,16 @@ impl MirRelationExpr {
Ok(())
}

fn fmt_attributes(
fn fmt_analyses(
&self,
f: &mut fmt::Formatter<'_>,
ctx: &PlanRenderingContext<'_, MirRelationExpr>,
) -> fmt::Result {
if ctx.config.requires_attributes() {
if let Some(attrs) = ctx.annotations.get(self) {
writeln!(f, " {}", HumanizedAttributes::new(attrs, ctx))
if ctx.config.requires_analyses() {
if let Some(analyses) = ctx.annotations.get(self) {
writeln!(f, " {}", HumanizedAnalyses::new(analyses, ctx))
} else {
writeln!(f, " // error: no attrs for subtree in map")
writeln!(f, " // error: no analyses for subtree in map")
}
} else {
writeln!(f)
Expand All @@ -876,8 +880,8 @@ impl MirRelationExpr {
) -> Option<&Vec<String>> {
if !ctx.config.humanized_exprs {
None
} else if let Some(attrs) = ctx.annotations.get(self) {
attrs.column_names.as_ref()
} else if let Some(analyses) = ctx.annotations.get(self) {
analyses.column_names.as_ref()
} else {
None
}
Expand Down
Loading
Loading