@@ -10353,70 +10353,84 @@ 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 let Some(func_part) =
10399
+ self.maybe_parse(|parser| parser.parse_object_name_function_part())?
10400
+ {
10401
+ parts.push(ObjectNamePart::Function(func_part));
10402
+ } else if dialect_of!(self is BigQueryDialect) && in_table_clause {
10403
+ let (ident, end_with_period) = self.parse_unquoted_hyphenated_identifier()?;
10404
+ parts.push(ObjectNamePart::Identifier(ident));
10405
+ if !self.consume_token(&Token::Period) && !end_with_period {
10406
+ break;
10381
10407
}
10408
+ } else if self.dialect.supports_object_name_double_dot_notation()
10409
+ && parts.len() == 1
10410
+ && matches!(self.peek_token().token, Token::Period)
10411
+ {
10412
+ // Empty string here means default schema
10413
+ parts.push(ObjectNamePart::Identifier(Ident::new("")));
10382
10414
} else {
10383
- if self.dialect.supports_object_name_double_dot_notation()
10384
- && idents.len() == 1
10385
- && self.consume_token(&Token::Period)
10386
- {
10387
- // Empty string here means default schema
10388
- idents.push(Ident::new(""));
10389
- }
10390
- self.parse_identifier()?
10391
- };
10392
- idents.push(ident);
10415
+ let ident = self.parse_identifier()?;
10416
+ parts.push(ObjectNamePart::Identifier(ident));
10417
+ }
10418
+
10393
10419
if !self.consume_token(&Token::Period) {
10394
10420
break;
10395
10421
}
10396
10422
}
10397
10423
}
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
10424
10411
10425
// BigQuery accepts any number of quoted identifiers of a table name.
10412
10426
// https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_identifiers
10413
10427
if dialect_of!(self is BigQueryDialect)
10414
- && idents .iter().any(|part| {
10428
+ && parts .iter().any(|part| {
10415
10429
part.as_ident()
10416
10430
.is_some_and(|ident| ident.value.contains('.'))
10417
10431
})
10418
10432
{
10419
- idents = idents
10433
+ parts = parts
10420
10434
.into_iter()
10421
10435
.flat_map(|part| match part.as_ident() {
10422
10436
Some(ident) => ident
@@ -10435,7 +10449,23 @@ impl<'a> Parser<'a> {
10435
10449
.collect()
10436
10450
}
10437
10451
10438
- Ok(ObjectName(idents))
10452
+ Ok(ObjectName(parts))
10453
+ }
10454
+
10455
+ fn parse_object_name_function_part(&mut self) -> Result<ObjectNamePartFunction, ParserError> {
10456
+ let name = self.parse_identifier()?;
10457
+ if self.dialect.is_identifier_generating_function_name(&name) {
10458
+ self.expect_token(&Token::LParen)?;
10459
+ let args: Vec<FunctionArg> =
10460
+ self.parse_comma_separated0(Self::parse_function_args, Token::RParen)?;
10461
+ self.expect_token(&Token::RParen)?;
10462
+ Ok(ObjectNamePartFunction { name, args })
10463
+ } else {
10464
+ self.expected(
10465
+ "dialect specific identifier-generating function",
10466
+ self.peek_token(),
10467
+ )
10468
+ }
10439
10469
}
10440
10470
10441
10471
/// Parse identifiers
@@ -13938,25 +13968,25 @@ impl<'a> Parser<'a> {
13938
13968
schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
13939
13969
})
13940
13970
} else if self.parse_keywords(&[Keyword::RESOURCE, Keyword::MONITOR]) {
13941
- Some(GrantObjects::ResourceMonitors(self.parse_comma_separated(
13942
- |p| p.parse_object_name_with_wildcards (false, true) ,
13943
- )?) )
13971
+ Some(GrantObjects::ResourceMonitors(
13972
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
13973
+ ))
13944
13974
} else if self.parse_keywords(&[Keyword::COMPUTE, Keyword::POOL]) {
13945
- Some(GrantObjects::ComputePools(self.parse_comma_separated(
13946
- |p| p.parse_object_name_with_wildcards (false, true) ,
13947
- )?) )
13975
+ Some(GrantObjects::ComputePools(
13976
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
13977
+ ))
13948
13978
} else if self.parse_keywords(&[Keyword::FAILOVER, Keyword::GROUP]) {
13949
- Some(GrantObjects::FailoverGroup(self.parse_comma_separated(
13950
- |p| p.parse_object_name_with_wildcards (false, true) ,
13951
- )?) )
13979
+ Some(GrantObjects::FailoverGroup(
13980
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
13981
+ ))
13952
13982
} else if self.parse_keywords(&[Keyword::REPLICATION, Keyword::GROUP]) {
13953
- Some(GrantObjects::ReplicationGroup(self.parse_comma_separated(
13954
- |p| p.parse_object_name_with_wildcards (false, true) ,
13955
- )?) )
13983
+ Some(GrantObjects::ReplicationGroup(
13984
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
13985
+ ))
13956
13986
} else if self.parse_keywords(&[Keyword::EXTERNAL, Keyword::VOLUME]) {
13957
- Some(GrantObjects::ExternalVolumes(self.parse_comma_separated(
13958
- |p| p.parse_object_name_with_wildcards (false, true) ,
13959
- )?) )
13987
+ Some(GrantObjects::ExternalVolumes(
13988
+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
13989
+ ))
13960
13990
} else {
13961
13991
let object_type = self.parse_one_of_keywords(&[
13962
13992
Keyword::SEQUENCE,
@@ -13973,7 +14003,7 @@ impl<'a> Parser<'a> {
13973
14003
Keyword::CONNECTION,
13974
14004
]);
13975
14005
let objects =
13976
- self.parse_comma_separated(|p| p.parse_object_name_with_wildcards (false, true));
14006
+ self.parse_comma_separated(|p| p.parse_object_name_inner (false, true));
13977
14007
match object_type {
13978
14008
Some(Keyword::DATABASE) => Some(GrantObjects::Databases(objects?)),
13979
14009
Some(Keyword::SCHEMA) => Some(GrantObjects::Schemas(objects?)),
0 commit comments