mirror of
				https://github.com/apache/datafusion-sqlparser-rs.git
				synced 2025-10-31 15:17:41 +00:00 
			
		
		
		
	support create function definition with $$ (#755)
				
					
				
			* support create function definition using '2700775' * fix warn
This commit is contained in:
		
							parent
							
								
									d420001c37
								
							
						
					
					
						commit
						6c545195e1
					
				
					 5 changed files with 91 additions and 10 deletions
				
			
		|  | @ -3777,6 +3777,23 @@ impl fmt::Display for FunctionBehavior { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] | ||||
| #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||||
| pub enum FunctionDefinition { | ||||
|     SingleQuotedDef(String), | ||||
|     DoubleDollarDef(String), | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for FunctionDefinition { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         match self { | ||||
|             FunctionDefinition::SingleQuotedDef(s) => write!(f, "'{s}'")?, | ||||
|             FunctionDefinition::DoubleDollarDef(s) => write!(f, "$${s}$$")?, | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Postgres: https://www.postgresql.org/docs/15/sql-createfunction.html
 | ||||
| #[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] | ||||
| #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||||
|  | @ -3788,7 +3805,7 @@ pub struct CreateFunctionBody { | |||
|     /// AS 'definition'
 | ||||
|     ///
 | ||||
|     /// Note that Hive's `AS class_name` is also parsed here.
 | ||||
|     pub as_: Option<String>, | ||||
|     pub as_: Option<FunctionDefinition>, | ||||
|     /// RETURN expression
 | ||||
|     pub return_: Option<Expr>, | ||||
|     /// USING ... (Hive only)
 | ||||
|  | @ -3804,7 +3821,7 @@ impl fmt::Display for CreateFunctionBody { | |||
|             write!(f, " {behavior}")?; | ||||
|         } | ||||
|         if let Some(definition) = &self.as_ { | ||||
|             write!(f, " AS '{definition}'")?; | ||||
|             write!(f, " AS {definition}")?; | ||||
|         } | ||||
|         if let Some(expr) = &self.return_ { | ||||
|             write!(f, " RETURN {expr}")?; | ||||
|  |  | |||
|  | @ -2310,7 +2310,7 @@ impl<'a> Parser<'a> { | |||
|         if dialect_of!(self is HiveDialect) { | ||||
|             let name = self.parse_object_name()?; | ||||
|             self.expect_keyword(Keyword::AS)?; | ||||
|             let class_name = self.parse_literal_string()?; | ||||
|             let class_name = self.parse_function_definition()?; | ||||
|             let params = CreateFunctionBody { | ||||
|                 as_: Some(class_name), | ||||
|                 using: self.parse_optional_create_function_using()?, | ||||
|  | @ -2400,7 +2400,7 @@ impl<'a> Parser<'a> { | |||
|             } | ||||
|             if self.parse_keyword(Keyword::AS) { | ||||
|                 ensure_not_set(&body.as_, "AS")?; | ||||
|                 body.as_ = Some(self.parse_literal_string()?); | ||||
|                 body.as_ = Some(self.parse_function_definition()?); | ||||
|             } else if self.parse_keyword(Keyword::LANGUAGE) { | ||||
|                 ensure_not_set(&body.language, "LANGUAGE")?; | ||||
|                 body.language = Some(self.parse_identifier()?); | ||||
|  | @ -3883,6 +3883,33 @@ impl<'a> Parser<'a> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn parse_function_definition(&mut self) -> Result<FunctionDefinition, ParserError> { | ||||
|         let peek_token = self.peek_token(); | ||||
|         match peek_token.token { | ||||
|             Token::DoubleDollarQuoting if dialect_of!(self is PostgreSqlDialect) => { | ||||
|                 self.next_token(); | ||||
|                 let mut func_desc = String::new(); | ||||
|                 loop { | ||||
|                     if let Some(next_token) = self.next_token_no_skip() { | ||||
|                         match &next_token.token { | ||||
|                             Token::DoubleDollarQuoting => break, | ||||
|                             Token::EOF => { | ||||
|                                 return self.expected( | ||||
|                                     "literal string", | ||||
|                                     TokenWithLocation::wrap(Token::EOF), | ||||
|                                 ); | ||||
|                             } | ||||
|                             token => func_desc.push_str(token.to_string().as_str()), | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 Ok(FunctionDefinition::DoubleDollarDef(func_desc)) | ||||
|             } | ||||
|             _ => Ok(FunctionDefinition::SingleQuotedDef( | ||||
|                 self.parse_literal_string()?, | ||||
|             )), | ||||
|         } | ||||
|     } | ||||
|     /// Parse a literal string
 | ||||
|     pub fn parse_literal_string(&mut self) -> Result<String, ParserError> { | ||||
|         let next_token = self.next_token(); | ||||
|  |  | |||
|  | @ -145,6 +145,8 @@ pub enum Token { | |||
|     PGCubeRoot, | ||||
|     /// `?` or `$` , a prepared statement arg placeholder
 | ||||
|     Placeholder(String), | ||||
|     /// `$$`, used for PostgreSQL create function definition
 | ||||
|     DoubleDollarQuoting, | ||||
|     /// ->, used as a operator to extract json field in PostgreSQL
 | ||||
|     Arrow, | ||||
|     /// ->>, used as a operator to extract json field as text in PostgreSQL
 | ||||
|  | @ -215,6 +217,7 @@ impl fmt::Display for Token { | |||
|             Token::LongArrow => write!(f, "->>"), | ||||
|             Token::HashArrow => write!(f, "#>"), | ||||
|             Token::HashLongArrow => write!(f, "#>>"), | ||||
|             Token::DoubleDollarQuoting => write!(f, "$$"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -770,8 +773,14 @@ impl<'a> Tokenizer<'a> { | |||
|                 } | ||||
|                 '$' => { | ||||
|                     chars.next(); | ||||
|                     let s = peeking_take_while(chars, |ch| ch.is_alphanumeric() || ch == '_'); | ||||
|                     Ok(Some(Token::Placeholder(String::from("$") + &s))) | ||||
|                     match chars.peek() { | ||||
|                         Some('$') => self.consume_and_return(chars, Token::DoubleDollarQuoting), | ||||
|                         _ => { | ||||
|                             let s = | ||||
|                                 peeking_take_while(chars, |ch| ch.is_alphanumeric() || ch == '_'); | ||||
|                             Ok(Some(Token::Placeholder(String::from("$") + &s))) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 //whitespace check (including unicode chars) should be last as it covers some of the chars above
 | ||||
|                 ch if ch.is_whitespace() => { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 zidaye
						zidaye