Enhance object name path segments (#1539)

This commit is contained in:
Ayman Elkfrawy 2025-01-26 06:13:51 -08:00 committed by GitHub
parent fd6c98e933
commit 211b15e790
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 584 additions and 466 deletions

View file

@ -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!(