Skip to content

Commit 27ce5eb

Browse files
committed
Fix: check ambiguous column reference
1 parent 6590ea3 commit 27ce5eb

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

datafusion/common/src/dfschema.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,33 @@ impl DFSchema {
412412
}
413413
}
414414

415+
/// Check whether the column reference is ambiguous
416+
pub fn check_ambiguous_name(
417+
&self,
418+
qualifier: Option<&TableReference>,
419+
name: &str,
420+
) -> Result<()> {
421+
let count = self
422+
.iter()
423+
.filter(|(field_q, f)| match (field_q, qualifier) {
424+
(Some(q1), Some(q2)) => q1.resolved_eq(q2) && f.name() == name,
425+
(None, None) => f.name() == name,
426+
_ => false,
427+
})
428+
.take(2)
429+
.count();
430+
if count > 1 {
431+
_schema_err!(SchemaError::AmbiguousReference {
432+
field: Column {
433+
relation: None,
434+
name: name.to_string(),
435+
},
436+
})
437+
} else {
438+
Ok(())
439+
}
440+
}
441+
415442
/// Find the qualified field with the given name
416443
pub fn qualified_field_with_name(
417444
&self,

datafusion/sql/src/expr/identifier.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,12 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
132132
nested_names,
133133
) {
134134
match planner_result {
135-
PlannerResult::Planned(expr) => return Ok(expr),
135+
PlannerResult::Planned(expr) => {
136+
// sanity check on column
137+
schema
138+
.check_ambiguous_name(qualifier, field.name())?;
139+
return Ok(expr);
140+
}
136141
PlannerResult::Original(_args) => {}
137142
}
138143
}
@@ -143,6 +148,8 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
143148
}
144149
// found matching field with no spare identifier(s)
145150
Some((field, qualifier, _nested_names)) => {
151+
// sanity check on column
152+
schema.check_ambiguous_name(qualifier, field.name())?;
146153
Ok(Expr::Column(Column::from((qualifier, field))))
147154
}
148155
None => {
@@ -186,6 +193,9 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
186193
let s = &ids[0..ids.len()];
187194
// safe unwrap as s can never be empty or exceed the bounds
188195
let (relation, column_name) = form_identifier(s).unwrap();
196+
// sanity check on column
197+
schema
198+
.check_ambiguous_name(relation.as_ref(), column_name)?;
189199
Ok(Expr::Column(Column::new(relation, column_name)))
190200
}
191201
}

datafusion/sqllogictest/test_files/join.slt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,3 +1209,20 @@ drop table t1;
12091209

12101210
statement ok
12111211
drop table t2;
1212+
1213+
# Test SQLancer issue: https://github.com/apache/datafusion/issues/12337
1214+
statement ok
1215+
create table t1(v1 int) as values(100);
1216+
1217+
## Query with Ambiguous column reference
1218+
query error DataFusion error: Schema error: Ambiguous reference to unqualified field v1
1219+
select count(*)
1220+
from t1
1221+
right outer join t1
1222+
on t1.v1 > 0;
1223+
1224+
query error DataFusion error: Schema error: Ambiguous reference to unqualified field v1
1225+
select t1.v1 from t1 join t1 using(v1) cross join (select struct('foo' as v1) as t1);
1226+
1227+
statement ok
1228+
drop table t1;

0 commit comments

Comments
 (0)