Skip to content

Commit 0a2f09f

Browse files
cj-zhukovSergey Zhukov
andauthored
Add a hint about normalization in error message (#14089) (#14113)
* Add a hint about normalization in error message (#14089) * normalization suggestion is only shown when a column name matches schema --------- Co-authored-by: Sergey Zhukov <szhukov@aligntech.com>
1 parent 53dab46 commit 0a2f09f

File tree

7 files changed

+48
-36
lines changed

7 files changed

+48
-36
lines changed

datafusion/common/src/column.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,8 @@ mod tests {
368368
&[],
369369
)
370370
.expect_err("should've failed to find field");
371-
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."#;
371+
let expected = "Schema error: No field named z. \
372+
Valid fields are t1.a, t1.b, t2.c, t2.d, t3.a, t3.b, t3.c, t3.d, t3.e.";
372373
assert_eq!(err.strip_backtrace(), expected);
373374

374375
// ambiguous column reference

datafusion/common/src/dfschema.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,10 +1068,12 @@ mod tests {
10681068
let schema = DFSchema::try_from_qualified_schema("t1", &test_schema_1())?;
10691069
// lookup with unqualified name "t1.c0"
10701070
let err = schema.index_of_column(&col).unwrap_err();
1071-
assert_eq!(
1072-
err.strip_backtrace(),
1073-
"Schema error: No field named \"t1.c0\". Valid fields are t1.c0, t1.c1."
1074-
);
1071+
let expected = "Schema error: No field named \"t1.c0\". \
1072+
Column names are case sensitive. \
1073+
You can use double quotes to refer to the \"\"t1.c0\"\" column \
1074+
or set the datafusion.sql_parser.enable_ident_normalization configuration. \
1075+
Valid fields are t1.c0, t1.c1.";
1076+
assert_eq!(err.strip_backtrace(), expected);
10751077
Ok(())
10761078
}
10771079

@@ -1088,10 +1090,9 @@ mod tests {
10881090

10891091
// lookup with unqualified name "t1.c0"
10901092
let err = schema.index_of_column(&col).unwrap_err();
1091-
assert_eq!(
1092-
err.strip_backtrace(),
1093-
"Schema error: No field named \"t1.c0\". Valid fields are t1.\"CapitalColumn\", t1.\"field.with.period\"."
1094-
);
1093+
let expected = "Schema error: No field named \"t1.c0\". \
1094+
Valid fields are t1.\"CapitalColumn\", t1.\"field.with.period\".";
1095+
assert_eq!(err.strip_backtrace(), expected);
10951096
Ok(())
10961097
}
10971098

@@ -1261,12 +1262,14 @@ mod tests {
12611262

12621263
let col = Column::from_qualified_name("t1.c0");
12631264
let err = schema.index_of_column(&col).unwrap_err();
1264-
assert_eq!(err.strip_backtrace(), "Schema error: No field named t1.c0.");
1265+
let expected = "Schema error: No field named t1.c0.";
1266+
assert_eq!(err.strip_backtrace(), expected);
12651267

12661268
// the same check without qualifier
12671269
let col = Column::from_name("c0");
12681270
let err = schema.index_of_column(&col).err().unwrap();
1269-
assert_eq!(err.strip_backtrace(), "Schema error: No field named c0.");
1271+
let expected = "Schema error: No field named c0.";
1272+
assert_eq!(err.strip_backtrace(), expected);
12701273
}
12711274

12721275
#[test]

datafusion/common/src/error.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,18 @@ impl Display for SchemaError {
167167
valid_fields,
168168
} => {
169169
write!(f, "No field named {}", field.quoted_flat_name())?;
170+
let lower_valid_fields = valid_fields
171+
.iter()
172+
.map(|column| column.flat_name().to_lowercase())
173+
.collect::<Vec<String>>();
174+
if lower_valid_fields.contains(&field.flat_name().to_lowercase()) {
175+
write!(
176+
f,
177+
". Column names are case sensitive. You can use double quotes to refer to the \"{}\" column \
178+
or set the datafusion.sql_parser.enable_ident_normalization configuration",
179+
field.quoted_flat_name()
180+
)?;
181+
}
170182
if !valid_fields.is_empty() {
171183
write!(
172184
f,

datafusion/expr/src/expr_rewriter/mod.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,9 @@ mod test {
462462
normalize_col_with_schemas_and_ambiguity_check(expr, &[&schemas], &[])
463463
.unwrap_err()
464464
.strip_backtrace();
465-
assert_eq!(
466-
error,
467-
r#"Schema error: No field named b. Valid fields are "tableA".a."#
468-
);
465+
let expected = "Schema error: No field named b. \
466+
Valid fields are \"tableA\".a.";
467+
assert_eq!(error, expected);
469468
}
470469

471470
#[test]

datafusion/sql/tests/sql_integration.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,8 @@ Dml: op=[Insert Into] table=[test_decimal]
492492
)]
493493
#[case::non_existing_column(
494494
"INSERT INTO test_decimal (nonexistent, price) VALUES (1, 2), (4, 5)",
495-
"Schema error: No field named nonexistent. Valid fields are id, price."
495+
"Schema error: No field named nonexistent. \
496+
Valid fields are id, price."
496497
)]
497498
#[case::target_column_count_mismatch(
498499
"INSERT INTO person (id, first_name, last_name) VALUES ($1, $2)",
@@ -1358,9 +1359,11 @@ fn select_simple_aggregate_with_groupby_column_unselected() {
13581359
fn select_simple_aggregate_with_groupby_and_column_in_group_by_does_not_exist() {
13591360
let sql = "SELECT sum(age) FROM person GROUP BY doesnotexist";
13601361
let err = logical_plan(sql).expect_err("query should have failed");
1361-
assert_eq!("Schema error: No field named doesnotexist. Valid fields are \"sum(person.age)\", \
1362+
let expected = "Schema error: No field named doesnotexist. \
1363+
Valid fields are \"sum(person.age)\", \
13621364
person.id, person.first_name, person.last_name, person.age, person.state, \
1363-
person.salary, person.birth_date, person.\"😀\".", err.strip_backtrace());
1365+
person.salary, person.birth_date, person.\"😀\".";
1366+
assert_eq!(err.strip_backtrace(), expected);
13641367
}
13651368

13661369
#[test]
@@ -3636,10 +3639,8 @@ fn test_prepare_statement_to_plan_panic_prepare_wrong_syntax() {
36363639
#[test]
36373640
fn test_prepare_statement_to_plan_panic_no_relation_and_constant_param() {
36383641
let sql = "PREPARE my_plan(INT) AS SELECT id + $1";
3639-
assert_eq!(
3640-
logical_plan(sql).unwrap_err().strip_backtrace(),
3641-
"Schema error: No field named id."
3642-
)
3642+
let expected = "Schema error: No field named id.";
3643+
assert_eq!(logical_plan(sql).unwrap_err().strip_backtrace(), expected);
36433644
}
36443645

36453646
#[test]
@@ -4334,18 +4335,14 @@ fn test_multi_grouping_sets() {
43344335
fn test_field_not_found_window_function() {
43354336
let order_by_sql = "SELECT count() OVER (order by a);";
43364337
let order_by_err = logical_plan(order_by_sql).expect_err("query should have failed");
4337-
assert_eq!(
4338-
"Schema error: No field named a.",
4339-
order_by_err.strip_backtrace()
4340-
);
4338+
let expected = "Schema error: No field named a.";
4339+
assert_eq!(order_by_err.strip_backtrace(), expected);
43414340

43424341
let partition_by_sql = "SELECT count() OVER (PARTITION BY a);";
43434342
let partition_by_err =
43444343
logical_plan(partition_by_sql).expect_err("query should have failed");
4345-
assert_eq!(
4346-
"Schema error: No field named a.",
4347-
partition_by_err.strip_backtrace()
4348-
);
4344+
let expected = "Schema error: No field named a.";
4345+
assert_eq!(partition_by_err.strip_backtrace(), expected);
43494346

43504347
let qualified_sql =
43514348
"SELECT order_id, MAX(qty) OVER (PARTITION BY orders.order_id) from orders";

datafusion/sqllogictest/test_files/identifiers.slt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,16 @@ drop table case_insensitive_test
9090
statement ok
9191
CREATE TABLE test("Column1" string) AS VALUES ('content1');
9292

93-
statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
93+
statement error DataFusion error: Schema error: No field named column1. Valid fields are test\."Column1"\.
9494
SELECT COLumn1 from test
9595

96-
statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
96+
statement error DataFusion error: Schema error: No field named column1. Valid fields are test\."Column1"\.
9797
SELECT Column1 from test
9898

99-
statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
99+
statement error DataFusion error: Schema error: No field named column1. Valid fields are test\."Column1"\.
100100
SELECT column1 from test
101101

102-
statement error DataFusion error: Schema error: No field named column1\. Valid fields are test\."Column1"\.
102+
statement error DataFusion error: Schema error: No field named column1. Valid fields are test\."Column1"\.
103103
SELECT "column1" from test
104104

105105
statement ok

datafusion/sqllogictest/test_files/select.slt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,7 @@ select a + b from (select 1 as a, 2 as b, 1 as "a + b");
17991799
3
18001800

18011801
# Can't reference an output column by expression over projection.
1802-
query error DataFusion error: Schema error: No field named a\. Valid fields are "a \+ Int64\(1\)"\.
1802+
query error DataFusion error: Schema error: No field named a. Valid fields are "a \+ Int64\(1\)"\.
18031803
select a + 1 from (select a+1 from (select 1 as a));
18041804

18051805
query I
@@ -1834,5 +1834,5 @@ statement ok
18341834
DROP TABLE test;
18351835

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

0 commit comments

Comments
 (0)