Skip to content

Commit

Permalink
Add a hint about normalization in error message (apache#14089)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Zhukov committed Jan 13, 2025
1 parent 17446ad commit efecf0d
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 39 deletions.
5 changes: 4 additions & 1 deletion datafusion/common/src/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,10 @@ mod tests {
&[],
)
.expect_err("should've failed to find field");
let expected = r#"Schema error: No field named z. Valid fields are t1.a, t1.b, t2.c, t2.d, t3.a, t3.b, t3.c, t3.d, t3.e."#;
let expected = "Schema error: No field named z. \
You can use double quotes to refer to the \"z\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option. \
Valid fields are t1.a, t1.b, t2.c, t2.d, t3.a, t3.b, t3.c, t3.d, t3.e.";
assert_eq!(err.strip_backtrace(), expected);

// ambiguous column reference
Expand Down
28 changes: 18 additions & 10 deletions datafusion/common/src/dfschema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1068,10 +1068,11 @@ mod tests {
let schema = DFSchema::try_from_qualified_schema("t1", &test_schema_1())?;
// lookup with unqualified name "t1.c0"
let err = schema.index_of_column(&col).unwrap_err();
assert_eq!(
err.strip_backtrace(),
"Schema error: No field named \"t1.c0\". Valid fields are t1.c0, t1.c1."
);
let expected = "Schema error: No field named \"t1.c0\". \
You can use double quotes to refer to the \"\"t1.c0\"\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option. \
Valid fields are t1.c0, t1.c1.";
assert_eq!(err.strip_backtrace(), expected);
Ok(())
}

Expand All @@ -1088,10 +1089,11 @@ mod tests {

// lookup with unqualified name "t1.c0"
let err = schema.index_of_column(&col).unwrap_err();
assert_eq!(
err.strip_backtrace(),
"Schema error: No field named \"t1.c0\". Valid fields are t1.\"CapitalColumn\", t1.\"field.with.period\"."
);
let expected = "Schema error: No field named \"t1.c0\". \
You can use double quotes to refer to the \"\"t1.c0\"\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option. \
Valid fields are t1.\"CapitalColumn\", t1.\"field.with.period\".";
assert_eq!(err.strip_backtrace(), expected);
Ok(())
}

Expand Down Expand Up @@ -1261,12 +1263,18 @@ mod tests {

let col = Column::from_qualified_name("t1.c0");
let err = schema.index_of_column(&col).unwrap_err();
assert_eq!(err.strip_backtrace(), "Schema error: No field named t1.c0.");
let expected = "Schema error: No field named t1.c0. \
You can use double quotes to refer to the \"t1.c0\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option.";
assert_eq!(err.strip_backtrace(), expected);

// the same check without qualifier
let col = Column::from_name("c0");
let err = schema.index_of_column(&col).err().unwrap();
assert_eq!(err.strip_backtrace(), "Schema error: No field named c0.");
let expected = "Schema error: No field named c0. \
You can use double quotes to refer to the \"c0\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option.";
assert_eq!(err.strip_backtrace(), expected);
}

#[test]
Expand Down
6 changes: 6 additions & 0 deletions datafusion/common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ impl Display for SchemaError {
valid_fields,
} => {
write!(f, "No field named {}", field.quoted_flat_name())?;
write!(
f,
". You can use double quotes to refer to the \"{}\" column",
field.quoted_flat_name()
)?;
write!(f, " or set the datafusion.sql_parser.enable_ident_normalization configuration option")?;
if !valid_fields.is_empty() {
write!(
f,
Expand Down
2 changes: 2 additions & 0 deletions datafusion/core/src/dataframe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2760,6 +2760,8 @@ mod tests {
// but since they are different expressions, it should fail.
.expect_err("Expected error");
let expected = "Schema error: No field named aggregate_test_100.c2. \
You can use double quotes to refer to the \"aggregate_test_100.c2\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option. \
Valid fields are \"aggregate_test_100.c2 + aggregate_test_100.c3\".";
assert_eq!(df.strip_backtrace(), expected);

Expand Down
9 changes: 5 additions & 4 deletions datafusion/expr/src/expr_rewriter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,10 +462,11 @@ mod test {
normalize_col_with_schemas_and_ambiguity_check(expr, &[&schemas], &[])
.unwrap_err()
.strip_backtrace();
assert_eq!(
error,
r#"Schema error: No field named b. Valid fields are "tableA".a."#
);
let expected = "Schema error: No field named b. \
You can use double quotes to refer to the \"b\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option. \
Valid fields are \"tableA\".a.";
assert_eq!(error, expected);
}

#[test]
Expand Down
37 changes: 22 additions & 15 deletions datafusion/sql/tests/sql_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,10 @@ Dml: op=[Insert Into] table=[test_decimal]
)]
#[case::non_existing_column(
"INSERT INTO test_decimal (nonexistent, price) VALUES (1, 2), (4, 5)",
"Schema error: No field named nonexistent. Valid fields are id, price."
"Schema error: No field named nonexistent. \
You can use double quotes to refer to the \"nonexistent\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option. \
Valid fields are id, price."
)]
#[case::target_column_count_mismatch(
"INSERT INTO person (id, first_name, last_name) VALUES ($1, $2)",
Expand Down Expand Up @@ -1358,9 +1361,13 @@ fn select_simple_aggregate_with_groupby_column_unselected() {
fn select_simple_aggregate_with_groupby_and_column_in_group_by_does_not_exist() {
let sql = "SELECT sum(age) FROM person GROUP BY doesnotexist";
let err = logical_plan(sql).expect_err("query should have failed");
assert_eq!("Schema error: No field named doesnotexist. Valid fields are \"sum(person.age)\", \
let expected = "Schema error: No field named doesnotexist. \
You can use double quotes to refer to the \"doesnotexist\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option. \
Valid fields are \"sum(person.age)\", \
person.id, person.first_name, person.last_name, person.age, person.state, \
person.salary, person.birth_date, person.\"😀\".", err.strip_backtrace());
person.salary, person.birth_date, person.\"😀\".";
assert_eq!(err.strip_backtrace(), expected);
}

#[test]
Expand Down Expand Up @@ -3636,10 +3643,10 @@ fn test_prepare_statement_to_plan_panic_prepare_wrong_syntax() {
#[test]
fn test_prepare_statement_to_plan_panic_no_relation_and_constant_param() {
let sql = "PREPARE my_plan(INT) AS SELECT id + $1";
assert_eq!(
logical_plan(sql).unwrap_err().strip_backtrace(),
"Schema error: No field named id."
)
let expected = "Schema error: No field named id. \
You can use double quotes to refer to the \"id\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option.";
assert_eq!(logical_plan(sql).unwrap_err().strip_backtrace(), expected);
}

#[test]
Expand Down Expand Up @@ -4334,18 +4341,18 @@ fn test_multi_grouping_sets() {
fn test_field_not_found_window_function() {
let order_by_sql = "SELECT count() OVER (order by a);";
let order_by_err = logical_plan(order_by_sql).expect_err("query should have failed");
assert_eq!(
"Schema error: No field named a.",
order_by_err.strip_backtrace()
);
let expected = "Schema error: No field named a. \
You can use double quotes to refer to the \"a\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option.";
assert_eq!(order_by_err.strip_backtrace(), expected);

let partition_by_sql = "SELECT count() OVER (PARTITION BY a);";
let partition_by_err =
logical_plan(partition_by_sql).expect_err("query should have failed");
assert_eq!(
"Schema error: No field named a.",
partition_by_err.strip_backtrace()
);
let expected = "Schema error: No field named a. \
You can use double quotes to refer to the \"a\" column \
or set the datafusion.sql_parser.enable_ident_normalization configuration option.";
assert_eq!(partition_by_err.strip_backtrace(), expected);

let qualified_sql =
"SELECT order_id, MAX(qty) OVER (PARTITION BY orders.order_id) from orders";
Expand Down
8 changes: 4 additions & 4 deletions datafusion/sqllogictest/test_files/identifiers.slt
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@ drop table case_insensitive_test
statement ok
CREATE TABLE test("Column1" string) AS VALUES ('content1');

statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
statement error DataFusion error: Schema error: No field named column1. You can use double quotes to refer to the "column1" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are test\."Column1"\.
SELECT COLumn1 from test

statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
statement error DataFusion error: Schema error: No field named column1. You can use double quotes to refer to the "column1" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are test\."Column1"\.
SELECT Column1 from test

statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
statement error DataFusion error: Schema error: No field named column1. You can use double quotes to refer to the "column1" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are test\."Column1"\.
SELECT column1 from test

statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
statement error DataFusion error: Schema error: No field named column1. You can use double quotes to refer to the "column1" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are test\."Column1"\.
SELECT "column1" from test

statement ok
Expand Down
2 changes: 1 addition & 1 deletion datafusion/sqllogictest/test_files/join.slt
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ statement ok
set datafusion.execution.batch_size = 4096;

# left semi with wrong where clause
query error DataFusion error: Schema error: No field named t2\.t2_id\. Valid fields are t1\.t1_id, t1\.t1_name, t1\.t1_int\.
query error DataFusion error: Schema error: No field named t2\.t2_id\. You can use double quotes to refer to the "t2.t2_id" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are t1\.t1_id, t1\.t1_name, t1\.t1_int\.
SELECT t1.t1_id, t1.t1_name, t1.t1_int
FROM t1
LEFT SEMI JOIN t2 ON t1.t1_id = t2.t2_id
Expand Down
2 changes: 1 addition & 1 deletion datafusion/sqllogictest/test_files/references.slt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ CREATE TABLE test("f.c1" TEXT, "test.c2" INT, "...." INT) AS VALUES
('foobar', 2, 20),
('foobaz', 3, 30);

query error DataFusion error: Schema error: No field named f1\.c1\. Valid fields are test\."f\.c1", test\."test\.c2", test\."\.\.\.\."\.
query error DataFusion error: Schema error: No field named f1\.c1\. You can use double quotes to refer to the "f1.c1" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are test\."f\.c1", test\."test\.c2", test\."\.\.\.\."\.
SELECT f1.c1 FROM test;

query T
Expand Down
6 changes: 3 additions & 3 deletions datafusion/sqllogictest/test_files/select.slt
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ SELECT * FROM empty_table
statement ok
CREATE TABLE case_sensitive_table("INT32" int) AS VALUES (1), (2), (3), (4), (5);

statement error DataFusion error: Schema error: No field named int32. Valid fields are case_sensitive_table."INT32".
statement error DataFusion error: Schema error: No field named int32. You can use double quotes to refer to the "int32" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are case_sensitive_table."INT32".
select "int32" from case_sensitive_table

query I
Expand Down Expand Up @@ -1799,7 +1799,7 @@ select a + b from (select 1 as a, 2 as b, 1 as "a + b");
3

# Can't reference an output column by expression over projection.
query error DataFusion error: Schema error: No field named a\. Valid fields are "a \+ Int64\(1\)"\.
query error DataFusion error: Schema error: No field named a. You can use double quotes to refer to the "a" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are "a \+ Int64\(1\)"\.
select a + 1 from (select a+1 from (select 1 as a));

query I
Expand Down Expand Up @@ -1834,5 +1834,5 @@ statement ok
DROP TABLE test;

# Can't reference an unqualified column by a qualified name
query error DataFusion error: Schema error: No field named t1\.v1\. Valid fields are "t1\.v1"\.
query error DataFusion error: Schema error: No field named t1\.v1\. You can use double quotes to refer to the "t1.v1" column or set the datafusion.sql_parser.enable_ident_normalization configuration option. Valid fields are "t1\.v1"\.
SELECT t1.v1 FROM (SELECT 1 AS "t1.v1");

0 comments on commit efecf0d

Please sign in to comment.