-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Minor: Avoid cloning as many Ident
during SQL planning
#4534
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,9 +72,7 @@ use datafusion_expr::{ | |
}; | ||
|
||
use crate::parser::{CreateExternalTable, DescribeTable, Statement as DFStatement}; | ||
use crate::utils::{ | ||
make_decimal_type, normalize_ident, normalize_ident_owned, resolve_columns, | ||
}; | ||
use crate::utils::{make_decimal_type, normalize_ident, resolve_columns}; | ||
|
||
use super::{ | ||
parser::DFParser, | ||
|
@@ -296,7 +294,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
.. | ||
} if with_options.is_empty() => { | ||
let mut plan = self.query_to_plan(*query, &mut PlannerContext::new())?; | ||
plan = self.apply_expr_alias(plan, &columns)?; | ||
plan = self.apply_expr_alias(plan, columns)?; | ||
|
||
Ok(LogicalPlan::CreateView(CreateView { | ||
name: object_name_to_table_reference(name)?, | ||
|
@@ -484,7 +482,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
|
||
for cte in with.cte_tables { | ||
// A `WITH` block can't use the same name more than once | ||
let cte_name = normalize_ident(&cte.alias.name); | ||
let cte_name = normalize_ident(cte.alias.name.clone()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. previously normalize_indent always cloned. Now it only clones in a few places and most of the time can reuse the String in the sqlparser-ast directly |
||
if planner_context.ctes.contains_key(&cte_name) { | ||
return Err(DataFusionError::SQL(ParserError(format!( | ||
"WITH query name {:?} specified more than once", | ||
|
@@ -689,7 +687,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
.iter() | ||
.any(|x| x.option == ColumnOption::Null); | ||
fields.push(Field::new( | ||
&normalize_ident(&column.name), | ||
&normalize_ident(column.name), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is unfortunate to simply drop the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, Look like we can do improvement like above |
||
data_type, | ||
allow_null, | ||
)); | ||
|
@@ -894,7 +892,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
JoinConstraint::Using(idents) => { | ||
let keys: Vec<Column> = idents | ||
.into_iter() | ||
.map(|x| Column::from_name(normalize_ident(&x))) | ||
.map(|x| Column::from_name(normalize_ident(x))) | ||
.collect(); | ||
LogicalPlanBuilder::from(left) | ||
.join_using(&right, join_type, keys)? | ||
|
@@ -977,16 +975,16 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
) -> Result<LogicalPlan> { | ||
let apply_name_plan = LogicalPlan::SubqueryAlias(SubqueryAlias::try_new( | ||
plan, | ||
&normalize_ident(&alias.name), | ||
normalize_ident(alias.name), | ||
)?); | ||
|
||
self.apply_expr_alias(apply_name_plan, &alias.columns) | ||
self.apply_expr_alias(apply_name_plan, alias.columns) | ||
} | ||
|
||
fn apply_expr_alias( | ||
&self, | ||
plan: LogicalPlan, | ||
idents: &Vec<Ident>, | ||
idents: Vec<Ident>, | ||
) -> Result<LogicalPlan> { | ||
if idents.is_empty() { | ||
Ok(plan) | ||
|
@@ -999,7 +997,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
} else { | ||
let fields = plan.schema().fields().clone(); | ||
LogicalPlanBuilder::from(plan) | ||
.project(fields.iter().zip(idents.iter()).map(|(field, ident)| { | ||
.project(fields.iter().zip(idents.into_iter()).map(|(field, ident)| { | ||
col(field.name()).alias(normalize_ident(ident)) | ||
}))? | ||
.build() | ||
|
@@ -1618,7 +1616,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
from_schema, | ||
&[select_expr.clone()], | ||
)?; | ||
let expr = Alias(Box::new(select_expr), normalize_ident(&alias)); | ||
let expr = Alias(Box::new(select_expr), normalize_ident(alias)); | ||
Ok(vec![normalize_col(expr, plan)?]) | ||
} | ||
SelectItem::Wildcard => { | ||
|
@@ -1946,13 +1944,13 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
|
||
Ok(Expr::Column(Column { | ||
relation: None, | ||
name: normalize_ident(&id), | ||
name: normalize_ident(id), | ||
})) | ||
} | ||
} | ||
|
||
SQLExpr::MapAccess { ref column, keys } => { | ||
if let SQLExpr::Identifier(ref id) = column.as_ref() { | ||
SQLExpr::MapAccess { column, keys } => { | ||
if let SQLExpr::Identifier(id) = *column { | ||
plan_indexed(col(&normalize_ident(id)), keys) | ||
} else { | ||
Err(DataFusionError::NotImplemented(format!( | ||
|
@@ -1969,7 +1967,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
|
||
SQLExpr::CompoundIdentifier(ids) => { | ||
if ids[0].value.starts_with('@') { | ||
let var_names: Vec<_> = ids.into_iter().map(|s| normalize_ident(&s)).collect(); | ||
let var_names: Vec<_> = ids.into_iter().map(normalize_ident).collect(); | ||
let ty = self | ||
.schema_provider | ||
.get_variable_type(&var_names) | ||
|
@@ -2294,7 +2292,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { | |
// (e.g. "foo.bar") for function names yet | ||
function.name.to_string() | ||
} else { | ||
normalize_ident(&function.name.0[0]) | ||
normalize_ident(function.name.0[0].clone()) | ||
}; | ||
|
||
// first, check SQL reserved words | ||
|
@@ -3060,7 +3058,7 @@ fn idents_to_table_reference(idents: Vec<Ident>) -> Result<OwnedTableReference> | |
impl IdentTaker { | ||
fn take(&mut self) -> String { | ||
let ident = self.0.pop().expect("no more identifiers"); | ||
normalize_ident_owned(ident) | ||
normalize_ident(ident) | ||
} | ||
} | ||
|
||
|
@@ -3103,7 +3101,7 @@ pub fn object_name_to_qualifier(sql_table_name: &ObjectName) -> String { | |
.rev() | ||
.zip(columns) | ||
.map(|(ident, column_name)| { | ||
format!(r#"{} = '{}'"#, column_name, normalize_ident(ident)) | ||
format!(r#"{} = '{}'"#, column_name, normalize_ident(ident.clone())) | ||
}) | ||
.collect::<Vec<_>>() | ||
.join(" AND ") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -539,16 +539,8 @@ pub(crate) fn make_decimal_type( | |
} | ||
} | ||
|
||
// Normalize an identifier to a lowercase string unless the identifier is quoted. | ||
pub(crate) fn normalize_ident(id: &Ident) -> String { | ||
match id.quote_style { | ||
Some(_) => id.value.clone(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here the value is always cloned which is not necessary for most uses when we already have an owned string |
||
None => id.value.to_ascii_lowercase(), | ||
} | ||
} | ||
|
||
// Normalize an owned identifier to a lowercase string unless the identifier is quoted. | ||
pub(crate) fn normalize_ident_owned(id: Ident) -> String { | ||
pub(crate) fn normalize_ident(id: Ident) -> String { | ||
match id.quote_style { | ||
Some(_) => id.value, | ||
None => id.value.to_ascii_lowercase(), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change allows
SubqueryAlias::try_new
to take aString
if the caller has one or a&str
that will be copied into a new String if neededThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice implementation👍, copy just when call
&str
.