Skip to content

Commit 32a3939

Browse files
committed
Display qualifiers in EXPLAIN
Sometimes we display qualifiers in plan's Display, e.g. for `Column`, but sometimes not. This adds qualifiers to output for `Alias`, `SubqueryAlias` and in `LogicalPlan::display_indent_schema`. Qualifiers are sometimes necessary to understand the plan semantics, especially when dealing with duplicate names, e.g. in joins.
1 parent 293bf3e commit 32a3939

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

datafusion/expr/src/expr.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3456,7 +3456,15 @@ pub const UNNEST_COLUMN_PREFIX: &str = "UNNEST";
34563456
impl Display for Expr {
34573457
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
34583458
match self {
3459-
Expr::Alias(Alias { expr, name, .. }) => write!(f, "{expr} AS {name}"),
3459+
Expr::Alias(Alias {
3460+
expr,
3461+
relation,
3462+
name,
3463+
..
3464+
}) => match relation {
3465+
None => write!(f, "{expr} AS {name}"),
3466+
Some(relation) => write!(f, "{expr} AS {relation}.{name}"),
3467+
},
34603468
Expr::Column(c) => write!(f, "{c}"),
34613469
Expr::OuterReferenceColumn(_, c) => {
34623470
write!(f, "{OUTER_REFERENCE_COLUMN_PREFIX}({c})")

datafusion/expr/src/logical_plan/display.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::dml::CopyTo;
3131
use arrow::datatypes::Schema;
3232
use datafusion_common::display::GraphvizBuilder;
3333
use datafusion_common::tree_node::{TreeNodeRecursion, TreeNodeVisitor};
34-
use datafusion_common::{Column, DataFusionError};
34+
use datafusion_common::{Column, DFSchema, DataFusionError};
3535
use serde_json::json;
3636

3737
/// Formats plans with a single line per node. For example:
@@ -72,11 +72,7 @@ impl<'n> TreeNodeVisitor<'n> for IndentVisitor<'_, '_> {
7272
write!(self.f, "{:indent$}", "", indent = self.indent * 2)?;
7373
write!(self.f, "{}", plan.display())?;
7474
if self.with_schema {
75-
write!(
76-
self.f,
77-
" {}",
78-
display_schema(&plan.schema().as_ref().to_owned().into())
79-
)?;
75+
write!(self.f, " {}", display_df_schema(&plan.schema().as_ref()))?;
8076
}
8177

8278
self.indent += 1;
@@ -92,7 +88,7 @@ impl<'n> TreeNodeVisitor<'n> for IndentVisitor<'_, '_> {
9288
}
9389
}
9490

95-
/// Print the schema in a compact representation to `buf`
91+
/// Print the schema in a compact representation
9692
///
9793
/// For example: `foo:Utf8` if `foo` can not be null, and
9894
/// `foo:Utf8;N` if `foo` is nullable.
@@ -135,6 +131,38 @@ pub fn display_schema(schema: &Schema) -> impl fmt::Display + '_ {
135131
Wrapper(schema)
136132
}
137133

134+
/// Print the schema in a compact representation.
135+
/// Similar to `display_schema`, but includes field qualifiers if any.
136+
pub fn display_df_schema(schema: &DFSchema) -> impl fmt::Display + '_ {
137+
struct Wrapper<'a>(&'a DFSchema);
138+
139+
impl fmt::Display for Wrapper<'_> {
140+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141+
write!(f, "[")?;
142+
for (idx, (qualifier, field)) in self.0.iter().enumerate() {
143+
if idx > 0 {
144+
write!(f, ", ")?;
145+
}
146+
let nullable_str = if field.is_nullable() { ";N" } else { "" };
147+
write!(
148+
f,
149+
"{}{}:{:?}{}",
150+
if let Some(q) = qualifier {
151+
format!("{q}.")
152+
} else {
153+
"".to_string()
154+
},
155+
field.name(),
156+
field.data_type(),
157+
nullable_str
158+
)?;
159+
}
160+
write!(f, "]")
161+
}
162+
}
163+
Wrapper(schema)
164+
}
165+
138166
/// Formats plans for graphical display using the `DOT` language. This
139167
/// format can be visualized using software from
140168
/// [`graphviz`](https://graphviz.org/)

0 commit comments

Comments
 (0)