Skip to content

Commit 60f9ad9

Browse files
committed
Use schema_name to create the physical_name
More consistency and less opportunity for column name mismatch.
1 parent 482ef45 commit 60f9ad9

File tree

4 files changed

+17
-273
lines changed

4 files changed

+17
-273
lines changed

datafusion/core/src/physical_planner.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ use datafusion_common::{
7373
};
7474
use datafusion_expr::dml::CopyTo;
7575
use datafusion_expr::expr::{
76-
self, create_function_physical_name, physical_name, AggregateFunction, Alias,
77-
GroupingSet, WindowFunction,
76+
self, physical_name, AggregateFunction, Alias, GroupingSet, WindowFunction,
7877
};
7978
use datafusion_expr::expr_rewriter::unnormalize_cols;
8079
use datafusion_expr::logical_plan::builder::wrap_projection_for_join_if_necessary;
@@ -1563,12 +1562,7 @@ pub fn create_aggregate_expr_with_name_and_maybe_filter(
15631562
let name = if let Some(name) = name {
15641563
name
15651564
} else {
1566-
create_function_physical_name(
1567-
func.name(),
1568-
*distinct,
1569-
args,
1570-
order_by.as_ref(),
1571-
)?
1565+
physical_name(e)?
15721566
};
15731567

15741568
let physical_args =
@@ -1582,8 +1576,7 @@ pub fn create_aggregate_expr_with_name_and_maybe_filter(
15821576
None => None,
15831577
};
15841578

1585-
let ignore_nulls = null_treatment
1586-
.unwrap_or(sqlparser::ast::NullTreatment::RespectNulls)
1579+
let ignore_nulls = null_treatment.unwrap_or(NullTreatment::RespectNulls)
15871580
== NullTreatment::IgnoreNulls;
15881581

15891582
let (agg_expr, filter, order_by) = {

datafusion/expr/src/expr.rs

Lines changed: 12 additions & 260 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ use datafusion_common::tree_node::{
3838
Transformed, TransformedResult, TreeNode, TreeNodeRecursion,
3939
};
4040
use datafusion_common::{
41-
internal_err, not_impl_err, plan_err, Column, DFSchema, Result, ScalarValue,
42-
TableReference,
41+
plan_err, Column, DFSchema, Result, ScalarValue, TableReference,
4342
};
4443
use sqlparser::ast::{
4544
display_comma_separated, ExceptSelectItem, ExcludeSelectItem, IlikeSelectItem,
@@ -1082,7 +1081,7 @@ impl Expr {
10821081
/// For example, for a projection (e.g. `SELECT <expr>`) the resulting arrow
10831082
/// [`Schema`] will have a field with this name.
10841083
///
1085-
/// Note that the resulting string is subtlety different than the `Display`
1084+
/// Note that the resulting string is subtlety different from the `Display`
10861085
/// representation for certain `Expr`. Some differences:
10871086
///
10881087
/// 1. [`Expr::Alias`], which shows only the alias itself
@@ -1104,6 +1103,7 @@ impl Expr {
11041103
}
11051104

11061105
/// Returns a full and complete string representation of this expression.
1106+
#[deprecated(note = "use format! instead")]
11071107
pub fn canonical_name(&self) -> String {
11081108
format!("{self}")
11091109
}
@@ -2386,263 +2386,13 @@ fn fmt_function(
23862386
write!(f, "{}({}{})", fun, distinct_str, args.join(", "))
23872387
}
23882388

2389-
pub fn create_function_physical_name(
2390-
fun: &str,
2391-
distinct: bool,
2392-
args: &[Expr],
2393-
order_by: Option<&Vec<Expr>>,
2394-
) -> Result<String> {
2395-
let names: Vec<String> = args
2396-
.iter()
2397-
.map(|e| create_physical_name(e, false))
2398-
.collect::<Result<_>>()?;
2399-
2400-
let distinct_str = match distinct {
2401-
true => "DISTINCT ",
2402-
false => "",
2403-
};
2404-
2405-
let phys_name = format!("{}({}{})", fun, distinct_str, names.join(","));
2406-
2407-
Ok(order_by
2408-
.map(|order_by| format!("{} ORDER BY [{}]", phys_name, expr_vec_fmt!(order_by)))
2409-
.unwrap_or(phys_name))
2410-
}
2411-
2412-
pub fn physical_name(e: &Expr) -> Result<String> {
2413-
create_physical_name(e, true)
2414-
}
2415-
2416-
fn create_physical_name(e: &Expr, is_first_expr: bool) -> Result<String> {
2417-
match e {
2418-
Expr::Unnest(_) => {
2419-
internal_err!(
2420-
"Expr::Unnest should have been converted to LogicalPlan::Unnest"
2421-
)
2422-
}
2423-
Expr::Column(c) => {
2424-
if is_first_expr {
2425-
Ok(c.name.clone())
2426-
} else {
2427-
Ok(c.flat_name())
2428-
}
2429-
}
2430-
Expr::Alias(Alias { name, .. }) => Ok(name.clone()),
2431-
Expr::ScalarVariable(_, variable_names) => Ok(variable_names.join(".")),
2432-
Expr::Literal(value) => Ok(format!("{value:?}")),
2433-
Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
2434-
let left = create_physical_name(left, false)?;
2435-
let right = create_physical_name(right, false)?;
2436-
Ok(format!("{left} {op} {right}"))
2437-
}
2438-
Expr::Case(case) => {
2439-
let mut name = "CASE ".to_string();
2440-
if let Some(e) = &case.expr {
2441-
let _ = write!(name, "{} ", create_physical_name(e, false)?);
2442-
}
2443-
for (w, t) in &case.when_then_expr {
2444-
let _ = write!(
2445-
name,
2446-
"WHEN {} THEN {} ",
2447-
create_physical_name(w, false)?,
2448-
create_physical_name(t, false)?
2449-
);
2450-
}
2451-
if let Some(e) = &case.else_expr {
2452-
let _ = write!(name, "ELSE {} ", create_physical_name(e, false)?);
2453-
}
2454-
name += "END";
2455-
Ok(name)
2456-
}
2457-
Expr::Cast(Cast { expr, .. }) => {
2458-
// CAST does not change the expression name
2459-
create_physical_name(expr, false)
2460-
}
2461-
Expr::TryCast(TryCast { expr, .. }) => {
2462-
// CAST does not change the expression name
2463-
create_physical_name(expr, false)
2464-
}
2465-
Expr::Not(expr) => {
2466-
let expr = create_physical_name(expr, false)?;
2467-
Ok(format!("NOT {expr}"))
2468-
}
2469-
Expr::Negative(expr) => {
2470-
let expr = create_physical_name(expr, false)?;
2471-
Ok(format!("(- {expr})"))
2472-
}
2473-
Expr::IsNull(expr) => {
2474-
let expr = create_physical_name(expr, false)?;
2475-
Ok(format!("{expr} IS NULL"))
2476-
}
2477-
Expr::IsNotNull(expr) => {
2478-
let expr = create_physical_name(expr, false)?;
2479-
Ok(format!("{expr} IS NOT NULL"))
2480-
}
2481-
Expr::IsTrue(expr) => {
2482-
let expr = create_physical_name(expr, false)?;
2483-
Ok(format!("{expr} IS TRUE"))
2484-
}
2485-
Expr::IsFalse(expr) => {
2486-
let expr = create_physical_name(expr, false)?;
2487-
Ok(format!("{expr} IS FALSE"))
2488-
}
2489-
Expr::IsUnknown(expr) => {
2490-
let expr = create_physical_name(expr, false)?;
2491-
Ok(format!("{expr} IS UNKNOWN"))
2492-
}
2493-
Expr::IsNotTrue(expr) => {
2494-
let expr = create_physical_name(expr, false)?;
2495-
Ok(format!("{expr} IS NOT TRUE"))
2496-
}
2497-
Expr::IsNotFalse(expr) => {
2498-
let expr = create_physical_name(expr, false)?;
2499-
Ok(format!("{expr} IS NOT FALSE"))
2500-
}
2501-
Expr::IsNotUnknown(expr) => {
2502-
let expr = create_physical_name(expr, false)?;
2503-
Ok(format!("{expr} IS NOT UNKNOWN"))
2504-
}
2505-
Expr::ScalarFunction(fun) => fun.func.schema_name(&fun.args),
2506-
Expr::WindowFunction(WindowFunction {
2507-
fun,
2508-
args,
2509-
order_by,
2510-
..
2511-
}) => {
2512-
create_function_physical_name(&fun.to_string(), false, args, Some(order_by))
2513-
}
2514-
Expr::AggregateFunction(AggregateFunction {
2515-
func,
2516-
distinct,
2517-
args,
2518-
filter: _,
2519-
order_by,
2520-
null_treatment: _,
2521-
}) => {
2522-
create_function_physical_name(func.name(), *distinct, args, order_by.as_ref())
2523-
}
2524-
Expr::GroupingSet(grouping_set) => match grouping_set {
2525-
GroupingSet::Rollup(exprs) => Ok(format!(
2526-
"ROLLUP ({})",
2527-
exprs
2528-
.iter()
2529-
.map(|e| create_physical_name(e, false))
2530-
.collect::<Result<Vec<_>>>()?
2531-
.join(", ")
2532-
)),
2533-
GroupingSet::Cube(exprs) => Ok(format!(
2534-
"CUBE ({})",
2535-
exprs
2536-
.iter()
2537-
.map(|e| create_physical_name(e, false))
2538-
.collect::<Result<Vec<_>>>()?
2539-
.join(", ")
2540-
)),
2541-
GroupingSet::GroupingSets(lists_of_exprs) => {
2542-
let mut strings = vec![];
2543-
for exprs in lists_of_exprs {
2544-
let exprs_str = exprs
2545-
.iter()
2546-
.map(|e| create_physical_name(e, false))
2547-
.collect::<Result<Vec<_>>>()?
2548-
.join(", ");
2549-
strings.push(format!("({exprs_str})"));
2550-
}
2551-
Ok(format!("GROUPING SETS ({})", strings.join(", ")))
2552-
}
2553-
},
2554-
2555-
Expr::InList(InList {
2556-
expr,
2557-
list,
2558-
negated,
2559-
}) => {
2560-
let expr = create_physical_name(expr, false)?;
2561-
let list = list.iter().map(|expr| create_physical_name(expr, false));
2562-
if *negated {
2563-
Ok(format!("{expr} NOT IN ({list:?})"))
2564-
} else {
2565-
Ok(format!("{expr} IN ({list:?})"))
2566-
}
2567-
}
2568-
Expr::Exists { .. } => {
2569-
not_impl_err!("EXISTS is not yet supported in the physical plan")
2570-
}
2571-
Expr::InSubquery(_) => {
2572-
not_impl_err!("IN subquery is not yet supported in the physical plan")
2573-
}
2574-
Expr::ScalarSubquery(_) => {
2575-
not_impl_err!("Scalar subqueries are not yet supported in the physical plan")
2576-
}
2577-
Expr::Between(Between {
2578-
expr,
2579-
negated,
2580-
low,
2581-
high,
2582-
}) => {
2583-
let expr = create_physical_name(expr, false)?;
2584-
let low = create_physical_name(low, false)?;
2585-
let high = create_physical_name(high, false)?;
2586-
if *negated {
2587-
Ok(format!("{expr} NOT BETWEEN {low} AND {high}"))
2588-
} else {
2589-
Ok(format!("{expr} BETWEEN {low} AND {high}"))
2590-
}
2591-
}
2592-
Expr::Like(Like {
2593-
negated,
2594-
expr,
2595-
pattern,
2596-
escape_char,
2597-
case_insensitive,
2598-
}) => {
2599-
let expr = create_physical_name(expr, false)?;
2600-
let pattern = create_physical_name(pattern, false)?;
2601-
let op_name = if *case_insensitive { "ILIKE" } else { "LIKE" };
2602-
let escape = if let Some(char) = escape_char {
2603-
format!("CHAR '{char}'")
2604-
} else {
2605-
"".to_string()
2606-
};
2607-
if *negated {
2608-
Ok(format!("{expr} NOT {op_name} {pattern}{escape}"))
2609-
} else {
2610-
Ok(format!("{expr} {op_name} {pattern}{escape}"))
2611-
}
2612-
}
2613-
Expr::SimilarTo(Like {
2614-
negated,
2615-
expr,
2616-
pattern,
2617-
escape_char,
2618-
case_insensitive: _,
2619-
}) => {
2620-
let expr = create_physical_name(expr, false)?;
2621-
let pattern = create_physical_name(pattern, false)?;
2622-
let escape = if let Some(char) = escape_char {
2623-
format!("CHAR '{char}'")
2624-
} else {
2625-
"".to_string()
2626-
};
2627-
if *negated {
2628-
Ok(format!("{expr} NOT SIMILAR TO {pattern}{escape}"))
2629-
} else {
2630-
Ok(format!("{expr} SIMILAR TO {pattern}{escape}"))
2631-
}
2632-
}
2633-
Expr::Sort { .. } => {
2634-
internal_err!("Create physical name does not support sort expression")
2635-
}
2636-
Expr::Wildcard { qualifier, options } => match qualifier {
2637-
Some(qualifier) => Ok(format!("{}.*{}", qualifier, options)),
2638-
None => Ok(format!("*{}", options)),
2639-
},
2640-
Expr::Placeholder(_) => {
2641-
internal_err!("Create physical name does not support placeholder")
2642-
}
2643-
Expr::OuterReferenceColumn(_, _) => {
2644-
internal_err!("Create physical name does not support OuterReferenceColumn")
2645-
}
2389+
/// The name of the column (field) that this `Expr` will produce in the physical plan.
2390+
/// The difference from [Expr::schema_name] is that top-level columns are unqualified.
2391+
pub fn physical_name(expr: &Expr) -> Result<String> {
2392+
if let Expr::Column(col) = expr {
2393+
Ok(col.name.clone())
2394+
} else {
2395+
Ok(expr.schema_name().to_string())
26462396
}
26472397
}
26482398

@@ -2658,6 +2408,7 @@ mod test {
26582408
use std::any::Any;
26592409

26602410
#[test]
2411+
#[allow(deprecated)]
26612412
fn format_case_when() -> Result<()> {
26622413
let expr = case(col("a"))
26632414
.when(lit(1), lit(true))
@@ -2670,6 +2421,7 @@ mod test {
26702421
}
26712422

26722423
#[test]
2424+
#[allow(deprecated)]
26732425
fn format_cast() -> Result<()> {
26742426
let expr = Expr::Cast(Cast {
26752427
expr: Box::new(Expr::Literal(ScalarValue::Float32(Some(1.23)))),

datafusion/physical-expr-functions-aggregate/src/aggregate.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
use arrow::datatypes::{DataType, Field, Schema, SchemaRef};
1919
use datafusion_common::{internal_err, not_impl_err, Result};
20-
use datafusion_expr::expr::create_function_physical_name;
2120
use datafusion_expr::AggregateUDF;
2221
use datafusion_expr::ReversedUDAF;
2322
use datafusion_expr_common::accumulator::Accumulator;
@@ -110,8 +109,7 @@ impl AggregateExprBuilder {
110109

111110
let data_type = fun.return_type(&input_exprs_types)?;
112111
let name = match alias {
113-
// TODO: Ideally, we should build the name from physical expressions
114-
None => create_function_physical_name(fun.name(), is_distinct, &[], None)?,
112+
None => return internal_err!("alias should be provided"),
115113
Some(alias) => alias,
116114
};
117115

datafusion/physical-plan/src/aggregates/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,6 +2179,7 @@ mod tests {
21792179
.map(|order_by_expr| {
21802180
let ordering_req = order_by_expr.unwrap_or_default();
21812181
AggregateExprBuilder::new(array_agg_udaf(), vec![Arc::clone(col_a)])
2182+
.alias("a")
21822183
.order_by(ordering_req.to_vec())
21832184
.schema(Arc::clone(&test_schema))
21842185
.build()

0 commit comments

Comments
 (0)