This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new 3b028fe677 Improve formatting of datatypes (#20605)
3b028fe677 is described below
commit 3b028fe6774ba6391e0b12c7ca205fdbe53a6cae
Author: Emil Ernerfeldt <[email protected]>
AuthorDate: Wed Mar 4 11:35:22 2026 +0100
Improve formatting of datatypes (#20605)
## Which issue does this PR close?
- Part of https://github.com/apache/datafusion/issues/19004
## Rationale for this change
Error messages should be friendly, short, and readable.
## What changes are included in this PR?
* Implement proper `Display` for `dyn LogicalType`, `TypeSignature`,
`TypeSignatureClass`, and `Coercion` instead of falling back to `Debug`
* Switch error messages across the codebase from `{:?}` (`Debug`) to
`{}` (`Display`)
* Add `non-null` prefix for non-nullable fields in `NativeType`
`Display`, following Arrow's convention
The north star is to follow the convention set by arrow-rs
## Are these changes tested?
New snapshot tests have been introduced, and existing ones updated.
## Are there any user-facing changes?
Yes!
#### Before
> LogicalType(Native(List(LogicalField { name: "item", logical_type:
LogicalType(Native(Int32), Int32), nullable: true })), List(LogicalField
{ name: "item", logical_type: LogicalType(Native(Int32), Int32),
nullable: true }))
#### After
> List(Int32)
#### Before
```
No function matches the given name and argument types 'round(Utf8, Utf8)'.
Candidate functions:
round(Coercion(TypeSignatureClass::Native(LogicalType(Native(Float64),
Float64)),
implicit_coercion=ImplicitCoercion([Numeric], default_type=Float64)),
Coercion(TypeSignatureClass::Native(LogicalType(Native(Int64), Int64)),
implicit_coercion=ImplicitCoercion([Integer], default_type=Int64)))
Function 'abs' expects NativeType::Numeric but received NativeType::String
Failed to coerce arguments: coercion from Int32, Utf8 to the signature
Coercible([Coercion { desired_type: Native(LogicalType(Native(Float64),
Float64)), ... }]) failed
```
#### After
```
No function matches the given name and argument types 'round(Utf8, Utf8)'.
Candidate functions:
round(Float64, Int64)
Function 'abs' expects Numeric but received String
Failed to coerce arguments: coercion from Int32, Utf8 to the signature
Coercible(Float64, Int64) failed
```
---------
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Tim Saucer <[email protected]>
---
Cargo.lock | 1 +
datafusion/common/src/types/logical.rs | 120 ++++++++++++-
datafusion/common/src/types/native.rs | 120 ++++++++++++-
datafusion/expr-common/Cargo.toml | 3 +
datafusion/expr-common/src/signature.rs | 195 +++++++++++++++++++--
.../expr-common/src/type_coercion/aggregates.rs | 11 +-
datafusion/expr-common/src/type_coercion/binary.rs | 6 +-
datafusion/expr/src/expr_schema.rs | 2 +-
datafusion/expr/src/type_coercion/functions.rs | 18 +-
datafusion/expr/src/udf.rs | 2 +-
datafusion/expr/src/utils.rs | 100 +++++++++++
.../src/aggregate/groups_accumulator/nulls.rs | 2 +-
datafusion/optimizer/src/analyzer/type_coercion.rs | 2 +-
.../physical-plan/src/aggregates/topk/heap.rs | 4 +-
datafusion/physical-plan/src/unnest.rs | 4 +-
datafusion/sql/tests/sql_integration.rs | 43 ++---
datafusion/sqllogictest/test_files/array.slt | 2 +-
.../sqllogictest/test_files/arrow_typeof.slt | 2 +-
datafusion/sqllogictest/test_files/binary.slt | 2 +-
.../test_files/datetime/timestamps.slt | 6 +-
datafusion/sqllogictest/test_files/encoding.slt | 6 +-
datafusion/sqllogictest/test_files/expr.slt | 2 +-
datafusion/sqllogictest/test_files/functions.slt | 4 +-
datafusion/sqllogictest/test_files/math.slt | 6 +-
datafusion/sqllogictest/test_files/scalar.slt | 2 +-
.../test_files/spark/datetime/unix.slt | 8 +-
.../test_files/spark/string/base64.slt | 4 +-
datafusion/sqllogictest/test_files/window.slt | 4 +-
28 files changed, 578 insertions(+), 103 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 23670a7877..beb87f615c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2176,6 +2176,7 @@ dependencies = [
"arrow",
"datafusion-common",
"indexmap 2.13.0",
+ "insta",
"itertools 0.14.0",
"paste",
]
diff --git a/datafusion/common/src/types/logical.rs
b/datafusion/common/src/types/logical.rs
index 674b1a4120..0f886252d6 100644
--- a/datafusion/common/src/types/logical.rs
+++ b/datafusion/common/src/types/logical.rs
@@ -100,7 +100,10 @@ impl fmt::Debug for dyn LogicalType {
impl std::fmt::Display for dyn LogicalType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{self:?}")
+ match self.signature() {
+ TypeSignature::Native(_) => write!(f, "{}", self.native()),
+ TypeSignature::Extension { name, .. } => write!(f, "{name}"),
+ }
}
}
@@ -132,3 +135,118 @@ impl Hash for dyn LogicalType {
self.signature().hash(state);
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::types::{
+ LogicalField, LogicalFields, logical_boolean, logical_date,
logical_float32,
+ logical_float64, logical_int32, logical_int64, logical_null,
logical_string,
+ };
+ use arrow::datatypes::{DataType, Field, Fields};
+ use insta::assert_snapshot;
+
+ #[test]
+ fn test_logical_type_display_simple() {
+ assert_snapshot!(logical_null(), @"Null");
+ assert_snapshot!(logical_boolean(), @"Boolean");
+ assert_snapshot!(logical_int32(), @"Int32");
+ assert_snapshot!(logical_int64(), @"Int64");
+ assert_snapshot!(logical_float32(), @"Float32");
+ assert_snapshot!(logical_float64(), @"Float64");
+ assert_snapshot!(logical_string(), @"String");
+ assert_snapshot!(logical_date(), @"Date");
+ }
+
+ #[test]
+ fn test_logical_type_display_list() {
+ let list_type: Arc<dyn LogicalType> =
Arc::new(NativeType::List(Arc::new(
+ LogicalField::from(&Field::new("item", DataType::Int32, true)),
+ )));
+ assert_snapshot!(list_type, @"List(Int32)");
+ }
+
+ #[test]
+ fn test_logical_type_display_struct() {
+ let struct_type: Arc<dyn LogicalType> = Arc::new(NativeType::Struct(
+ LogicalFields::from(&Fields::from(vec![
+ Field::new("x", DataType::Float64, false),
+ Field::new("y", DataType::Float64, true),
+ ])),
+ ));
+ assert_snapshot!(struct_type, @r#"Struct("x": non-null Float64, "y":
Float64)"#);
+ }
+
+ #[test]
+ fn test_logical_type_display_fixed_size_list() {
+ let fsl_type: Arc<dyn LogicalType> =
Arc::new(NativeType::FixedSizeList(
+ Arc::new(LogicalField::from(&Field::new(
+ "item",
+ DataType::Float32,
+ false,
+ ))),
+ 3,
+ ));
+ assert_snapshot!(fsl_type, @"FixedSizeList(3 x non-null Float32)");
+ }
+
+ #[test]
+ fn test_logical_type_display_map() {
+ let map_type: Arc<dyn LogicalType> = Arc::new(NativeType::Map(Arc::new(
+ LogicalField::from(&Field::new("entries", DataType::Utf8, false)),
+ )));
+ assert_snapshot!(map_type, @"Map(non-null String)");
+ }
+
+ #[test]
+ fn test_logical_type_display_union() {
+ use arrow::datatypes::UnionFields;
+
+ let union_fields = UnionFields::try_new(
+ vec![0, 1],
+ vec![
+ Field::new("int_val", DataType::Int32, false),
+ Field::new("str_val", DataType::Utf8, true),
+ ],
+ )
+ .unwrap();
+ let union_type: Arc<dyn LogicalType> = Arc::new(NativeType::Union(
+ crate::types::LogicalUnionFields::from(&union_fields),
+ ));
+ assert_snapshot!(union_type, @r#"Union(0: ("int_val": non-null Int32),
1: ("str_val": String))"#);
+ }
+
+ #[test]
+ fn test_logical_type_display_nullable_vs_non_nullable() {
+ let nullable_list: Arc<dyn LogicalType> =
Arc::new(NativeType::List(Arc::new(
+ LogicalField::from(&Field::new("item", DataType::Int32, true)),
+ )));
+ let non_nullable_list: Arc<dyn LogicalType> =
+ Arc::new(NativeType::List(Arc::new(LogicalField::from(&Field::new(
+ "item",
+ DataType::Int32,
+ false,
+ )))));
+
+ assert_snapshot!(nullable_list, @"List(Int32)");
+ assert_snapshot!(non_nullable_list, @"List(non-null Int32)");
+ }
+
+ #[test]
+ fn test_logical_type_display_extension() {
+ struct JsonType;
+ impl LogicalType for JsonType {
+ fn native(&self) -> &NativeType {
+ &NativeType::String
+ }
+ fn signature(&self) -> TypeSignature<'_> {
+ TypeSignature::Extension {
+ name: "JSON",
+ parameters: &[],
+ }
+ }
+ }
+ let json: Arc<dyn LogicalType> = Arc::new(JsonType);
+ assert_snapshot!(json, @"JSON");
+ }
+}
diff --git a/datafusion/common/src/types/native.rs
b/datafusion/common/src/types/native.rs
index 65b6a5a15f..a4202db986 100644
--- a/datafusion/common/src/types/native.rs
+++ b/datafusion/common/src/types/native.rs
@@ -184,6 +184,16 @@ pub enum NativeType {
Map(LogicalFieldRef),
}
+/// Format a [`LogicalField`] for display, matching
[`arrow::datatypes::DataType`]'s
+/// Display convention of showing a `"non-null "` prefix for non-nullable
fields.
+fn format_logical_field(
+ f: &mut std::fmt::Formatter<'_>,
+ field: &LogicalField,
+) -> std::fmt::Result {
+ let non_null = if field.nullable { "" } else { "non-null " };
+ write!(f, "{:?}: {non_null}{}", field.name, field.logical_type)
+}
+
impl Display for NativeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Match the format used by arrow::datatypes::DataType's Display impl
@@ -210,9 +220,17 @@ impl Display for NativeType {
Self::Binary => write!(f, "Binary"),
Self::FixedSizeBinary(size) => write!(f,
"FixedSizeBinary({size})"),
Self::String => write!(f, "String"),
- Self::List(field) => write!(f, "List({})", field.logical_type),
+ Self::List(field) => {
+ let non_null = if field.nullable { "" } else { "non-null " };
+ write!(f, "List({non_null}{})", field.logical_type)
+ }
Self::FixedSizeList(field, size) => {
- write!(f, "FixedSizeList({size} x {})", field.logical_type)
+ let non_null = if field.nullable { "" } else { "non-null " };
+ write!(
+ f,
+ "FixedSizeList({size} x {non_null}{})",
+ field.logical_type
+ )
}
Self::Struct(fields) => {
write!(f, "Struct(")?;
@@ -220,7 +238,7 @@ impl Display for NativeType {
if i > 0 {
write!(f, ", ")?;
}
- write!(f, "{:?}: {}", field.name, field.logical_type)?;
+ format_logical_field(f, field)?;
}
write!(f, ")")
}
@@ -230,12 +248,17 @@ impl Display for NativeType {
if i > 0 {
write!(f, ", ")?;
}
- write!(f, "{type_id}: ({:?}: {})", field.name,
field.logical_type)?;
+ write!(f, "{type_id}: (")?;
+ format_logical_field(f, field)?;
+ write!(f, ")")?;
}
write!(f, ")")
}
Self::Decimal(precision, scale) => write!(f, "Decimal({precision},
{scale})"),
- Self::Map(field) => write!(f, "Map({})", field.logical_type),
+ Self::Map(field) => {
+ let non_null = if field.nullable { "" } else { "non-null " };
+ write!(f, "Map({non_null}{})", field.logical_type)
+ }
}
}
}
@@ -537,3 +560,90 @@ impl NativeType {
matches!(self, Self::Float16 | Self::Float32 | Self::Float64)
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::types::LogicalField;
+ use arrow::datatypes::Field;
+ use insta::assert_snapshot;
+
+ #[test]
+ fn test_native_type_display() {
+ assert_snapshot!(NativeType::Null, @"Null");
+ assert_snapshot!(NativeType::Boolean, @"Boolean");
+ assert_snapshot!(NativeType::Int8, @"Int8");
+ assert_snapshot!(NativeType::Int16, @"Int16");
+ assert_snapshot!(NativeType::Int32, @"Int32");
+ assert_snapshot!(NativeType::Int64, @"Int64");
+ assert_snapshot!(NativeType::UInt8, @"UInt8");
+ assert_snapshot!(NativeType::UInt16, @"UInt16");
+ assert_snapshot!(NativeType::UInt32, @"UInt32");
+ assert_snapshot!(NativeType::UInt64, @"UInt64");
+ assert_snapshot!(NativeType::Float16, @"Float16");
+ assert_snapshot!(NativeType::Float32, @"Float32");
+ assert_snapshot!(NativeType::Float64, @"Float64");
+ assert_snapshot!(NativeType::Date, @"Date");
+ assert_snapshot!(NativeType::Binary, @"Binary");
+ assert_snapshot!(NativeType::String, @"String");
+ assert_snapshot!(NativeType::FixedSizeBinary(16),
@"FixedSizeBinary(16)");
+ assert_snapshot!(NativeType::Decimal(10, 2), @"Decimal(10, 2)");
+ }
+
+ #[test]
+ fn test_native_type_display_timestamp() {
+ assert_snapshot!(
+ NativeType::Timestamp(TimeUnit::Second, None),
+ @"Timestamp(s)"
+ );
+ assert_snapshot!(
+ NativeType::Timestamp(TimeUnit::Millisecond, None),
+ @"Timestamp(ms)"
+ );
+ assert_snapshot!(
+ NativeType::Timestamp(TimeUnit::Nanosecond,
Some(Arc::from("UTC"))),
+ @r#"Timestamp(ns, "UTC")"#
+ );
+ }
+
+ #[test]
+ fn test_native_type_display_time_duration_interval() {
+ assert_snapshot!(NativeType::Time(TimeUnit::Microsecond), @"Time(µs)");
+ assert_snapshot!(NativeType::Duration(TimeUnit::Nanosecond),
@"Duration(ns)");
+ assert_snapshot!(NativeType::Interval(IntervalUnit::YearMonth),
@"Interval(YearMonth)");
+ assert_snapshot!(NativeType::Interval(IntervalUnit::MonthDayNano),
@"Interval(MonthDayNano)");
+ }
+
+ #[test]
+ fn test_native_type_display_nested() {
+ let list = NativeType::List(Arc::new(LogicalField::from(&Field::new(
+ "item",
+ DataType::Int32,
+ true,
+ ))));
+ assert_snapshot!(list, @"List(Int32)");
+
+ let fixed_list = NativeType::FixedSizeList(
+ Arc::new(LogicalField::from(&Field::new(
+ "item",
+ DataType::Float64,
+ false,
+ ))),
+ 3,
+ );
+ assert_snapshot!(fixed_list, @"FixedSizeList(3 x non-null Float64)");
+
+ let struct_type =
NativeType::Struct(LogicalFields::from(&Fields::from(vec![
+ Field::new("name", DataType::Utf8, false),
+ Field::new("age", DataType::Int32, true),
+ ])));
+ assert_snapshot!(struct_type, @r#"Struct("name": non-null String,
"age": Int32)"#);
+
+ let map = NativeType::Map(Arc::new(LogicalField::from(&Field::new(
+ "entries",
+ DataType::Utf8,
+ false,
+ ))));
+ assert_snapshot!(map, @"Map(non-null String)");
+ }
+}
diff --git a/datafusion/expr-common/Cargo.toml
b/datafusion/expr-common/Cargo.toml
index 5ee46b454e..d66d8ee858 100644
--- a/datafusion/expr-common/Cargo.toml
+++ b/datafusion/expr-common/Cargo.toml
@@ -46,3 +46,6 @@ datafusion-common = { workspace = true }
indexmap = { workspace = true }
itertools = { workspace = true }
paste = { workspace = true }
+
+[dev-dependencies]
+insta = { workspace = true }
diff --git a/datafusion/expr-common/src/signature.rs
b/datafusion/expr-common/src/signature.rs
index 857e9dc5d4..82759be9f7 100644
--- a/datafusion/expr-common/src/signature.rs
+++ b/datafusion/expr-common/src/signature.rs
@@ -322,6 +322,43 @@ impl TypeSignature {
}
}
+impl Display for TypeSignature {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ TypeSignature::Variadic(types) => {
+ write!(f, "Variadic({})", types.iter().join(", "))
+ }
+ TypeSignature::UserDefined => write!(f, "UserDefined"),
+ TypeSignature::VariadicAny => write!(f, "VariadicAny"),
+ TypeSignature::Uniform(count, types) => {
+ write!(f, "Uniform({count}, [{}])", types.iter().join(", "))
+ }
+ TypeSignature::Exact(types) => {
+ write!(f, "Exact({})", types.iter().join(", "))
+ }
+ TypeSignature::Coercible(coercions) => {
+ write!(f, "Coercible({})", coercions.iter().join(", "))
+ }
+ TypeSignature::Comparable(count) => write!(f,
"Comparable({count})"),
+ TypeSignature::Any(count) => write!(f, "Any({count})"),
+ TypeSignature::OneOf(sigs) => {
+ write!(f, "OneOf(")?;
+ for (i, sig) in sigs.iter().enumerate() {
+ if i > 0 {
+ write!(f, ", ")?;
+ }
+ write!(f, "{sig}")?;
+ }
+ write!(f, ")")
+ }
+ TypeSignature::ArraySignature(sig) => write!(f,
"ArraySignature({sig})"),
+ TypeSignature::Numeric(count) => write!(f, "Numeric({count})"),
+ TypeSignature::String(count) => write!(f, "String({count})"),
+ TypeSignature::Nullary => write!(f, "Nullary"),
+ }
+ }
+}
+
/// Represents the class of types that can be used in a function signature.
///
/// This is used to specify what types are valid for function arguments in a
more flexible way than
@@ -358,7 +395,19 @@ pub enum TypeSignatureClass {
impl Display for TypeSignatureClass {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "TypeSignatureClass::{self:?}")
+ match self {
+ Self::Any => write!(f, "Any"),
+ Self::Timestamp => write!(f, "Timestamp"),
+ Self::Time => write!(f, "Time"),
+ Self::Interval => write!(f, "Interval"),
+ Self::Duration => write!(f, "Duration"),
+ Self::Native(logical_type) => write!(f, "{logical_type}"),
+ Self::Integer => write!(f, "Integer"),
+ Self::Float => write!(f, "Float"),
+ Self::Decimal => write!(f, "Decimal"),
+ Self::Numeric => write!(f, "Numeric"),
+ Self::Binary => write!(f, "Binary"),
+ }
}
}
@@ -1062,12 +1111,7 @@ impl Coercion {
impl Display for Coercion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "Coercion({}", self.desired_type())?;
- if let Some(implicit_coercion) = self.implicit_coercion() {
- write!(f, ", implicit_coercion={implicit_coercion}",)
- } else {
- write!(f, ")")
- }
+ write!(f, "{}", self.desired_type())
}
}
@@ -1119,11 +1163,14 @@ pub struct ImplicitCoercion {
impl Display for ImplicitCoercion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(
- f,
- "ImplicitCoercion({:?}, default_type={:?})",
- self.allowed_source_types, self.default_casted_type
- )
+ write!(f, "ImplicitCoercion(")?;
+ for (i, source_type) in self.allowed_source_types.iter().enumerate() {
+ if i > 0 {
+ write!(f, ", ")?;
+ }
+ write!(f, "{source_type}")?;
+ }
+ write!(f, "; default={}", self.default_casted_type)
}
}
@@ -1438,7 +1485,9 @@ impl Signature {
#[cfg(test)]
mod tests {
- use datafusion_common::types::{logical_int32, logical_int64,
logical_string};
+ use datafusion_common::types::{
+ NativeType, logical_float64, logical_int32, logical_int64,
logical_string,
+ };
use super::*;
use crate::signature::{
@@ -2034,4 +2083,124 @@ mod tests {
let sig = TypeSignature::UserDefined;
assert_eq!(sig.arity(), Arity::Variable);
}
+
+ #[test]
+ fn test_type_signature_display() {
+ use insta::assert_snapshot;
+
+ assert_snapshot!(TypeSignature::Nullary, @"Nullary");
+ assert_snapshot!(TypeSignature::Any(2), @"Any(2)");
+ assert_snapshot!(TypeSignature::Numeric(3), @"Numeric(3)");
+ assert_snapshot!(TypeSignature::String(1), @"String(1)");
+ assert_snapshot!(TypeSignature::Comparable(2), @"Comparable(2)");
+ assert_snapshot!(TypeSignature::VariadicAny, @"VariadicAny");
+ assert_snapshot!(TypeSignature::UserDefined, @"UserDefined");
+
+ assert_snapshot!(
+ TypeSignature::Exact(vec![DataType::Int32, DataType::Utf8]),
+ @"Exact(Int32, Utf8)"
+ );
+ assert_snapshot!(
+ TypeSignature::Variadic(vec![DataType::Utf8, DataType::LargeUtf8]),
+ @"Variadic(Utf8, LargeUtf8)"
+ );
+ assert_snapshot!(
+ TypeSignature::Uniform(2, vec![DataType::Float32,
DataType::Float64]),
+ @"Uniform(2, [Float32, Float64])"
+ );
+
+ assert_snapshot!(
+ TypeSignature::Coercible(vec![
+
Coercion::new_exact(TypeSignatureClass::Native(logical_float64())),
+
Coercion::new_exact(TypeSignatureClass::Native(logical_int32())),
+ ]),
+ @"Coercible(Float64, Int32)"
+ );
+
+ assert_snapshot!(
+ TypeSignature::OneOf(vec![
+ TypeSignature::Nullary,
+ TypeSignature::VariadicAny,
+ ]),
+ @"OneOf(Nullary, VariadicAny)"
+ );
+ }
+
+ #[test]
+ fn test_type_signature_class_display() {
+ use insta::assert_snapshot;
+
+ assert_snapshot!(TypeSignatureClass::Any, @"Any");
+ assert_snapshot!(TypeSignatureClass::Numeric, @"Numeric");
+ assert_snapshot!(TypeSignatureClass::Integer, @"Integer");
+ assert_snapshot!(TypeSignatureClass::Float, @"Float");
+ assert_snapshot!(TypeSignatureClass::Decimal, @"Decimal");
+ assert_snapshot!(TypeSignatureClass::Timestamp, @"Timestamp");
+ assert_snapshot!(TypeSignatureClass::Time, @"Time");
+ assert_snapshot!(TypeSignatureClass::Interval, @"Interval");
+ assert_snapshot!(TypeSignatureClass::Duration, @"Duration");
+ assert_snapshot!(TypeSignatureClass::Binary, @"Binary");
+ assert_snapshot!(TypeSignatureClass::Native(logical_int32()),
@"Int32");
+ assert_snapshot!(TypeSignatureClass::Native(logical_string()),
@"String");
+ }
+
+ #[test]
+ fn test_coercion_display() {
+ use insta::assert_snapshot;
+
+ let exact_int =
Coercion::new_exact(TypeSignatureClass::Native(logical_int32()));
+ assert_snapshot!(exact_int, @"Int32");
+
+ let exact_numeric = Coercion::new_exact(TypeSignatureClass::Numeric);
+ assert_snapshot!(exact_numeric, @"Numeric");
+
+ let implicit = Coercion::new_implicit(
+ TypeSignatureClass::Native(logical_float64()),
+ vec![TypeSignatureClass::Numeric],
+ NativeType::Float64,
+ );
+ assert_snapshot!(implicit, @"Float64");
+
+ let implicit_with_multiple_sources = Coercion::new_implicit(
+ TypeSignatureClass::Native(logical_int64()),
+ vec![TypeSignatureClass::Integer, TypeSignatureClass::Numeric],
+ NativeType::Int64,
+ );
+ assert_snapshot!(implicit_with_multiple_sources, @"Int64");
+ }
+
+ #[test]
+ fn test_to_string_repr_coercible() {
+ use insta::assert_snapshot;
+
+ // Simulates a function like round(Float64, Int64) with coercion
+ let sig = TypeSignature::Coercible(vec![
+ Coercion::new_implicit(
+ TypeSignatureClass::Native(logical_float64()),
+ vec![TypeSignatureClass::Numeric],
+ NativeType::Float64,
+ ),
+ Coercion::new_implicit(
+ TypeSignatureClass::Native(logical_int64()),
+ vec![TypeSignatureClass::Integer],
+ NativeType::Int64,
+ ),
+ ]);
+ let repr = sig.to_string_repr();
+ assert_eq!(repr.len(), 1);
+ assert_snapshot!(repr[0], @"Float64, Int64");
+ }
+
+ #[test]
+ fn test_to_string_repr_coercible_exact() {
+ use insta::assert_snapshot;
+
+ let sig = TypeSignature::Coercible(vec![
+ Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
+ Coercion::new_exact(TypeSignatureClass::Native(logical_int64())),
+ ]);
+ let repr = sig.to_string_repr();
+ assert_eq!(repr.len(), 1);
+ assert_snapshot!(repr[0], @"String, Int64");
+ }
}
diff --git a/datafusion/expr-common/src/type_coercion/aggregates.rs
b/datafusion/expr-common/src/type_coercion/aggregates.rs
index ab4d086e4c..df86ff582d 100644
--- a/datafusion/expr-common/src/type_coercion/aggregates.rs
+++ b/datafusion/expr-common/src/type_coercion/aggregates.rs
@@ -61,8 +61,7 @@ pub fn check_arg_count(
TypeSignature::Uniform(agg_count, _) | TypeSignature::Any(agg_count)
=> {
if input_fields.len() != *agg_count {
return plan_err!(
- "The function {func_name} expects {:?} arguments, but {:?}
were provided",
- agg_count,
+ "The function {func_name} expects {agg_count} arguments,
but {} were provided",
input_fields.len()
);
}
@@ -70,7 +69,7 @@ pub fn check_arg_count(
TypeSignature::Exact(types) => {
if types.len() != input_fields.len() {
return plan_err!(
- "The function {func_name} expects {:?} arguments, but {:?}
were provided",
+ "The function {func_name} expects {} arguments, but {}
were provided",
types.len(),
input_fields.len()
);
@@ -82,7 +81,7 @@ pub fn check_arg_count(
.any(|v| check_arg_count(func_name, input_fields, v).is_ok());
if !ok {
return plan_err!(
- "The function {func_name} does not accept {:?} function
arguments.",
+ "The function {func_name} does not accept {} function
arguments.",
input_fields.len()
);
}
@@ -101,9 +100,7 @@ pub fn check_arg_count(
// Numeric and Coercible signature is validated in
`get_valid_types`
}
_ => {
- return internal_err!(
- "Aggregate functions do not support this {signature:?}"
- );
+ return internal_err!("Aggregate functions do not support this
{signature}");
}
}
Ok(())
diff --git a/datafusion/expr-common/src/type_coercion/binary.rs
b/datafusion/expr-common/src/type_coercion/binary.rs
index c6ac86cd39..dd3db8e40b 100644
--- a/datafusion/expr-common/src/type_coercion/binary.rs
+++ b/datafusion/expr-common/src/type_coercion/binary.rs
@@ -753,15 +753,15 @@ fn type_union_resolution_coercion(
/// Handle type union resolution including struct type and others.
pub fn try_type_union_resolution(data_types: &[DataType]) ->
Result<Vec<DataType>> {
- let err = match try_type_union_resolution_with_struct(data_types) {
+ let struct_err = match try_type_union_resolution_with_struct(data_types) {
Ok(struct_types) => return Ok(struct_types),
- Err(e) => Some(e),
+ Err(e) => e,
};
if let Some(new_type) = type_union_resolution(data_types) {
Ok(vec![new_type; data_types.len()])
} else {
- exec_err!("Fail to find the coerced type, errors: {:?}", err)
+ exec_err!("Fail to find the coerced type, errors: {struct_err}")
}
}
diff --git a/datafusion/expr/src/expr_schema.rs
b/datafusion/expr/src/expr_schema.rs
index f2ac777af3..4168310002 100644
--- a/datafusion/expr/src/expr_schema.rs
+++ b/datafusion/expr/src/expr_schema.rs
@@ -649,7 +649,7 @@ fn verify_function_arguments<F: UDFCoercionExt>(
.cloned()
.collect::<Vec<_>>();
plan_datafusion_err!(
- "{} {}",
+ "{}. {}",
match err {
DataFusionError::Plan(msg) => msg,
err => err.to_string(),
diff --git a/datafusion/expr/src/type_coercion/functions.rs
b/datafusion/expr/src/type_coercion/functions.rs
index fe259fb8c9..a79f2c6683 100644
--- a/datafusion/expr/src/type_coercion/functions.rs
+++ b/datafusion/expr/src/type_coercion/functions.rs
@@ -221,12 +221,12 @@ pub fn data_types(
} else if type_signature.used_to_support_zero_arguments() {
// Special error to help during upgrade:
https://github.com/apache/datafusion/issues/13763
return plan_err!(
- "function '{}' has signature {type_signature:?} which does not
support zero arguments. Use TypeSignature::Nullary for zero arguments",
+ "function '{}' has signature {type_signature} which does not
support zero arguments. Use TypeSignature::Nullary for zero arguments",
function_name.as_ref()
);
} else {
return plan_err!(
- "Function '{}' has signature {type_signature:?} which does not
support zero arguments",
+ "Function '{}' has signature {type_signature} which does not
support zero arguments",
function_name.as_ref()
);
}
@@ -302,7 +302,7 @@ fn try_coerce_types(
// none possible -> Error
plan_err!(
- "Failed to coerce arguments to satisfy a call to '{function_name}'
function: coercion from {} to the signature {type_signature:?} failed",
+ "Failed to coerce arguments to satisfy a call to '{function_name}'
function: coercion from {} to the signature {type_signature} failed",
current_types.iter().join(", ")
)
}
@@ -317,7 +317,7 @@ fn get_valid_types_with_udf<F: UDFCoercionExt>(
Ok(coerced_types) => vec![coerced_types],
Err(e) => {
return exec_err!(
- "Function '{}' user-defined coercion failed with {:?}",
+ "Function '{}' user-defined coercion failed with: {}",
func.name(),
e.strip_backtrace()
);
@@ -502,7 +502,7 @@ fn get_valid_types(
new_types.push(DataType::Utf8);
} else {
return plan_err!(
- "Function '{function_name}' expects NativeType::String
but NativeType::received NativeType::{logical_data_type}"
+ "Function '{function_name}' expects String but
received {logical_data_type}"
);
}
}
@@ -562,7 +562,7 @@ fn get_valid_types(
if !logical_data_type.is_numeric() {
return plan_err!(
- "Function '{function_name}' expects
NativeType::Numeric but received NativeType::{logical_data_type}"
+ "Function '{function_name}' expects Numeric but
received {logical_data_type}"
);
}
@@ -583,7 +583,7 @@ fn get_valid_types(
valid_type = DataType::Float64;
} else if !logical_data_type.is_numeric() {
return plan_err!(
- "Function '{function_name}' expects NativeType::Numeric
but received NativeType::{logical_data_type}"
+ "Function '{function_name}' expects Numeric but received
{logical_data_type}"
);
}
@@ -1056,7 +1056,7 @@ mod tests {
.unwrap_err();
assert_contains!(
got.to_string(),
- "Function 'test' expects NativeType::Numeric but received
NativeType::String"
+ "Function 'test' expects Numeric but received String"
);
// Fallbacks to float64 if the arg is of type null.
@@ -1076,7 +1076,7 @@ mod tests {
.unwrap_err();
assert_contains!(
got.to_string(),
- "Function 'test' expects NativeType::Numeric but received
NativeType::Timestamp(s)"
+ "Function 'test' expects Numeric but received Timestamp(s)"
);
Ok(())
diff --git a/datafusion/expr/src/udf.rs b/datafusion/expr/src/udf.rs
index 405fb25680..9705006e41 100644
--- a/datafusion/expr/src/udf.rs
+++ b/datafusion/expr/src/udf.rs
@@ -261,7 +261,7 @@ impl ScalarUDF {
let expected_type = return_field.data_type();
assert_or_internal_err!(
result_data_type == *expected_type,
- "Function '{}' returned value of type '{:?}' while the
following type was promised at planning time and expected: '{:?}'",
+ "Function '{}' returned value of type '{}' while the following
type was promised at planning time and expected: '{}'",
self.name(),
result_data_type,
expected_type
diff --git a/datafusion/expr/src/utils.rs b/datafusion/expr/src/utils.rs
index b19299981c..81a6fd393a 100644
--- a/datafusion/expr/src/utils.rs
+++ b/datafusion/expr/src/utils.rs
@@ -1784,4 +1784,104 @@ mod tests {
"Expected 'Any, Any' without parameter names, got: {error_msg}"
);
}
+
+ #[test]
+ fn test_signature_error_msg_exact() {
+ use insta::assert_snapshot;
+
+ let sig = Signature::one_of(
+ vec![
+ TypeSignature::Exact(vec![DataType::Float64, DataType::Int64]),
+ TypeSignature::Exact(vec![DataType::Float32, DataType::Int64]),
+ TypeSignature::Exact(vec![DataType::Float64]),
+ TypeSignature::Exact(vec![DataType::Float32]),
+ ],
+ Volatility::Immutable,
+ );
+ let msg = generate_signature_error_message(
+ "round",
+ &sig,
+ &[DataType::Float64, DataType::Float64],
+ );
+ assert_snapshot!(msg, @r"
+ No function matches the given name and argument types 'round(Float64,
Float64)'. You might need to add explicit type casts.
+ Candidate functions:
+ round(Float64, Int64)
+ round(Float32, Int64)
+ round(Float64)
+ round(Float32)
+ ");
+ }
+
+ #[test]
+ fn test_signature_error_msg_coercible() {
+ use datafusion_common::types::NativeType;
+ use datafusion_expr_common::signature::{Coercion, TypeSignatureClass};
+ use insta::assert_snapshot;
+
+ let sig = Signature::coercible(
+ vec![
+ Coercion::new_implicit(
+ TypeSignatureClass::Native(
+ datafusion_common::types::logical_float64(),
+ ),
+ vec![TypeSignatureClass::Numeric],
+ NativeType::Float64,
+ ),
+ Coercion::new_implicit(
+
TypeSignatureClass::Native(datafusion_common::types::logical_int64()),
+ vec![TypeSignatureClass::Integer],
+ NativeType::Int64,
+ ),
+ ],
+ Volatility::Immutable,
+ );
+ let msg = generate_signature_error_message(
+ "round",
+ &sig,
+ &[DataType::Utf8, DataType::Utf8],
+ );
+ assert_snapshot!(msg, @r"
+ No function matches the given name and argument types 'round(Utf8,
Utf8)'. You might need to add explicit type casts.
+ Candidate functions:
+ round(Float64, Int64)
+ ");
+ }
+
+ #[test]
+ fn test_signature_error_msg_with_names_coercible() {
+ use datafusion_common::types::NativeType;
+ use datafusion_expr_common::signature::{Coercion, TypeSignatureClass};
+ use insta::assert_snapshot;
+
+ let sig = Signature::coercible(
+ vec![
+ Coercion::new_exact(TypeSignatureClass::Native(
+ datafusion_common::types::logical_string(),
+ )),
+ Coercion::new_exact(TypeSignatureClass::Native(
+ datafusion_common::types::logical_int64(),
+ )),
+ Coercion::new_implicit(
+
TypeSignatureClass::Native(datafusion_common::types::logical_int64()),
+ vec![TypeSignatureClass::Integer],
+ NativeType::Int64,
+ ),
+ ],
+ Volatility::Immutable,
+ )
+ .with_parameter_names(vec![
+ "string".to_string(),
+ "start_pos".to_string(),
+ "length".to_string(),
+ ])
+ .expect("valid parameter names");
+
+ let msg = generate_signature_error_message("substr", &sig,
&[DataType::Int32]);
+ assert_snapshot!(msg, @r"
+ No function matches the given name and argument types 'substr(Int32)'.
You might need to add explicit type casts.
+ Candidate functions:
+ substr(string: String, start_pos: Int64, length: Int64)
+ ");
+ }
}
diff --git
a/datafusion/functions-aggregate-common/src/aggregate/groups_accumulator/nulls.rs
b/datafusion/functions-aggregate-common/src/aggregate/groups_accumulator/nulls.rs
index 435560721c..5b56b77e11 100644
---
a/datafusion/functions-aggregate-common/src/aggregate/groups_accumulator/nulls.rs
+++
b/datafusion/functions-aggregate-common/src/aggregate/groups_accumulator/nulls.rs
@@ -206,7 +206,7 @@ pub fn set_nulls_dyn(input: &dyn Array, nulls:
Option<NullBuffer>) -> Result<Arr
}
}
_ => {
- return not_impl_err!("Applying nulls {:?}", input.data_type());
+ return not_impl_err!("Applying nulls {}", input.data_type());
}
};
assert_eq!(input.len(), output.len());
diff --git a/datafusion/optimizer/src/analyzer/type_coercion.rs
b/datafusion/optimizer/src/analyzer/type_coercion.rs
index ed04aa4285..efc9984acb 100644
--- a/datafusion/optimizer/src/analyzer/type_coercion.rs
+++ b/datafusion/optimizer/src/analyzer/type_coercion.rs
@@ -849,7 +849,7 @@ fn coerce_scalar_range_aware(
// If type coercion fails, check if the largest type in family works:
if let Some(largest_type) = get_widest_type_in_family(target_type) {
coerce_scalar(largest_type, value).map_or_else(
- |_| exec_err!("Cannot cast {value:?} to {target_type}"),
+ |_| exec_err!("Cannot cast {value} to {target_type}"),
|_| ScalarValue::try_from(target_type),
)
} else {
diff --git a/datafusion/physical-plan/src/aggregates/topk/heap.rs
b/datafusion/physical-plan/src/aggregates/topk/heap.rs
index 9f0b697cca..889fe04bf8 100644
--- a/datafusion/physical-plan/src/aggregates/topk/heap.rs
+++ b/datafusion/physical-plan/src/aggregates/topk/heap.rs
@@ -216,7 +216,7 @@ fn extract_string_value<'a>(
DataType::Utf8 => batch.as_string::<i32>().value(idx),
DataType::LargeUtf8 => batch.as_string::<i64>().value(idx),
DataType::Utf8View => batch.as_string_view().value(idx),
- _ => unreachable!("Unsupported string type: {:?}", data_type),
+ _ => unreachable!("Unsupported string type: {data_type}"),
}
}
@@ -316,7 +316,7 @@ impl ArrowHeap for StringHeap {
DataType::Utf8 => build_string_array!(StringBuilder),
DataType::LargeUtf8 => build_string_array!(LargeStringBuilder),
DataType::Utf8View => build_string_array!(StringViewBuilder),
- _ => unreachable!("Unsupported string type: {:?}", self.data_type),
+ _ => unreachable!("Unsupported string type: {}", self.data_type),
};
(arr, map_idxs)
}
diff --git a/datafusion/physical-plan/src/unnest.rs
b/datafusion/physical-plan/src/unnest.rs
index 72faeb83c5..48de79b741 100644
--- a/datafusion/physical-plan/src/unnest.rs
+++ b/datafusion/physical-plan/src/unnest.rs
@@ -426,9 +426,7 @@ fn flatten_struct_cols(
Ok(struct_arr.columns().to_vec())
}
data_type => internal_err!(
- "expecting column {} from input plan to be a struct, got
{:?}",
- idx,
- data_type
+ "expecting column {idx} from input plan to be a struct,
got {data_type}"
),
},
None => Ok(vec![Arc::clone(column_data)]),
diff --git a/datafusion/sql/tests/sql_integration.rs
b/datafusion/sql/tests/sql_integration.rs
index 444bdae73a..9570336e99 100644
--- a/datafusion/sql/tests/sql_integration.rs
+++ b/datafusion/sql/tests/sql_integration.rs
@@ -4730,56 +4730,35 @@ fn test_custom_type_plan() -> Result<()> {
Ok(())
}
-fn error_message_test(sql: &str, err_msg_starts_with: &str) {
+fn error_message(sql: &str) -> String {
let err = logical_plan(sql).expect_err("query should have failed");
- assert!(
- err.strip_backtrace().starts_with(err_msg_starts_with),
- "Expected error to start with '{}', but got: '{}'",
- err_msg_starts_with,
- err.strip_backtrace(),
- );
+ err.strip_backtrace()
}
#[test]
fn test_error_message_invalid_scalar_function_signature() {
- error_message_test(
- "select sqrt()",
- "Error during planning: 'sqrt' does not support zero arguments",
- );
- error_message_test(
- "select sqrt(1, 2)",
- "Error during planning: Failed to coerce arguments",
+ assert!(
+ error_message("select sqrt()").starts_with(
+ r"Error during planning: 'sqrt' does not support zero arguments"
+ )
);
+ assert!(error_message("select sqrt(1, 2)").starts_with(r"Error during
planning: Failed to coerce arguments to satisfy a call to 'sqrt' function:
coercion from Int64, Int64 to the signature Exact(Int64) failed"));
}
#[test]
fn test_error_message_invalid_aggregate_function_signature() {
- error_message_test(
- "select sum()",
- "Error during planning: Execution error: Function 'sum' user-defined
coercion failed with \"Execution error: sum function requires 1 argument, got
0\"",
- );
- // We keep two different prefixes because they clarify each other.
- // It might be incorrect, and we should consider keeping only one.
- error_message_test(
- "select max(9, 3)",
- "Error during planning: Execution error: Function 'max' user-defined
coercion failed",
- );
+ assert!(error_message("select sum()").starts_with(r"Error during planning:
Execution error: Function 'sum' user-defined coercion failed with: Execution
error: sum function requires 1 argument, got 0"));
+ assert!(error_message("select max(9, 3)").starts_with(r"Error during
planning: Execution error: Function 'max' user-defined coercion failed with:
Execution error: min/max was called with 2 arguments. It requires only 1"));
}
#[test]
fn test_error_message_invalid_window_function_signature() {
- error_message_test(
- "select rank(1) over()",
- "Error during planning: The function 'rank' expected zero argument but
received 1",
- );
+ assert!(error_message("select rank(1) over()").starts_with(r"Error during
planning: The function 'rank' expected zero argument but received 1"));
}
#[test]
fn test_error_message_invalid_window_aggregate_function_signature() {
- error_message_test(
- "select sum() over()",
- "Error during planning: Execution error: Function 'sum' user-defined
coercion failed with \"Execution error: sum function requires 1 argument, got
0\"",
- );
+ assert!(error_message("select sum() over()").starts_with(r"Error during
planning: Execution error: Function 'sum' user-defined coercion failed with:
Execution error: sum function requires 1 argument, got 0"));
}
// Test issue: https://github.com/apache/datafusion/issues/14058
diff --git a/datafusion/sqllogictest/test_files/array.slt
b/datafusion/sqllogictest/test_files/array.slt
index 00d28d38d6..112351c5ef 100644
--- a/datafusion/sqllogictest/test_files/array.slt
+++ b/datafusion/sqllogictest/test_files/array.slt
@@ -3470,7 +3470,7 @@ select array_concat([NULL, NULL], [NULL, NULL]);
[NULL, NULL, NULL, NULL]
# array_concat error
-query error DataFusion error: Error during planning: Execution error: Function
'array_concat' user-defined coercion failed with "Error during planning:
array_concat does not support type Int64"
+query error DataFusion error: Error during planning: Execution error: Function
'array_concat' user-defined coercion failed with: Error during planning:
array_concat does not support type Int64
select array_concat(1, 2);
# array_concat scalar function #1
diff --git a/datafusion/sqllogictest/test_files/arrow_typeof.slt
b/datafusion/sqllogictest/test_files/arrow_typeof.slt
index 0c69e8591c..e00909ad5f 100644
--- a/datafusion/sqllogictest/test_files/arrow_typeof.slt
+++ b/datafusion/sqllogictest/test_files/arrow_typeof.slt
@@ -95,7 +95,7 @@ SELECT arrow_cast('1', 'Int16')
query error
SELECT arrow_cast('1')
-query error DataFusion error: Error during planning: Function 'arrow_cast'
requires TypeSignatureClass::Native\(LogicalType\(Native\(String\), String\)\),
but received Int64 \(DataType: Int64\)
+query error DataFusion error: Error during planning: Function 'arrow_cast'
requires String, but received Int64 \(DataType: Int64\)
SELECT arrow_cast('1', 43)
query error DataFusion error: Execution error: arrow_cast requires its second
argument to be a non\-empty constant string
diff --git a/datafusion/sqllogictest/test_files/binary.slt
b/datafusion/sqllogictest/test_files/binary.slt
index c4a21deeff..54ac51d9e7 100644
--- a/datafusion/sqllogictest/test_files/binary.slt
+++ b/datafusion/sqllogictest/test_files/binary.slt
@@ -313,7 +313,7 @@ Bar Bar Bar Bar
FooBar fooBar FooBar fooBar
# show helpful error msg when Binary type is used with string functions
-query error DataFusion error: Error during planning: Function 'split_part'
requires TypeSignatureClass::Native\(LogicalType\(Native\(String\), String\)\),
but received Binary \(DataType: Binary\)\.\n\nHint: Binary types are not
automatically coerced to String\. Use CAST\(column AS VARCHAR\) to convert
Binary data to String\.
+query error DataFusion error: Error during planning: Function 'split_part'
requires String, but received Binary \(DataType: Binary\)\.\n\nHint: Binary
types are not automatically coerced to String\. Use CAST\(column AS VARCHAR\)
to convert Binary data to String\.
SELECT split_part(binary, '~', 2) FROM t WHERE binary IS NOT NULL LIMIT 1;
# ensure the suggested CAST workaround works
diff --git a/datafusion/sqllogictest/test_files/datetime/timestamps.slt
b/datafusion/sqllogictest/test_files/datetime/timestamps.slt
index 9526ccebfd..78889230fd 100644
--- a/datafusion/sqllogictest/test_files/datetime/timestamps.slt
+++ b/datafusion/sqllogictest/test_files/datetime/timestamps.slt
@@ -3076,7 +3076,7 @@ NULL
query error DataFusion error: Error during planning: Function 'make_date'
expects 3 arguments but received 1
select make_date(1);
-query error DataFusion error: Error during planning: Function 'make_date'
requires TypeSignatureClass::Native\(LogicalType\(Native\(Int32\), Int32\)\),
but received Interval\(MonthDayNano\) \(DataType: Interval\(MonthDayNano\)\)
+query error DataFusion error: Error during planning: Function 'make_date'
requires Int32, but received Interval\(MonthDayNano\) \(DataType:
Interval\(MonthDayNano\)\).
select make_date(interval '1 day', '2001-05-21'::timestamp,
'2001-05-21'::timestamp);
##########
@@ -3349,7 +3349,7 @@ select make_time(22, '', 27);
query error Cannot cast string '' to value of Int32 type
select make_time(22, 1, '');
-query error DataFusion error: Error during planning: Function 'make_time'
requires TypeSignatureClass::Native\(LogicalType\(Native\(Int32\), Int32\)\),
but received Float64 \(DataType: Float64\)
+query error DataFusion error: Error during planning: Function 'make_time'
requires Int32, but received Float64 \(DataType: Float64\)
select make_time(arrow_cast(22, 'Float64'), 1, '');
##########
@@ -3964,7 +3964,7 @@ statement error
select to_local_time('2024-04-01T00:00:20Z'::timestamp, 'some string');
# invalid argument data type
-statement error DataFusion error: Error during planning: Function
'to_local_time' requires TypeSignatureClass::Timestamp, but received String
\(DataType: Utf8\)
+statement error DataFusion error: Error during planning: Function
'to_local_time' requires Timestamp, but received String \(DataType: Utf8\)
select to_local_time('2024-04-01T00:00:20Z');
# invalid timezone
diff --git a/datafusion/sqllogictest/test_files/encoding.slt
b/datafusion/sqllogictest/test_files/encoding.slt
index b04d506182..c68d59819e 100644
--- a/datafusion/sqllogictest/test_files/encoding.slt
+++ b/datafusion/sqllogictest/test_files/encoding.slt
@@ -75,10 +75,10 @@ CREATE TABLE test(
;
# errors
-query error DataFusion error: Error during planning: Function 'encode'
requires TypeSignatureClass::Binary, but received Int64 \(DataType: Int64\)
+query error DataFusion error: Error during planning: Function 'encode'
requires Binary, but received Int64 \(DataType: Int64\)
select encode(12, 'hex');
-query error DataFusion error: Error during planning: Function 'decode'
requires TypeSignatureClass::Binary, but received Int64 \(DataType: Int64\)
+query error DataFusion error: Error during planning: Function 'decode'
requires Binary, but received Int64 \(DataType: Int64\)
select decode(12, 'hex');
query error DataFusion error: Error during planning: There is no built\-in
encoding named 'non_encoding', currently supported encodings are: base64,
base64pad, hex
@@ -93,7 +93,7 @@ select decode('', null) from test;
query error DataFusion error: This feature is not implemented: Encoding must
be a scalar; array specified encoding is not yet supported
select decode('', hex_field) from test;
-query error DataFusion error: Error during planning: Function 'to_hex'
requires TypeSignatureClass::Integer, but received String \(DataType: Utf8View\)
+query error DataFusion error: Error during planning: Function 'to_hex'
requires Integer, but received String \(DataType: Utf8View\)
select to_hex(hex_field) from test;
query error DataFusion error: Execution error: Failed to decode value using
base64
diff --git a/datafusion/sqllogictest/test_files/expr.slt
b/datafusion/sqllogictest/test_files/expr.slt
index 6d19d1436e..a6341bc686 100644
--- a/datafusion/sqllogictest/test_files/expr.slt
+++ b/datafusion/sqllogictest/test_files/expr.slt
@@ -618,7 +618,7 @@ select repeat('-1.2', arrow_cast(3, 'Int32'));
----
-1.2-1.2-1.2
-query error DataFusion error: Error during planning: Function 'repeat'
requires TypeSignatureClass::Native\(LogicalType\(Native\(Int64\), Int64\)\),
but received Float64 \(DataType: Float64\)
+query error DataFusion error: Error during planning: Function 'repeat'
requires Int64, but received Float64 \(DataType: Float64\)
select repeat('-1.2', 3.2);
query T
diff --git a/datafusion/sqllogictest/test_files/functions.slt
b/datafusion/sqllogictest/test_files/functions.slt
index 5a43d18e23..fa852e98ac 100644
--- a/datafusion/sqllogictest/test_files/functions.slt
+++ b/datafusion/sqllogictest/test_files/functions.slt
@@ -887,7 +887,7 @@ SELECT greatest(-1, 1, 2.3, 123456789, 3 + 5, -(-4),
abs(-9.0))
123456789
-query error Function 'greatest' user-defined coercion failed with "Error
during planning: greatest was called without any arguments. It requires at
least 1."
+query error Function 'greatest' user-defined coercion failed with: Error
during planning: greatest was called without any arguments. It requires at
least 1.
SELECT greatest()
query I
@@ -1085,7 +1085,7 @@ SELECT least(-1, 1, 2.3, 123456789, 3 + 5, -(-4),
abs(-9.0))
-1
-query error Function 'least' user-defined coercion failed with "Error during
planning: least was called without any arguments. It requires at least 1."
+query error Function 'least' user-defined coercion failed with: Error during
planning: least was called without any arguments. It requires at least 1.
SELECT least()
query I
diff --git a/datafusion/sqllogictest/test_files/math.slt
b/datafusion/sqllogictest/test_files/math.slt
index 2227466fdf..d571fcd947 100644
--- a/datafusion/sqllogictest/test_files/math.slt
+++ b/datafusion/sqllogictest/test_files/math.slt
@@ -158,15 +158,15 @@ statement error
SELECT abs(1, 2);
# abs: unsupported argument type
-query error DataFusion error: Error during planning: Function 'abs' expects
NativeType::Numeric but received NativeType::String
+query error DataFusion error: Error during planning: Function 'abs' expects
Numeric but received String
SELECT abs('foo');
# abs: numeric string
# TODO: In Postgres, '-1.2' is unknown type and interpreted to float8 so they
don't fail on this query
-query error DataFusion error: Error during planning: Function 'abs' expects
NativeType::Numeric but received NativeType::String
+query error DataFusion error: Error during planning: Function 'abs' expects
Numeric but received String
select abs('-1.2');
-query error DataFusion error: Error during planning: Function 'abs' expects
NativeType::Numeric but received NativeType::String
+query error DataFusion error: Error during planning: Function 'abs' expects
Numeric but received String
select abs(arrow_cast('-1.2', 'Utf8'));
statement ok
diff --git a/datafusion/sqllogictest/test_files/scalar.slt
b/datafusion/sqllogictest/test_files/scalar.slt
index 681540a29d..e91ec1cb84 100644
--- a/datafusion/sqllogictest/test_files/scalar.slt
+++ b/datafusion/sqllogictest/test_files/scalar.slt
@@ -2137,7 +2137,7 @@ select position('' in '')
----
1
-query error DataFusion error: Error during planning: Function 'strpos'
requires TypeSignatureClass::Native\(LogicalType\(Native\(String\), String\)\),
but received Int64 \(DataType: Int64\)
+query error DataFusion error: Error during planning: Function 'strpos'
requires String, but received Int64 \(DataType: Int64\).
select position(1 in 1)
query I
diff --git a/datafusion/sqllogictest/test_files/spark/datetime/unix.slt
b/datafusion/sqllogictest/test_files/spark/datetime/unix.slt
index d7441f487d..9dd39acd7f 100644
--- a/datafusion/sqllogictest/test_files/spark/datetime/unix.slt
+++ b/datafusion/sqllogictest/test_files/spark/datetime/unix.slt
@@ -38,7 +38,7 @@ SELECT unix_date(NULL::date);
----
NULL
-query error Function 'unix_date' requires
TypeSignatureClass::Native\(LogicalType\(Native\(Date\), Date\)\), but received
String \(DataType: Utf8View\)
+query error Function 'unix_date' requires Date, but received String
\(DataType: Utf8View\)
SELECT unix_date('1970-01-02'::string);
# Unix Micro Tests
@@ -68,7 +68,7 @@ SELECT unix_micros(NULL::timestamp);
----
NULL
-query error Function 'unix_micros' requires TypeSignatureClass::Timestamp, but
received String \(DataType: Utf8View\)
+query error Function 'unix_micros' requires Timestamp, but received String
\(DataType: Utf8View\)
SELECT unix_micros('1970-01-01 00:00:01Z'::string);
@@ -99,7 +99,7 @@ SELECT unix_millis(NULL::timestamp);
----
NULL
-query error Function 'unix_millis' requires TypeSignatureClass::Timestamp, but
received String \(DataType: Utf8View\)
+query error Function 'unix_millis' requires Timestamp, but received String
\(DataType: Utf8View\)
SELECT unix_millis('1970-01-01 00:00:01Z'::string);
@@ -130,5 +130,5 @@ SELECT unix_seconds(NULL::timestamp);
----
NULL
-query error Function 'unix_seconds' requires TypeSignatureClass::Timestamp,
but received String \(DataType: Utf8View\)
+query error Function 'unix_seconds' requires Timestamp, but received String
\(DataType: Utf8View\)
SELECT unix_seconds('1970-01-01 00:00:01Z'::string);
diff --git a/datafusion/sqllogictest/test_files/spark/string/base64.slt
b/datafusion/sqllogictest/test_files/spark/string/base64.slt
index 03b488de0e..dbd266f65a 100644
--- a/datafusion/sqllogictest/test_files/spark/string/base64.slt
+++ b/datafusion/sqllogictest/test_files/spark/string/base64.slt
@@ -58,7 +58,7 @@ U3BhcmsgU1E=
U3BhcmsgUw==
NULL
-query error Function 'base64' requires TypeSignatureClass::Binary, but
received Int32 \(DataType: Int32\)
+query error Error during planning: Function 'base64' requires Binary, but
received Int32 \(DataType: Int32\)
SELECT base64(12::integer);
@@ -111,5 +111,5 @@ SELECT unbase64('123'::string);
query error Failed to decode value using base64
SELECT unbase64('123'::bytea);
-query error Function 'unbase64' requires TypeSignatureClass::Binary, but
received Int32 \(DataType: Int32\)
+query error Error during planning: Function 'unbase64' requires Binary, but
received Int32 \(DataType: Int32\)
SELECT unbase64(12::integer);
diff --git a/datafusion/sqllogictest/test_files/window.slt
b/datafusion/sqllogictest/test_files/window.slt
index c3e6f39adb..62296c5d87 100644
--- a/datafusion/sqllogictest/test_files/window.slt
+++ b/datafusion/sqllogictest/test_files/window.slt
@@ -2580,7 +2580,7 @@ statement ok
set datafusion.optimizer.skip_failed_rules = true
# Error is returned from the physical plan.
-query error Cannot cast Utf8\("1 DAY"\) to Int8
+query error Cannot cast 1 DAY to Int8
SELECT
COUNT(c1) OVER (ORDER BY c2 RANGE BETWEEN '1 DAY' PRECEDING AND '2 DAY'
FOLLOWING)
FROM aggregate_test_100;
@@ -2589,7 +2589,7 @@ statement ok
set datafusion.optimizer.skip_failed_rules = false
# Error is returned from the logical plan.
-query error Cannot cast Utf8\("1 DAY"\) to Int8
+query error Cannot cast 1 DAY to Int8
SELECT
COUNT(c1) OVER (ORDER BY c2 RANGE BETWEEN '1 DAY' PRECEDING AND '2 DAY'
FOLLOWING)
FROM aggregate_test_100;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]