Skip to content

Commit 0c4ace8

Browse files
authored
feat: Upgrade to sqlparser-rs 0.62.0 (#22069)
## Which issue does this PR close? <!-- We generally require a GitHub issue to be filed for all bug fixes and enhancements and this helps us generate change logs for our releases. You can link an issue to this PR using the GitHub syntax. For example `Closes #123` indicates that this PR will close issue #123. --> N/A ## Rationale for this change <!-- Why are you proposing this change? If this is already explained clearly in the issue then this section is not needed. Explaining clearly why changes are proposed helps reviewers understand your changes and offer better suggestions for fixes. --> Dependency update ## What changes are included in this PR? <!-- There is no need to duplicate the description in the issue here but it is sometimes worth providing a summary of the individual changes in this PR. --> ## Are these changes tested? <!-- We typically require tests for all PRs in order to: 1. Prevent the code from being accidentally broken by subsequent changes 2. Serve as another way to document the expected behavior of the code If tests are not included in your PR, please explain why (for example, are they covered by existing tests)? --> ## Are there any user-facing changes? <!-- If there are user-facing changes then we may require documentation to be updated before approving the PR. --> <!-- If there are any breaking changes to public APIs, please add the `api change` label. -->
1 parent 12bd5b0 commit 0c4ace8

15 files changed

Lines changed: 213 additions & 41 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ regex = "1.12"
192192
rstest = "0.26.1"
193193
serde_json = "1"
194194
sha2 = "^0.11.0"
195-
sqlparser = { version = "0.61.0", default-features = false, features = ["std", "visitor"] }
195+
sqlparser = { version = "0.62.0", default-features = false, features = ["std", "visitor"] }
196196
strum = "0.28.0"
197197
strum_macros = "0.28.0"
198198
tempfile = "3"

datafusion/expr/src/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4014,8 +4014,8 @@ mod test {
40144014
wildcard_with_options(wildcard_options(
40154015
None,
40164016
Some(ExcludeSelectItem::Multiple(vec![
4017-
Ident::from("c1"),
4018-
Ident::from("c2")
4017+
Ident::from("c1").into(),
4018+
Ident::from("c2").into()
40194019
])),
40204020
None,
40214021
None,

datafusion/expr/src/sql.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ impl Display for IlikeSelectItem {
4545

4646
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
4747
pub enum ExcludeSelectItem {
48-
Single(Ident),
49-
Multiple(Vec<Ident>),
48+
Single(ObjectName),
49+
Multiple(Vec<ObjectName>),
5050
}
5151

5252
impl Display for ExcludeSelectItem {
@@ -64,6 +64,37 @@ impl Display for ExcludeSelectItem {
6464
}
6565
}
6666

67+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
68+
pub struct ObjectName(pub Vec<ObjectNamePart>);
69+
70+
impl Display for ObjectName {
71+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
72+
let parts: Vec<String> = self.0.iter().map(|p| format!("{p}")).collect();
73+
write!(f, "{}", parts.join("."))
74+
}
75+
}
76+
77+
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
78+
pub enum ObjectNamePart {
79+
Identifier(Ident),
80+
}
81+
82+
impl ObjectNamePart {
83+
pub fn as_ident(&self) -> Option<&Ident> {
84+
match self {
85+
ObjectNamePart::Identifier(ident) => Some(ident),
86+
}
87+
}
88+
}
89+
90+
impl Display for ObjectNamePart {
91+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
92+
match self {
93+
ObjectNamePart::Identifier(ident) => write!(f, "{ident}"),
94+
}
95+
}
96+
}
97+
6798
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
6899
pub struct ExceptSelectItem {
69100
pub first_element: Ident,

datafusion/expr/src/utils.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ use datafusion_common::{
3939
};
4040

4141
#[cfg(not(feature = "sql"))]
42-
use crate::sql::{ExceptSelectItem, ExcludeSelectItem};
42+
use crate::sql::{ExceptSelectItem, ExcludeSelectItem, Ident, ObjectName};
4343
use indexmap::IndexSet;
4444
#[cfg(feature = "sql")]
45-
use sqlparser::ast::{ExceptSelectItem, ExcludeSelectItem};
45+
use sqlparser::ast::{ExceptSelectItem, ExcludeSelectItem, Ident, ObjectName};
4646

4747
pub use datafusion_functions_aggregate_common::order::AggregateOrderSensitivity;
4848

@@ -339,11 +339,32 @@ fn get_excluded_columns(
339339
idents.push(&excepts.first_element);
340340
idents.extend(&excepts.additional_elements);
341341
}
342+
// Declared outside the `if let` so `idents.extend(exclude_owned.iter())`
343+
// below can borrow references that outlive the inner scope.
344+
let exclude_owned: Vec<Ident>;
342345
if let Some(exclude) = opt_exclude {
343-
match exclude {
344-
ExcludeSelectItem::Single(ident) => idents.push(ident),
345-
ExcludeSelectItem::Multiple(idents_inner) => idents.extend(idents_inner),
346-
}
346+
let object_name_to_ident = |name: &ObjectName| -> Result<Ident> {
347+
if name.0.len() != 1 {
348+
return plan_err!(
349+
"EXCLUDE with multi-part identifiers is not supported: {name}"
350+
);
351+
}
352+
let part = &name.0[0];
353+
let Some(ident) = part.as_ident() else {
354+
return plan_err!(
355+
"EXCLUDE with non-identifier name part is not supported: {part}"
356+
);
357+
};
358+
Ok(ident.clone())
359+
};
360+
exclude_owned = match exclude {
361+
ExcludeSelectItem::Single(name) => vec![object_name_to_ident(name)?],
362+
ExcludeSelectItem::Multiple(names) => names
363+
.iter()
364+
.map(object_name_to_ident)
365+
.collect::<Result<Vec<_>>>()?,
366+
};
367+
idents.extend(exclude_owned.iter());
347368
}
348369
// Excluded columns should be unique
349370
let n_elem = idents.len();

datafusion/sql/src/expr/function.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -927,10 +927,15 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
927927
);
928928
}
929929

930+
if lambda.params.iter().any(|p| p.data_type.is_some()) {
931+
return not_impl_err!(
932+
"Lambda parameters with explicit data types are not supported"
933+
);
934+
}
930935
let params = lambda
931936
.params
932937
.iter()
933-
.map(|p| crate::utils::normalize_ident(p.clone()))
938+
.map(|p| crate::utils::normalize_ident(p.name.clone()))
934939
.collect();
935940

936941
let lambda_parameters = std::iter::zip(lambda_params, &params)
@@ -1181,19 +1186,19 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
11811186
/// After normalization with [normalize_ident], check whether all params are unique
11821187
///
11831188
/// [normalize_ident]: crate::utils::normalize_ident
1184-
fn all_unique(params: &[sqlparser::ast::Ident]) -> bool {
1189+
fn all_unique(params: &[sqlparser::ast::LambdaFunctionParameter]) -> bool {
11851190
match params.len() {
11861191
0 | 1 => true,
11871192
2 => {
1188-
crate::utils::normalize_ident(params[0].clone())
1189-
!= crate::utils::normalize_ident(params[1].clone())
1193+
crate::utils::normalize_ident(params[0].name.clone())
1194+
!= crate::utils::normalize_ident(params[1].name.clone())
11901195
}
11911196
_ => {
11921197
let mut set = HashSet::with_capacity(params.len());
11931198

11941199
params
11951200
.iter()
1196-
.map(|p| crate::utils::normalize_ident(p.clone()))
1201+
.map(|p| crate::utils::normalize_ident(p.name.clone()))
11971202
.all(|p| set.insert(p))
11981203
}
11991204
}

datafusion/sql/src/expr/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
900900
negated: bool,
901901
expr: SQLExpr,
902902
pattern: SQLExpr,
903-
escape_char: Option<Value>,
903+
escape_char: Option<ValueWithSpan>,
904904
schema: &DFSchema,
905905
planner_context: &mut PlannerContext,
906906
case_insensitive: bool,
@@ -910,7 +910,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
910910
return not_impl_err!("ANY in LIKE expression");
911911
}
912912
let pattern = self.sql_expr_to_logical_expr(pattern, schema, planner_context)?;
913-
let escape_char = match escape_char {
913+
let escape_char = match escape_char.map(|v| v.value) {
914914
Some(Value::SingleQuotedString(char)) if char.len() == 1 => {
915915
Some(char.chars().next().unwrap())
916916
}
@@ -935,7 +935,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
935935
negated: bool,
936936
expr: SQLExpr,
937937
pattern: SQLExpr,
938-
escape_char: Option<Value>,
938+
escape_char: Option<ValueWithSpan>,
939939
schema: &DFSchema,
940940
planner_context: &mut PlannerContext,
941941
) -> Result<Expr> {
@@ -944,7 +944,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
944944
if pattern_type != DataType::Utf8 && pattern_type != DataType::Null {
945945
return plan_err!("Invalid pattern in SIMILAR TO expression");
946946
}
947-
let escape_char = match escape_char {
947+
let escape_char = match escape_char.map(|v| v.value) {
948948
Some(Value::SingleQuotedString(char)) if char.len() == 1 => {
949949
Some(char.chars().next().unwrap())
950950
}

datafusion/sql/src/query.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
171171
// Apply to all fields
172172
columns: vec![],
173173
explicit: true,
174+
at: None,
174175
},
175176
),
176177
PipeOperator::Union {

datafusion/sql/src/select.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,9 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
839839

840840
Ok(SelectExpr::Expression(expr))
841841
}
842+
SelectItem::ExprWithAliases { .. } => {
843+
not_impl_err!("SELECT item with multiple aliases is not supported")
844+
}
842845
SelectItem::Wildcard(options) => {
843846
Self::check_wildcard_options(&options)?;
844847
if empty_from {
@@ -886,11 +889,14 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
886889
opt_rename,
887890
opt_replace: _opt_replace,
888891
opt_ilike: _opt_ilike,
892+
opt_alias,
889893
wildcard_token: _wildcard_token,
890894
} = options;
891895

892896
if opt_rename.is_some() {
893897
not_impl_err!("wildcard * with RENAME not supported ")
898+
} else if opt_alias.is_some() {
899+
not_impl_err!("wildcard * with AS alias not supported")
894900
} else {
895901
Ok(())
896902
}

0 commit comments

Comments
 (0)