@@ -10353,70 +10353,92 @@ 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 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;
1038110403 }
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("")));
1038210410 } 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)
1038610415 {
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+
1039310427 if !self.consume_token(&Token::Period) {
1039410428 break;
1039510429 }
1039610430 }
1039710431 }
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)?;
1041010432
1041110433 // BigQuery accepts any number of quoted identifiers of a table name.
1041210434 // https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_identifiers
1041310435 if dialect_of!(self is BigQueryDialect)
10414- && idents .iter().any(|part| {
10436+ && parts .iter().any(|part| {
1041510437 part.as_ident()
1041610438 .is_some_and(|ident| ident.value.contains('.'))
1041710439 })
1041810440 {
10419- idents = idents
10441+ parts = parts
1042010442 .into_iter()
1042110443 .flat_map(|part| match part.as_ident() {
1042210444 Some(ident) => ident
@@ -10435,7 +10457,7 @@ impl<'a> Parser<'a> {
1043510457 .collect()
1043610458 }
1043710459
10438- Ok(ObjectName(idents ))
10460+ Ok(ObjectName(parts ))
1043910461 }
1044010462
1044110463 /// Parse identifiers
@@ -14006,25 +14028,25 @@ impl<'a> Parser<'a> {
1400614028 schemas: self.parse_comma_separated(|p| p.parse_object_name(false))?,
1400714029 })
1400814030 } 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+ ))
1401214034 } 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+ ))
1401614038 } 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+ ))
1402014042 } 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+ ))
1402414046 } 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+ ))
1402814050 } else {
1402914051 let object_type = self.parse_one_of_keywords(&[
1403014052 Keyword::SEQUENCE,
@@ -14041,7 +14063,7 @@ impl<'a> Parser<'a> {
1404114063 Keyword::CONNECTION,
1404214064 ]);
1404314065 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));
1404514067 match object_type {
1404614068 Some(Keyword::DATABASE) => Some(GrantObjects::Databases(objects?)),
1404714069 Some(Keyword::SCHEMA) => Some(GrantObjects::Schemas(objects?)),
0 commit comments