Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 67 additions & 4 deletions datafusion/common/src/dfschema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1338,11 +1338,44 @@ impl SchemaExt for Schema {
}
}

/// Build a fully-qualified field name string. This is equivalent to
/// `format!("{q}.{name}")` when `qualifier` is `Some`, or just `name` when
/// `None`. We avoid going through the `fmt` machinery for performance reasons.
pub fn qualified_name(qualifier: Option<&TableReference>, name: &str) -> String {
match qualifier {
Some(q) => format!("{q}.{name}"),
None => name.to_string(),
}
let qualifier = match qualifier {
None => return name.to_string(),
Some(q) => q,
};
let (a, b, c) = match qualifier {
TableReference::Bare { table } => (table.as_ref(), None, None),
TableReference::Partial { schema, table } => {
(schema.as_ref(), Some(table.as_ref()), None)
}
TableReference::Full {
catalog,
schema,
table,
} => (
catalog.as_ref(),
Some(schema.as_ref()),
Some(table.as_ref()),
),
};

let extra = b.unwrap_or("").len() + c.unwrap_or("").len();
let mut s = String::with_capacity(a.len() + extra + 3 + name.len());
s.push_str(a);
if let Some(b) = b {
s.push('.');
s.push_str(b);
}
if let Some(c) = c {
s.push('.');
s.push_str(c);
}
s.push('.');
s.push_str(name);
s
}

#[cfg(test)]
Expand All @@ -1351,6 +1384,36 @@ mod tests {

use super::*;

/// `qualified_name` doesn't use `TableReference::Display` for performance
/// reasons, but check that the output is consistent.
#[test]
fn qualified_name_agrees_with_display() {
let cases: &[(Option<TableReference>, &str)] = &[
(None, "col"),
(Some(TableReference::bare("t")), "c0"),
(Some(TableReference::partial("s", "t")), "c0"),
(Some(TableReference::full("c", "s", "t")), "c0"),
(Some(TableReference::bare("mytable")), "some_column_name"),
// Empty segments must be preserved so that distinct qualified
// fields don't collide in `DFSchema::field_names()`.
(Some(TableReference::bare("")), "col"),
(Some(TableReference::partial("s", "")), "col"),
(Some(TableReference::partial("", "t")), "col"),
(Some(TableReference::full("c", "", "t")), "col"),
(Some(TableReference::full("", "s", "t")), "col"),
(Some(TableReference::full("c", "s", "")), "col"),
(Some(TableReference::full("", "", "")), "col"),
];
for (qualifier, name) in cases {
let actual = qualified_name(qualifier.as_ref(), name);
let expected = match qualifier {
Some(q) => format!("{q}.{name}"),
None => name.to_string(),
};
assert_eq!(actual, expected, "qualifier={qualifier:?} name={name}");
}
}

#[test]
fn qualifier_in_name() -> Result<()> {
let col = Column::from_name("t1.c0");
Expand Down
Loading