@@ -10353,70 +10353,84 @@ impl<'a> Parser<'a> {
1035310353 }
1035410354 }
1035510355
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
1035710374 /// e.g. *, *.*, `foo`.*, or "foo"."bar"
10358- fn parse_object_name_with_wildcards (
10375+ fn parse_object_name_inner (
1035910376 &mut self,
1036010377 in_table_clause: bool,
1036110378 allow_wildcards: bool,
1036210379 ) -> Result<ObjectName, ParserError> {
10363- let mut idents = vec![];
10364-
10380+ let mut parts = vec![];
1036510381 if dialect_of!(self is BigQueryDialect) && in_table_clause {
1036610382 loop {
1036710383 let (ident, end_with_period) = self.parse_unquoted_hyphenated_identifier()?;
10368- idents .push(ident);
10384+ parts .push(ObjectNamePart::Identifier( ident) );
1036910385 if !self.consume_token(&Token::Period) && !end_with_period {
1037010386 break;
1037110387 }
1037210388 }
1037310389 } else {
1037410390 loop {
10375- let ident = if allow_wildcards && self.peek_token().token == Token::Mul {
10391+ if allow_wildcards && self.peek_token().token == Token::Mul {
1037610392 let span = self.next_token().span;
10377- Ident {
10393+ parts.push(ObjectNamePart::Identifier( Ident {
1037810394 value: Token::Mul.to_string(),
1037910395 quote_style: None,
1038010396 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;
1038110407 }
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("")));
1038210414 } 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+
1039310419 if !self.consume_token(&Token::Period) {
1039410420 break;
1039510421 }
1039610422 }
1039710423 }
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)?;
1041010424
1041110425 // BigQuery accepts any number of quoted identifiers of a table name.
1041210426 // https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_identifiers
1041310427 if dialect_of!(self is BigQueryDialect)
10414- && idents .iter().any(|part| {
10428+ && parts .iter().any(|part| {
1041510429 part.as_ident()
1041610430 .is_some_and(|ident| ident.value.contains('.'))
1041710431 })
1041810432 {
10419- idents = idents
10433+ parts = parts
1042010434 .into_iter()
1042110435 .flat_map(|part| match part.as_ident() {
1042210436 Some(ident) => ident
@@ -10435,7 +10449,23 @@ impl<'a> Parser<'a> {
1043510449 .collect()
1043610450 }
1043710451
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+ }
1043910469 }
1044010470
1044110471 /// Parse identifiers
@@ -13938,25 +13968,25 @@ impl<'a> Parser<'a> {
1393813968 schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
1393913969 })
1394013970 } 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+ ))
1394413974 } 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+ ))
1394813978 } 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+ ))
1395213982 } 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+ ))
1395613986 } 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+ ))
1396013990 } else {
1396113991 let object_type = self.parse_one_of_keywords(&[
1396213992 Keyword::SEQUENCE,
@@ -13973,7 +14003,7 @@ impl<'a> Parser<'a> {
1397314003 Keyword::CONNECTION,
1397414004 ]);
1397514005 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));
1397714007 match object_type {
1397814008 Some(Keyword::DATABASE) => Some(GrantObjects::Databases(objects?)),
1397914009 Some(Keyword::SCHEMA) => Some(GrantObjects::Schemas(objects?)),
0 commit comments