mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-12-23 11:12:51 +00:00
Enhance object name path segments (#1539)
This commit is contained in:
parent
fd6c98e933
commit
211b15e790
20 changed files with 584 additions and 466 deletions
|
|
@ -988,7 +988,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
Token::Mul => {
|
||||
return Ok(Expr::QualifiedWildcard(
|
||||
ObjectName(id_parts),
|
||||
ObjectName::from(id_parts),
|
||||
AttachedToken(next_token),
|
||||
));
|
||||
}
|
||||
|
|
@ -1128,7 +1128,7 @@ impl<'a> Parser<'a> {
|
|||
if dialect_of!(self is PostgreSqlDialect | GenericDialect) =>
|
||||
{
|
||||
Ok(Some(Expr::Function(Function {
|
||||
name: ObjectName(vec![w.clone().into_ident(w_span)]),
|
||||
name: ObjectName::from(vec![w.clone().into_ident(w_span)]),
|
||||
uses_odbc_syntax: false,
|
||||
parameters: FunctionArguments::None,
|
||||
args: FunctionArguments::None,
|
||||
|
|
@ -1143,7 +1143,7 @@ impl<'a> Parser<'a> {
|
|||
| Keyword::CURRENT_DATE
|
||||
| Keyword::LOCALTIME
|
||||
| Keyword::LOCALTIMESTAMP => {
|
||||
Ok(Some(self.parse_time_functions(ObjectName(vec![w.clone().into_ident(w_span)]))?))
|
||||
Ok(Some(self.parse_time_functions(ObjectName::from(vec![w.clone().into_ident(w_span)]))?))
|
||||
}
|
||||
Keyword::CASE => Ok(Some(self.parse_case_expr()?)),
|
||||
Keyword::CONVERT => Ok(Some(self.parse_convert_expr(false)?)),
|
||||
|
|
@ -1187,7 +1187,7 @@ impl<'a> Parser<'a> {
|
|||
let query = self.parse_query()?;
|
||||
self.expect_token(&Token::RParen)?;
|
||||
Ok(Some(Expr::Function(Function {
|
||||
name: ObjectName(vec![w.clone().into_ident(w_span)]),
|
||||
name: ObjectName::from(vec![w.clone().into_ident(w_span)]),
|
||||
uses_odbc_syntax: false,
|
||||
parameters: FunctionArguments::None,
|
||||
args: FunctionArguments::Subquery(query),
|
||||
|
|
@ -1232,7 +1232,7 @@ impl<'a> Parser<'a> {
|
|||
if let Some(expr) = self.parse_outer_join_expr(&id_parts) {
|
||||
Ok(expr)
|
||||
} else {
|
||||
let mut expr = self.parse_function(ObjectName(id_parts))?;
|
||||
let mut expr = self.parse_function(ObjectName::from(id_parts))?;
|
||||
// consume all period if it's a method chain
|
||||
expr = self.try_parse_method(expr)?;
|
||||
let fields = vec![];
|
||||
|
|
@ -1553,7 +1553,7 @@ impl<'a> Parser<'a> {
|
|||
return self.expected("an identifier or a '*' after '.'", self.peek_token());
|
||||
};
|
||||
Ok(Expr::QualifiedWildcard(
|
||||
ObjectName(Self::exprs_to_idents(root, chain)?),
|
||||
ObjectName::from(Self::exprs_to_idents(root, chain)?),
|
||||
AttachedToken(wildcard_token),
|
||||
))
|
||||
} else if self.peek_token().token == Token::LParen {
|
||||
|
|
@ -1566,7 +1566,7 @@ impl<'a> Parser<'a> {
|
|||
if let Some(expr) = self.parse_outer_join_expr(&id_parts) {
|
||||
Ok(expr)
|
||||
} else {
|
||||
self.parse_function(ObjectName(id_parts))
|
||||
self.parse_function(ObjectName::from(id_parts))
|
||||
}
|
||||
} else {
|
||||
if Self::is_all_ident(&root, &chain) {
|
||||
|
|
@ -1694,7 +1694,7 @@ impl<'a> Parser<'a> {
|
|||
Token::Word(word) => word.into_ident(tok.span),
|
||||
_ => return p.expected("identifier", tok),
|
||||
};
|
||||
let func = match p.parse_function(ObjectName(vec![name]))? {
|
||||
let func = match p.parse_function(ObjectName::from(vec![name]))? {
|
||||
Expr::Function(func) => func,
|
||||
_ => return p.expected("function", p.peek_token()),
|
||||
};
|
||||
|
|
@ -2197,7 +2197,7 @@ impl<'a> Parser<'a> {
|
|||
Some(expr) => Ok(expr),
|
||||
// Snowflake supports `position` as an ordinary function call
|
||||
// without the special `IN` syntax.
|
||||
None => self.parse_function(ObjectName(vec![ident])),
|
||||
None => self.parse_function(ObjectName::from(vec![ident])),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4044,6 +4044,21 @@ impl<'a> Parser<'a> {
|
|||
Ok(values)
|
||||
}
|
||||
|
||||
/// Parse a period-separated list of 1+ items accepted by `F`
|
||||
fn parse_period_separated<T, F>(&mut self, mut f: F) -> Result<Vec<T>, ParserError>
|
||||
where
|
||||
F: FnMut(&mut Parser<'a>) -> Result<T, ParserError>,
|
||||
{
|
||||
let mut values = vec![];
|
||||
loop {
|
||||
values.push(f(self)?);
|
||||
if !self.consume_token(&Token::Period) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
/// Parse a keyword-separated list of 1+ items accepted by `F`
|
||||
pub fn parse_keyword_separated<T, F>(
|
||||
&mut self,
|
||||
|
|
@ -4757,7 +4772,9 @@ impl<'a> Parser<'a> {
|
|||
let mut data_type = self.parse_data_type()?;
|
||||
if let DataType::Custom(n, _) = &data_type {
|
||||
// the first token is actually a name
|
||||
name = Some(n.0[0].clone());
|
||||
match n.0[0].clone() {
|
||||
ObjectNamePart::Identifier(ident) => name = Some(ident),
|
||||
}
|
||||
data_type = self.parse_data_type()?;
|
||||
}
|
||||
|
||||
|
|
@ -9063,7 +9080,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(ObjectName(idents))
|
||||
Ok(ObjectName::from(idents))
|
||||
}
|
||||
|
||||
/// Parse a possibly qualified, possibly quoted identifier, e.g.
|
||||
|
|
@ -9079,20 +9096,26 @@ impl<'a> Parser<'a> {
|
|||
// BigQuery accepts any number of quoted identifiers of a table name.
|
||||
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_identifiers
|
||||
if dialect_of!(self is BigQueryDialect)
|
||||
&& idents.iter().any(|ident| ident.value.contains('.'))
|
||||
&& idents.iter().any(|part| {
|
||||
part.as_ident()
|
||||
.is_some_and(|ident| ident.value.contains('.'))
|
||||
})
|
||||
{
|
||||
idents = idents
|
||||
.into_iter()
|
||||
.flat_map(|ident| {
|
||||
ident
|
||||
.flat_map(|part| match part.as_ident() {
|
||||
Some(ident) => ident
|
||||
.value
|
||||
.split('.')
|
||||
.map(|value| Ident {
|
||||
value: value.into(),
|
||||
quote_style: ident.quote_style,
|
||||
span: ident.span,
|
||||
.map(|value| {
|
||||
ObjectNamePart::Identifier(Ident {
|
||||
value: value.into(),
|
||||
quote_style: ident.quote_style,
|
||||
span: ident.span,
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.collect::<Vec<_>>(),
|
||||
None => vec![part],
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
@ -10427,14 +10450,14 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
let variables = if self.parse_keywords(&[Keyword::TIME, Keyword::ZONE]) {
|
||||
OneOrManyWithParens::One(ObjectName(vec!["TIMEZONE".into()]))
|
||||
OneOrManyWithParens::One(ObjectName::from(vec!["TIMEZONE".into()]))
|
||||
} else if self.dialect.supports_parenthesized_set_variables()
|
||||
&& self.consume_token(&Token::LParen)
|
||||
{
|
||||
let variables = OneOrManyWithParens::Many(
|
||||
self.parse_comma_separated(|parser: &mut Parser<'a>| parser.parse_identifier())?
|
||||
.into_iter()
|
||||
.map(|ident| ObjectName(vec![ident]))
|
||||
.map(|ident| ObjectName::from(vec![ident]))
|
||||
.collect(),
|
||||
);
|
||||
self.expect_token(&Token::RParen)?;
|
||||
|
|
@ -11770,7 +11793,7 @@ impl<'a> Parser<'a> {
|
|||
Token::Word(w) => Ok(w.value),
|
||||
_ => self.expected("a function identifier", self.peek_token()),
|
||||
}?;
|
||||
let expr = self.parse_function(ObjectName(vec![Ident::new(function_name)]))?;
|
||||
let expr = self.parse_function(ObjectName::from(vec![Ident::new(function_name)]))?;
|
||||
let alias = if self.parse_keyword(Keyword::AS) {
|
||||
Some(self.parse_identifier()?)
|
||||
} else {
|
||||
|
|
@ -11819,7 +11842,7 @@ impl<'a> Parser<'a> {
|
|||
self.expect_token(&Token::LParen)?;
|
||||
let aggregate_functions = self.parse_comma_separated(Self::parse_aliased_function_call)?;
|
||||
self.expect_keyword_is(Keyword::FOR)?;
|
||||
let value_column = self.parse_object_name(false)?.0;
|
||||
let value_column = self.parse_period_separated(|p| p.parse_identifier())?;
|
||||
self.expect_keyword_is(Keyword::IN)?;
|
||||
|
||||
self.expect_token(&Token::LParen)?;
|
||||
|
|
@ -11955,10 +11978,9 @@ impl<'a> Parser<'a> {
|
|||
// https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-iam-access-control-native-idp.html
|
||||
let ident = self.parse_identifier()?;
|
||||
if let GranteeName::ObjectName(namespace) = name {
|
||||
name = GranteeName::ObjectName(ObjectName(vec![Ident::new(format!(
|
||||
"{}:{}",
|
||||
namespace, ident
|
||||
))]));
|
||||
name = GranteeName::ObjectName(ObjectName::from(vec![Ident::new(
|
||||
format!("{}:{}", namespace, ident),
|
||||
)]));
|
||||
};
|
||||
}
|
||||
Grantee {
|
||||
|
|
@ -12267,9 +12289,10 @@ impl<'a> Parser<'a> {
|
|||
let mut name = self.parse_object_name(false)?;
|
||||
if self.dialect.supports_user_host_grantee()
|
||||
&& name.0.len() == 1
|
||||
&& name.0[0].as_ident().is_some()
|
||||
&& self.consume_token(&Token::AtSign)
|
||||
{
|
||||
let user = name.0.pop().unwrap();
|
||||
let user = name.0.pop().unwrap().as_ident().unwrap().clone();
|
||||
let host = self.parse_identifier()?;
|
||||
Ok(GranteeName::UserHost { user, host })
|
||||
} else {
|
||||
|
|
@ -13781,7 +13804,7 @@ impl<'a> Parser<'a> {
|
|||
// [ OWNED BY { table_name.column_name | NONE } ]
|
||||
let owned_by = if self.parse_keywords(&[Keyword::OWNED, Keyword::BY]) {
|
||||
if self.parse_keywords(&[Keyword::NONE]) {
|
||||
Some(ObjectName(vec![Ident::new("NONE")]))
|
||||
Some(ObjectName::from(vec![Ident::new("NONE")]))
|
||||
} else {
|
||||
Some(self.parse_object_name(false)?)
|
||||
}
|
||||
|
|
@ -14072,7 +14095,9 @@ impl<'a> Parser<'a> {
|
|||
.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN])
|
||||
.is_some()
|
||||
{
|
||||
parent_name.0.insert(0, self.parse_identifier()?);
|
||||
parent_name
|
||||
.0
|
||||
.insert(0, ObjectNamePart::Identifier(self.parse_identifier()?));
|
||||
}
|
||||
(None, Some(parent_name))
|
||||
}
|
||||
|
|
@ -14388,14 +14413,14 @@ mod tests {
|
|||
test_parse_data_type!(
|
||||
dialect,
|
||||
"GEOMETRY",
|
||||
DataType::Custom(ObjectName(vec!["GEOMETRY".into()]), vec![])
|
||||
DataType::Custom(ObjectName::from(vec!["GEOMETRY".into()]), vec![])
|
||||
);
|
||||
|
||||
test_parse_data_type!(
|
||||
dialect,
|
||||
"GEOMETRY(POINT)",
|
||||
DataType::Custom(
|
||||
ObjectName(vec!["GEOMETRY".into()]),
|
||||
ObjectName::from(vec!["GEOMETRY".into()]),
|
||||
vec!["POINT".to_string()]
|
||||
)
|
||||
);
|
||||
|
|
@ -14404,7 +14429,7 @@ mod tests {
|
|||
dialect,
|
||||
"GEOMETRY(POINT, 4326)",
|
||||
DataType::Custom(
|
||||
ObjectName(vec!["GEOMETRY".into()]),
|
||||
ObjectName::from(vec!["GEOMETRY".into()]),
|
||||
vec!["POINT".to_string(), "4326".to_string()]
|
||||
)
|
||||
);
|
||||
|
|
@ -14540,7 +14565,7 @@ mod tests {
|
|||
}};
|
||||
}
|
||||
|
||||
let dummy_name = ObjectName(vec![Ident::new("dummy_name")]);
|
||||
let dummy_name = ObjectName::from(vec![Ident::new("dummy_name")]);
|
||||
let dummy_authorization = Ident::new("dummy_authorization");
|
||||
|
||||
test_parse_schema_name!(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue