Skip to content

Commit f995de5

Browse files
authored
Improve field not found error messages (#625)
1 parent 5bdc880 commit f995de5

File tree

2 files changed

+50
-12
lines changed

2 files changed

+50
-12
lines changed

datafusion/src/logical_plan/dfschema.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,18 @@ impl DFSchema {
135135
&self.fields[i]
136136
}
137137

138-
/// Find the index of the column with the given unqualifed name
138+
/// Find the index of the column with the given unqualified name
139139
pub fn index_of(&self, name: &str) -> Result<usize> {
140140
for i in 0..self.fields.len() {
141141
if self.fields[i].name() == name {
142142
return Ok(i);
143143
}
144144
}
145-
Err(DataFusionError::Plan(format!("No field named '{}'", name)))
145+
Err(DataFusionError::Plan(format!(
146+
"No field named '{}'. Valid fields are {}.",
147+
name,
148+
self.get_field_names()
149+
)))
146150
}
147151

148152
/// Find the index of the column with the given qualifer and name
@@ -181,8 +185,9 @@ impl DFSchema {
181185
.collect();
182186
match matches.len() {
183187
0 => Err(DataFusionError::Plan(format!(
184-
"No field with unqualified name '{}'",
185-
name
188+
"No field with unqualified name '{}'. Valid fields are {}.",
189+
name,
190+
self.get_field_names()
186191
))),
187192
1 => Ok(matches[0].to_owned()),
188193
_ => Err(DataFusionError::Plan(format!(
@@ -207,8 +212,10 @@ impl DFSchema {
207212
.collect();
208213
match matches.len() {
209214
0 => Err(DataFusionError::Plan(format!(
210-
"No field named '{}.{}'",
211-
relation_name, name
215+
"No field named '{}.{}'. Valid fields are {}.",
216+
relation_name,
217+
name,
218+
self.get_field_names()
212219
))),
213220
1 => Ok(matches[0].to_owned()),
214221
_ => Err(DataFusionError::Internal(format!(
@@ -273,6 +280,15 @@ impl DFSchema {
273280
.collect(),
274281
}
275282
}
283+
284+
/// Get comma-seperated list of field names for use in error messages
285+
fn get_field_names(&self) -> String {
286+
self.fields
287+
.iter()
288+
.map(|f| format!("'{}'", f.name()))
289+
.collect::<Vec<_>>()
290+
.join(", ")
291+
}
276292
}
277293

278294
impl Into<Schema> for DFSchema {
@@ -585,6 +601,28 @@ mod tests {
585601
Ok(())
586602
}
587603

604+
#[test]
605+
fn helpful_error_messages() -> Result<()> {
606+
let schema = DFSchema::try_from_qualified_schema("t1", &test_schema_1())?;
607+
let expected_help = "Valid fields are \'c0\', \'c1\'.";
608+
assert!(schema
609+
.field_with_qualified_name("x", "y")
610+
.unwrap_err()
611+
.to_string()
612+
.contains(expected_help));
613+
assert!(schema
614+
.field_with_unqualified_name("y")
615+
.unwrap_err()
616+
.to_string()
617+
.contains(expected_help));
618+
assert!(schema
619+
.index_of("y")
620+
.unwrap_err()
621+
.to_string()
622+
.contains(expected_help));
623+
Ok(())
624+
}
625+
588626
#[test]
589627
fn into() {
590628
// Demonstrate how to convert back and forth between Schema, SchemaRef, DFSchema, and DFSchemaRef

datafusion/src/sql/planner.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,7 @@ mod tests {
16501650
let err = logical_plan(sql).expect_err("query should have failed");
16511651
assert!(matches!(
16521652
err,
1653-
DataFusionError::Plan(msg) if msg == "No field with unqualified name 'doesnotexist'",
1653+
DataFusionError::Plan(msg) if msg.contains("No field with unqualified name 'doesnotexist'"),
16541654
));
16551655
}
16561656

@@ -1708,7 +1708,7 @@ mod tests {
17081708
let err = logical_plan(sql).expect_err("query should have failed");
17091709
assert!(matches!(
17101710
err,
1711-
DataFusionError::Plan(msg) if msg == "No field with unqualified name 'doesnotexist'",
1711+
DataFusionError::Plan(msg) if msg.contains("No field with unqualified name 'doesnotexist'"),
17121712
));
17131713
}
17141714

@@ -1718,7 +1718,7 @@ mod tests {
17181718
let err = logical_plan(sql).expect_err("query should have failed");
17191719
assert!(matches!(
17201720
err,
1721-
DataFusionError::Plan(msg) if msg == "No field with unqualified name 'x'",
1721+
DataFusionError::Plan(msg) if msg.contains("No field with unqualified name 'x'"),
17221722
));
17231723
}
17241724

@@ -2189,7 +2189,7 @@ mod tests {
21892189
let err = logical_plan(sql).expect_err("query should have failed");
21902190
assert!(matches!(
21912191
err,
2192-
DataFusionError::Plan(msg) if msg == "No field with unqualified name 'doesnotexist'",
2192+
DataFusionError::Plan(msg) if msg.contains("No field with unqualified name 'doesnotexist'"),
21932193
));
21942194
}
21952195

@@ -2279,7 +2279,7 @@ mod tests {
22792279
let err = logical_plan(sql).expect_err("query should have failed");
22802280
assert!(matches!(
22812281
err,
2282-
DataFusionError::Plan(msg) if msg == "No field with unqualified name 'doesnotexist'",
2282+
DataFusionError::Plan(msg) if msg.contains("No field with unqualified name 'doesnotexist'"),
22832283
));
22842284
}
22852285

@@ -2289,7 +2289,7 @@ mod tests {
22892289
let err = logical_plan(sql).expect_err("query should have failed");
22902290
assert!(matches!(
22912291
err,
2292-
DataFusionError::Plan(msg) if msg == "No field with unqualified name 'doesnotexist'",
2292+
DataFusionError::Plan(msg) if msg.contains("No field with unqualified name 'doesnotexist'"),
22932293
));
22942294
}
22952295

0 commit comments

Comments
 (0)