@@ -10353,70 +10353,92 @@ impl<'a> Parser<'a> {
10353
10353
}
10354
10354
}
10355
10355
10356
- /// Parse a possibly qualified, possibly quoted identifier, optionally allowing for wildcards,
10356
+ /// Parse a possibly qualified, possibly quoted identifier, e.g.
10357
+ /// `foo` or `myschema."table"
10358
+ ///
10359
+ /// The `in_table_clause` parameter indicates whether the object name is a table in a FROM, JOIN,
10360
+ /// or similar table clause. Currently, this is used only to support unquoted hyphenated identifiers
10361
+ /// in this context on BigQuery.
10362
+ pub fn parse_object_name(&mut self, in_table_clause: bool) -> Result<ObjectName, ParserError> {
10363
+ self.parse_object_name_inner(in_table_clause, false)
10364
+ }
10365
+
10366
+ /// Parse a possibly qualified, possibly quoted identifier, e.g.
10367
+ /// `foo` or `myschema."table"
10368
+ ///
10369
+ /// The `in_table_clause` parameter indicates whether the object name is a table in a FROM, JOIN,
10370
+ /// or similar table clause. Currently, this is used only to support unquoted hyphenated identifiers
10371
+ /// in this context on BigQuery.
10372
+ ///
10373
+ /// The `allow_wildcards` parameter indicates whether to allow for wildcards in the object name
10357
10374
/// e.g. *, *.*, `foo`.*, or "foo"."bar"
10358
- fn parse_object_name_with_wildcards (
10375
+ fn parse_object_name_inner (
10359
10376
&mut self,
10360
10377
in_table_clause: bool,
10361
10378
allow_wildcards: bool,
10362
10379
) -> Result<ObjectName, ParserError> {
10363
- let mut idents = vec![];
10364
-
10380
+ let mut parts = vec![];
10365
10381
if dialect_of!(self is BigQueryDialect) && in_table_clause {
10366
10382
loop {
10367
10383
let (ident, end_with_period) = self.parse_unquoted_hyphenated_identifier()?;
10368
- idents .push(ident);
10384
+ parts .push(ObjectNamePart::Identifier( ident) );
10369
10385
if !self.consume_token(&Token::Period) && !end_with_period {
10370
10386
break;
10371
10387
}
10372
10388
}
10373
10389
} else {
10374
10390
loop {
10375
- let ident = if allow_wildcards && self.peek_token().token == Token::Mul {
10391
+ if allow_wildcards && self.peek_token().token == Token::Mul {
10376
10392
let span = self.next_token().span;
10377
- Ident {
10393
+ parts.push(ObjectNamePart::Identifier( Ident {
10378
10394
value: Token::Mul.to_string(),
10379
10395
quote_style: None,
10380
10396
span,
10397
+ }));
10398
+ } else if dialect_of!(self is BigQueryDialect) && in_table_clause {
10399
+ let (ident, end_with_period) = self.parse_unquoted_hyphenated_identifier()?;
10400
+ parts.push(ObjectNamePart::Identifier(ident));
10401
+ if !self.consume_token(&Token::Period) && !end_with_period {
10402
+ break;
10381
10403
}
10404
+ } else if self.dialect.supports_object_name_double_dot_notation()
10405
+ && parts.len() == 1
10406
+ && matches!(self.peek_token().token, Token::Period)
10407
+ {
10408
+ // Empty string here means default schema
10409
+ parts.push(ObjectNamePart::Identifier(Ident::new("")));
10382
10410
} else {
10383
- if self.dialect.supports_object_name_double_dot_notation()
10384
- && idents.len() == 1
10385
- && self.consume_token(&Token::Period)
10411
+ let ident = self.parse_identifier()?;
10412
+ let part = if self
10413
+ .dialect
10414
+ .is_identifier_generating_function_name(&ident, &parts)
10386
10415
{
10387
- // Empty string here means default schema
10388
- idents.push(Ident::new(""));
10389
- }
10390
- self.parse_identifier()?
10391
- };
10392
- idents.push(ident);
10416
+ self.expect_token(&Token::LParen)?;
10417
+ let args: Vec<FunctionArg> =
10418
+ self.parse_comma_separated0(Self::parse_function_args, Token::RParen)?;
10419
+ self.expect_token(&Token::RParen)?;
10420
+ ObjectNamePart::Function(ObjectNamePartFunction { name: ident, args })
10421
+ } else {
10422
+ ObjectNamePart::Identifier(ident)
10423
+ };
10424
+ parts.push(part);
10425
+ }
10426
+
10393
10427
if !self.consume_token(&Token::Period) {
10394
10428
break;
10395
10429
}
10396
10430
}
10397
10431
}
10398
- Ok(ObjectName::from(idents))
10399
- }
10400
-
10401
- /// Parse a possibly qualified, possibly quoted identifier, e.g.
10402
- /// `foo` or `myschema."table"
10403
- ///
10404
- /// The `in_table_clause` parameter indicates whether the object name is a table in a FROM, JOIN,
10405
- /// or similar table clause. Currently, this is used only to support unquoted hyphenated identifiers
10406
- /// in this context on BigQuery.
10407
- pub fn parse_object_name(&mut self, in_table_clause: bool) -> Result<ObjectName, ParserError> {
10408
- let ObjectName(mut idents) =
10409
- self.parse_object_name_with_wildcards(in_table_clause, false)?;
10410
10432
10411
10433
// BigQuery accepts any number of quoted identifiers of a table name.
10412
10434
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_identifiers
10413
10435
if dialect_of!(self is BigQueryDialect)
10414
- && idents .iter().any(|part| {
10436
+ && parts .iter().any(|part| {
10415
10437
part.as_ident()
10416
10438
.is_some_and(|ident| ident.value.contains('.'))
10417
10439
})
10418
10440
{
10419
- idents = idents
10441
+ parts = parts
10420
10442
.into_iter()
10421
10443
.flat_map(|part| match part.as_ident() {
10422
10444
Some(ident) => ident
@@ -10435,7 +10457,7 @@ impl<'a> Parser<'a> {
10435
10457
.collect()
10436
10458
}
10437
10459
10438
- Ok(ObjectName(idents ))
10460
+ Ok(ObjectName(parts ))
10439
10461
}
10440
10462
10441
10463
/// Parse identifiers
@@ -14006,25 +14028,25 @@ impl<'a> Parser<'a> {
14006
14028
schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
14007
14029
})
14008
14030
} else if self.parse_keywords(&[Keyword::RESOURCE, Keyword::MONITOR]) {
14009
- Some(GrantObjects::ResourceMonitors(self.parse_comma_separated(
14010
- |p| p.parse_object_name_with_wildcards (false, true) ,
14011
- )?) )
14031
+ Some(GrantObjects::ResourceMonitors(
14032
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14033
+ ))
14012
14034
} else if self.parse_keywords(&[Keyword::COMPUTE, Keyword::POOL]) {
14013
- Some(GrantObjects::ComputePools(self.parse_comma_separated(
14014
- |p| p.parse_object_name_with_wildcards (false, true) ,
14015
- )?) )
14035
+ Some(GrantObjects::ComputePools(
14036
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14037
+ ))
14016
14038
} else if self.parse_keywords(&[Keyword::FAILOVER, Keyword::GROUP]) {
14017
- Some(GrantObjects::FailoverGroup(self.parse_comma_separated(
14018
- |p| p.parse_object_name_with_wildcards (false, true) ,
14019
- )?) )
14039
+ Some(GrantObjects::FailoverGroup(
14040
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14041
+ ))
14020
14042
} else if self.parse_keywords(&[Keyword::REPLICATION, Keyword::GROUP]) {
14021
- Some(GrantObjects::ReplicationGroup(self.parse_comma_separated(
14022
- |p| p.parse_object_name_with_wildcards (false, true) ,
14023
- )?) )
14043
+ Some(GrantObjects::ReplicationGroup(
14044
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14045
+ ))
14024
14046
} else if self.parse_keywords(&[Keyword::EXTERNAL, Keyword::VOLUME]) {
14025
- Some(GrantObjects::ExternalVolumes(self.parse_comma_separated(
14026
- |p| p.parse_object_name_with_wildcards (false, true) ,
14027
- )?) )
14047
+ Some(GrantObjects::ExternalVolumes(
14048
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14049
+ ))
14028
14050
} else {
14029
14051
let object_type = self.parse_one_of_keywords(&[
14030
14052
Keyword::SEQUENCE,
@@ -14041,7 +14063,7 @@ impl<'a> Parser<'a> {
14041
14063
Keyword::CONNECTION,
14042
14064
]);
14043
14065
let objects =
14044
- self.parse_comma_separated(|p| p.parse_object_name_with_wildcards (false, true));
14066
+ self.parse_comma_separated(|p| p.parse_object_name_inner (false, true));
14045
14067
match object_type {
14046
14068
Some(Keyword::DATABASE) => Some(GrantObjects::Databases(objects?)),
14047
14069
Some(Keyword::SCHEMA) => Some(GrantObjects::Schemas(objects?)),
0 commit comments