mirror of
				https://github.com/apache/datafusion-sqlparser-rs.git
				synced 2025-10-31 15:17:41 +00:00 
			
		
		
		
	Support redshift's columns definition list for system information functions (#769)
* parsing of redshift's column definition list for pg_get_late_binding_view_cols pg_get_cols pg_get_grantee_by_iam_role pg_get_iam_role_by_user * Renamed ColsDefinition to TableAliasDefinition added generic dialect * Tests fixed * Visitor for IdentPair * Parsing redshift table alias based on indentifier and parentheses instead of function name * fix clippy --------- Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com> Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
		
							parent
							
								
									a2fea10f89
								
							
						
					
					
						commit
						c35dcc93a7
					
				
					 14 changed files with 194 additions and 0 deletions
				
			
		|  | @ -4141,6 +4141,35 @@ impl fmt::Display for SearchModifier { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /// A result table definition i.e. `cols(view_schema name, view_name name, col_name name, col_type varchar, col_num int)`
 | ||||
| /// used for redshift functions: pg_get_late_binding_view_cols, pg_get_cols, pg_get_grantee_by_iam_role,pg_get_iam_role_by_user
 | ||||
| #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] | ||||
| #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||||
| #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] | ||||
| pub struct TableAliasDefinition { | ||||
|     pub name: Ident, | ||||
|     pub args: Vec<IdentPair>, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for TableAliasDefinition { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(f, "{}({})", self.name, display_comma_separated(&self.args))?; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] | ||||
| #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||||
| #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] | ||||
| pub struct IdentPair(pub Ident, pub Ident); | ||||
| 
 | ||||
| impl fmt::Display for IdentPair { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(f, "{} {}", self.0, self.1)?; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|  |  | |||
|  | @ -580,6 +580,9 @@ pub enum TableFactor { | |||
|         /// vector of arguments, in the case of a table-valued function call,
 | ||||
|         /// whereas it's `None` in the case of a regular table name.
 | ||||
|         args: Option<Vec<FunctionArg>>, | ||||
|         /// A table alias definition i.e. `cols(view_schema name, view_name name, col_name name, col_type varchar, col_num int)`
 | ||||
|         /// used for redshift functions: pg_get_late_binding_view_cols, pg_get_cols, pg_get_grantee_by_iam_role,pg_get_iam_role_by_user)
 | ||||
|         columns_definition: Option<TableAliasDefinition>, | ||||
|         /// MSSQL-specific `WITH (...)` hints such as NOLOCK.
 | ||||
|         with_hints: Vec<Expr>, | ||||
|     }, | ||||
|  | @ -628,6 +631,7 @@ impl fmt::Display for TableFactor { | |||
|                 name, | ||||
|                 alias, | ||||
|                 args, | ||||
|                 columns_definition, | ||||
|                 with_hints, | ||||
|             } => { | ||||
|                 write!(f, "{name}")?; | ||||
|  | @ -637,6 +641,9 @@ impl fmt::Display for TableFactor { | |||
|                 if let Some(alias) = alias { | ||||
|                     write!(f, " AS {alias}")?; | ||||
|                 } | ||||
|                 if let Some(columns_definition) = columns_definition { | ||||
|                     write!(f, " {columns_definition}")?; | ||||
|                 } | ||||
|                 if !with_hints.is_empty() { | ||||
|                     write!(f, " WITH ({})", display_comma_separated(with_hints))?; | ||||
|                 } | ||||
|  |  | |||
|  | @ -669,6 +669,7 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[ | |||
|     Keyword::OUTER, | ||||
|     Keyword::SET, | ||||
|     Keyword::QUALIFY, | ||||
|     Keyword::AS, | ||||
| ]; | ||||
| 
 | ||||
| /// Can't be used as a column alias, so that `SELECT <expr> alias`
 | ||||
|  | @ -698,4 +699,5 @@ pub const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[ | |||
|     // Reserved only as a column alias in the `SELECT` clause
 | ||||
|     Keyword::FROM, | ||||
|     Keyword::INTO, | ||||
|     Keyword::AS, | ||||
| ]; | ||||
|  |  | |||
|  | @ -5649,6 +5649,7 @@ impl<'a> Parser<'a> { | |||
|             } else { | ||||
|                 None | ||||
|             }; | ||||
|             let columns_definition = self.parse_redshift_columns_definition_list()?; | ||||
|             let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?; | ||||
|             // MSSQL-specific table hints:
 | ||||
|             let mut with_hints = vec![]; | ||||
|  | @ -5665,11 +5666,56 @@ impl<'a> Parser<'a> { | |||
|                 name, | ||||
|                 alias, | ||||
|                 args, | ||||
|                 columns_definition, | ||||
|                 with_hints, | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn parse_redshift_columns_definition_list( | ||||
|         &mut self, | ||||
|     ) -> Result<Option<TableAliasDefinition>, ParserError> { | ||||
|         if !dialect_of!(self is RedshiftSqlDialect | GenericDialect) { | ||||
|             return Ok(None); | ||||
|         } | ||||
| 
 | ||||
|         if let Some(col_definition_list_name) = self.parse_optional_columns_definition_list_alias() | ||||
|         { | ||||
|             if self.consume_token(&Token::LParen) { | ||||
|                 let names = self.parse_comma_separated(Parser::parse_ident_pair)?; | ||||
|                 self.expect_token(&Token::RParen)?; | ||||
|                 Ok(Some(TableAliasDefinition { | ||||
|                     name: col_definition_list_name, | ||||
|                     args: names, | ||||
|                 })) | ||||
|             } else { | ||||
|                 self.prev_token(); | ||||
|                 Ok(None) | ||||
|             } | ||||
|         } else { | ||||
|             Ok(None) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn parse_optional_columns_definition_list_alias(&mut self) -> Option<Ident> { | ||||
|         match self.next_token().token { | ||||
|             Token::Word(w) if !keywords::RESERVED_FOR_TABLE_ALIAS.contains(&w.keyword) => { | ||||
|                 Some(w.to_ident()) | ||||
|             } | ||||
|             _ => { | ||||
|                 self.prev_token(); | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn parse_ident_pair(&mut self) -> Result<IdentPair, ParserError> { | ||||
|         Ok(IdentPair( | ||||
|             self.parse_identifier()?, | ||||
|             self.parse_identifier()?, | ||||
|         )) | ||||
|     } | ||||
| 
 | ||||
|     pub fn parse_derived_table_factor( | ||||
|         &mut self, | ||||
|         lateral: IsLateral, | ||||
|  |  | |||
|  | @ -185,6 +185,7 @@ pub fn table(name: impl Into<String>) -> TableFactor { | |||
|         name: ObjectName(vec![Ident::new(name.into())]), | ||||
|         alias: None, | ||||
|         args: None, | ||||
|         columns_definition: None, | ||||
|         with_hints: vec![], | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Maciej Skrzypkowski
						Maciej Skrzypkowski