LucaCappelletti94 commented on code in PR #2096:
URL:
https://github.com/apache/datafusion-sqlparser-rs/pull/2096#discussion_r2524774445
##########
src/parser/mod.rs:
##########
@@ -6422,6 +6431,291 @@ impl<'a> Parser<'a> {
}))
}
+ /// Helper function to parse an operator name (which can contain special
characters)
+ /// Operator names can be schema-qualified (e.g., schema.operator)
+ fn parse_operator_name(&mut self) -> Result<ObjectName, ParserError> {
+ let mut name_parts = vec![];
+ loop {
+ let token = self.next_token();
+ let part =
ObjectNamePart::Identifier(Ident::new(token.to_string()));
+ name_parts.push(part);
+
+ if !self.consume_token(&Token::Period) {
+ break;
+ }
+ }
+ Ok(ObjectName(name_parts))
+ }
+
+ /// Parse a CREATE OPERATOR statement
+ ///
+ /// [PostgreSQL
Documentation](https://www.postgresql.org/docs/current/sql-createoperator.html)
+ pub fn parse_create_operator(&mut self) -> Result<Statement, ParserError> {
+ // Parse the operator name (can be schema-qualified)
+ // Operators can contain special characters like +, -, *, /, <, >, =,
~, !, @, #, %, ^, &, |, `, ?
+ // See https://www.postgresql.org/docs/current/sql-createoperator.html
+ let name = self.parse_operator_name()?;
+
+ // Expect opening parenthesis
+ self.expect_token(&Token::LParen)?;
+
+ let mut function: Option<ObjectName> = None;
+ let mut is_procedure = false;
+ let mut left_arg: Option<DataType> = None;
+ let mut right_arg: Option<DataType> = None;
+ let mut commutator: Option<ObjectName> = None;
+ let mut negator: Option<ObjectName> = None;
+ let mut restrict: Option<ObjectName> = None;
+ let mut join: Option<ObjectName> = None;
+ let mut hashes = false;
+ let mut merges = false;
+
+ loop {
+ // Parse parameter name as keyword
+ let keyword = self.expect_one_of_keywords(&[
+ Keyword::FUNCTION,
+ Keyword::PROCEDURE,
+ Keyword::LEFTARG,
+ Keyword::RIGHTARG,
+ Keyword::COMMUTATOR,
+ Keyword::NEGATOR,
+ Keyword::RESTRICT,
+ Keyword::JOIN,
+ Keyword::HASHES,
+ Keyword::MERGES,
+ ])?;
+
+ // Check if this is a flag (HASHES or MERGES) - no '=' expected
+ match keyword {
+ Keyword::HASHES => {
+ hashes = true;
+ }
+ Keyword::MERGES => {
+ merges = true;
+ }
+ Keyword::FUNCTION | Keyword::PROCEDURE => {
+ self.expect_token(&Token::Eq)?;
+ let func_name = self.parse_object_name(false)?;
+ function = Some(func_name);
+ is_procedure = keyword == Keyword::PROCEDURE;
+ }
+ Keyword::LEFTARG => {
+ self.expect_token(&Token::Eq)?;
+ let data_type = self.parse_data_type()?;
+ left_arg = Some(data_type);
+ }
+ Keyword::RIGHTARG => {
+ self.expect_token(&Token::Eq)?;
+ let data_type = self.parse_data_type()?;
+ right_arg = Some(data_type);
+ }
+ Keyword::COMMUTATOR => {
+ self.expect_token(&Token::Eq)?;
+ let op_name = if self.parse_keyword(Keyword::OPERATOR) {
+ self.expect_token(&Token::LParen)?;
+ let op = self.parse_operator_name()?;
+ self.expect_token(&Token::RParen)?;
+ op
+ } else {
+ self.parse_operator_name()?
+ };
+ commutator = Some(op_name);
+ }
+ Keyword::NEGATOR => {
+ self.expect_token(&Token::Eq)?;
+ let op_name = if self.parse_keyword(Keyword::OPERATOR) {
+ self.expect_token(&Token::LParen)?;
+ let op = self.parse_operator_name()?;
+ self.expect_token(&Token::RParen)?;
+ op
+ } else {
+ self.parse_operator_name()?
+ };
+ negator = Some(op_name);
+ }
+ Keyword::RESTRICT => {
+ self.expect_token(&Token::Eq)?;
+ let func_name = self.parse_object_name(false)?;
+ restrict = Some(func_name);
+ }
+ Keyword::JOIN => {
+ self.expect_token(&Token::Eq)?;
+ let func_name = self.parse_object_name(false)?;
+ join = Some(func_name);
+ }
+ _ => unreachable!("unexpected keyword in CREATE OPERATOR"),
+ }
+
+ // Check for comma or closing parenthesis
+ if !self.consume_token(&Token::Comma) {
+ break;
+ }
+ }
+
+ // Expect closing parenthesis
+ self.expect_token(&Token::RParen)?;
+
+ // FUNCTION is required
+ let function = function.ok_or_else(|| {
+ ParserError::ParserError("CREATE OPERATOR requires FUNCTION
parameter".to_string())
+ })?;
+
+ Ok(Statement::CreateOperator(CreateOperator {
+ name,
+ function,
+ is_procedure,
+ left_arg,
+ right_arg,
+ commutator,
+ negator,
+ restrict,
+ join,
+ hashes,
+ merges,
+ }))
+ }
+
+ /// Parse a CREATE OPERATOR FAMILY statement
+ ///
+ /// [PostgreSQL
Documentation](https://www.postgresql.org/docs/current/sql-createopfamily.html)
+ pub fn parse_create_operator_family(&mut self) -> Result<Statement,
ParserError> {
+ let name = self.parse_object_name(false)?;
+ self.expect_keyword(Keyword::USING)?;
+ let using = self.parse_identifier()?;
+
+ Ok(Statement::CreateOperatorFamily(CreateOperatorFamily {
+ name,
+ using,
+ }))
+ }
+
+ /// Parse a CREATE OPERATOR CLASS statement
+ ///
+ /// [PostgreSQL
Documentation](https://www.postgresql.org/docs/current/sql-createopclass.html)
+ pub fn parse_create_operator_class(&mut self) -> Result<Statement,
ParserError> {
+ let name = self.parse_object_name(false)?;
+ let default = self.parse_keyword(Keyword::DEFAULT);
+ self.expect_keywords(&[Keyword::FOR, Keyword::TYPE])?;
+ let for_type = self.parse_data_type()?;
+ self.expect_keyword(Keyword::USING)?;
+ let using = self.parse_identifier()?;
+
+ let family = if self.parse_keyword(Keyword::FAMILY) {
+ Some(self.parse_object_name(false)?)
+ } else {
+ None
+ };
+
+ self.expect_keyword(Keyword::AS)?;
+
+ let mut items = vec![];
+ loop {
+ if self.parse_keyword(Keyword::OPERATOR) {
+ let strategy_number = self.parse_literal_uint()? as u32;
+ let operator_name = self.parse_operator_name()?;
+
+ // Optional operator argument types
+ let op_types = if self.consume_token(&Token::LParen) {
+ let left = self.parse_data_type()?;
+ self.expect_token(&Token::Comma)?;
+ let right = self.parse_data_type()?;
+ self.expect_token(&Token::RParen)?;
+ Some(OperatorArgTypes { left, right })
Review Comment:
Made sure we do cover this case.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]