@@ -10384,70 +10384,92 @@ impl<'a> Parser<'a> {
1038410384 }
1038510385 }
1038610386
10387- /// Parse a possibly qualified, possibly quoted identifier, optionally allowing for wildcards,
10387+ /// Parse a possibly qualified, possibly quoted identifier, e.g.
10388+ /// `foo` or `myschema."table"
10389+ ///
10390+ /// The `in_table_clause` parameter indicates whether the object name is a table in a FROM, JOIN,
10391+ /// or similar table clause. Currently, this is used only to support unquoted hyphenated identifiers
10392+ /// in this context on BigQuery.
10393+ pub fn parse_object_name(&mut self, in_table_clause: bool) -> Result<ObjectName, ParserError> {
10394+ self.parse_object_name_inner(in_table_clause, false)
10395+ }
10396+
10397+ /// Parse a possibly qualified, possibly quoted identifier, e.g.
10398+ /// `foo` or `myschema."table"
10399+ ///
10400+ /// The `in_table_clause` parameter indicates whether the object name is a table in a FROM, JOIN,
10401+ /// or similar table clause. Currently, this is used only to support unquoted hyphenated identifiers
10402+ /// in this context on BigQuery.
10403+ ///
10404+ /// The `allow_wildcards` parameter indicates whether to allow for wildcards in the object name
1038810405 /// e.g. *, *.*, `foo`.*, or "foo"."bar"
10389- fn parse_object_name_with_wildcards (
10406+ fn parse_object_name_inner (
1039010407 &mut self,
1039110408 in_table_clause: bool,
1039210409 allow_wildcards: bool,
1039310410 ) -> Result<ObjectName, ParserError> {
10394- let mut idents = vec![];
10395-
10411+ let mut parts = vec![];
1039610412 if dialect_of!(self is BigQueryDialect) && in_table_clause {
1039710413 loop {
1039810414 let (ident, end_with_period) = self.parse_unquoted_hyphenated_identifier()?;
10399- idents .push(ident);
10415+ parts .push(ObjectNamePart::Identifier( ident) );
1040010416 if !self.consume_token(&Token::Period) && !end_with_period {
1040110417 break;
1040210418 }
1040310419 }
1040410420 } else {
1040510421 loop {
10406- let ident = if allow_wildcards && self.peek_token().token == Token::Mul {
10422+ if allow_wildcards && self.peek_token().token == Token::Mul {
1040710423 let span = self.next_token().span;
10408- Ident {
10424+ parts.push(ObjectNamePart::Identifier( Ident {
1040910425 value: Token::Mul.to_string(),
1041010426 quote_style: None,
1041110427 span,
10428+ }));
10429+ } else if dialect_of!(self is BigQueryDialect) && in_table_clause {
10430+ let (ident, end_with_period) = self.parse_unquoted_hyphenated_identifier()?;
10431+ parts.push(ObjectNamePart::Identifier(ident));
10432+ if !self.consume_token(&Token::Period) && !end_with_period {
10433+ break;
1041210434 }
10435+ } else if self.dialect.supports_object_name_double_dot_notation()
10436+ && parts.len() == 1
10437+ && matches!(self.peek_token().token, Token::Period)
10438+ {
10439+ // Empty string here means default schema
10440+ parts.push(ObjectNamePart::Identifier(Ident::new("")));
1041310441 } else {
10414- if self.dialect.supports_object_name_double_dot_notation()
10415- && idents.len() == 1
10416- && self.consume_token(&Token::Period)
10442+ let ident = self.parse_identifier()?;
10443+ let part = if self
10444+ .dialect
10445+ .is_identifier_generating_function_name(&ident, &parts)
1041710446 {
10418- // Empty string here means default schema
10419- idents.push(Ident::new(""));
10420- }
10421- self.parse_identifier()?
10422- };
10423- idents.push(ident);
10447+ self.expect_token(&Token::LParen)?;
10448+ let args: Vec<FunctionArg> =
10449+ self.parse_comma_separated0(Self::parse_function_args, Token::RParen)?;
10450+ self.expect_token(&Token::RParen)?;
10451+ ObjectNamePart::Function(ObjectNamePartFunction { name: ident, args })
10452+ } else {
10453+ ObjectNamePart::Identifier(ident)
10454+ };
10455+ parts.push(part);
10456+ }
10457+
1042410458 if !self.consume_token(&Token::Period) {
1042510459 break;
1042610460 }
1042710461 }
1042810462 }
10429- Ok(ObjectName::from(idents))
10430- }
10431-
10432- /// Parse a possibly qualified, possibly quoted identifier, e.g.
10433- /// `foo` or `myschema."table"
10434- ///
10435- /// The `in_table_clause` parameter indicates whether the object name is a table in a FROM, JOIN,
10436- /// or similar table clause. Currently, this is used only to support unquoted hyphenated identifiers
10437- /// in this context on BigQuery.
10438- pub fn parse_object_name(&mut self, in_table_clause: bool) -> Result<ObjectName, ParserError> {
10439- let ObjectName(mut idents) =
10440- self.parse_object_name_with_wildcards(in_table_clause, false)?;
1044110463
1044210464 // BigQuery accepts any number of quoted identifiers of a table name.
1044310465 // https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_identifiers
1044410466 if dialect_of!(self is BigQueryDialect)
10445- && idents .iter().any(|part| {
10467+ && parts .iter().any(|part| {
1044610468 part.as_ident()
1044710469 .is_some_and(|ident| ident.value.contains('.'))
1044810470 })
1044910471 {
10450- idents = idents
10472+ parts = parts
1045110473 .into_iter()
1045210474 .flat_map(|part| match part.as_ident() {
1045310475 Some(ident) => ident
@@ -10466,7 +10488,7 @@ impl<'a> Parser<'a> {
1046610488 .collect()
1046710489 }
1046810490
10469- Ok(ObjectName(idents ))
10491+ Ok(ObjectName(parts ))
1047010492 }
1047110493
1047210494 /// Parse identifiers
@@ -14038,25 +14060,25 @@ impl<'a> Parser<'a> {
1403814060 schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
1403914061 })
1404014062 } else if self.parse_keywords(&[Keyword::RESOURCE, Keyword::MONITOR]) {
14041- Some(GrantObjects::ResourceMonitors(self.parse_comma_separated(
14042- |p| p.parse_object_name_with_wildcards (false, true) ,
14043- )?) )
14063+ Some(GrantObjects::ResourceMonitors(
14064+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14065+ ))
1404414066 } else if self.parse_keywords(&[Keyword::COMPUTE, Keyword::POOL]) {
14045- Some(GrantObjects::ComputePools(self.parse_comma_separated(
14046- |p| p.parse_object_name_with_wildcards (false, true) ,
14047- )?) )
14067+ Some(GrantObjects::ComputePools(
14068+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14069+ ))
1404814070 } else if self.parse_keywords(&[Keyword::FAILOVER, Keyword::GROUP]) {
14049- Some(GrantObjects::FailoverGroup(self.parse_comma_separated(
14050- |p| p.parse_object_name_with_wildcards (false, true) ,
14051- )?) )
14071+ Some(GrantObjects::FailoverGroup(
14072+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14073+ ))
1405214074 } else if self.parse_keywords(&[Keyword::REPLICATION, Keyword::GROUP]) {
14053- Some(GrantObjects::ReplicationGroup(self.parse_comma_separated(
14054- |p| p.parse_object_name_with_wildcards (false, true) ,
14055- )?) )
14075+ Some(GrantObjects::ReplicationGroup(
14076+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14077+ ))
1405614078 } else if self.parse_keywords(&[Keyword::EXTERNAL, Keyword::VOLUME]) {
14057- Some(GrantObjects::ExternalVolumes(self.parse_comma_separated(
14058- |p| p.parse_object_name_with_wildcards (false, true) ,
14059- )?) )
14079+ Some(GrantObjects::ExternalVolumes(
14080+ self.parse_comma_separated( |p| p.parse_object_name (false))? ,
14081+ ))
1406014082 } else {
1406114083 let object_type = self.parse_one_of_keywords(&[
1406214084 Keyword::SEQUENCE,
@@ -14073,7 +14095,7 @@ impl<'a> Parser<'a> {
1407314095 Keyword::CONNECTION,
1407414096 ]);
1407514097 let objects =
14076- self.parse_comma_separated(|p| p.parse_object_name_with_wildcards (false, true));
14098+ self.parse_comma_separated(|p| p.parse_object_name_inner (false, true));
1407714099 match object_type {
1407814100 Some(Keyword::DATABASE) => Some(GrantObjects::Databases(objects?)),
1407914101 Some(Keyword::SCHEMA) => Some(GrantObjects::Schemas(objects?)),
0 commit comments