Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support redshift's columns definition list for system information functions #769

Merged
29 changes: 29 additions & 0 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down
7 changes: 7 additions & 0 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
},
Expand Down Expand Up @@ -628,6 +631,7 @@ impl fmt::Display for TableFactor {
name,
alias,
args,
columns_definition,
with_hints,
} => {
write!(f, "{name}")?;
Expand All @@ -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))?;
}
Expand Down
2 changes: 2 additions & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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,
];
46 changes: 46 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![];
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![],
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/sqlparser_bigquery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fn parse_table_identifiers() {
name: ObjectName(expected),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![]
Expand Down
3 changes: 3 additions & 0 deletions tests/sqlparser_clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fn parse_map_access_expr() {
name: ObjectName(vec![Ident::new("foos")]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![]
Expand Down Expand Up @@ -164,11 +165,13 @@ fn parse_delimited_identifiers() {
name,
alias,
args,
columns_definition,
with_hints,
} => {
assert_eq!(vec![Ident::with_quote('"', "a table")], name.0);
assert_eq!(Ident::with_quote('"', "alias"), alias.unwrap().name);
assert!(args.is_none());
assert!(columns_definition.is_none());
assert!(with_hints.is_empty());
}
_ => panic!("Expecting TableFactor::Table"),
Expand Down
21 changes: 21 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ fn parse_update_set_from() {
name: ObjectName(vec![Ident::new("t1")]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![],
Expand All @@ -236,6 +237,7 @@ fn parse_update_set_from() {
name: ObjectName(vec![Ident::new("t1")]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![],
Expand Down Expand Up @@ -298,6 +300,7 @@ fn parse_update_with_table_alias() {
columns: vec![],
}),
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![],
Expand Down Expand Up @@ -353,6 +356,7 @@ fn parse_delete_statement() {
name: ObjectName(vec![Ident::with_quote('"', "table")]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
table_name
Expand All @@ -379,6 +383,7 @@ fn parse_where_delete_statement() {
name: ObjectName(vec![Ident::new("foo")]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
table_name,
Expand Down Expand Up @@ -419,6 +424,7 @@ fn parse_where_delete_with_alias_statement() {
columns: vec![],
}),
args: None,
columns_definition: None,
with_hints: vec![],
},
table_name,
Expand All @@ -432,6 +438,7 @@ fn parse_where_delete_with_alias_statement() {
columns: vec![],
}),
args: None,
columns_definition: None,
with_hints: vec![],
}),
using
Expand Down Expand Up @@ -3447,6 +3454,7 @@ fn parse_interval_and_or_xor() {
}]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![],
Expand Down Expand Up @@ -3893,6 +3901,7 @@ fn parse_implicit_join() {
name: ObjectName(vec!["t1".into()]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![],
Expand All @@ -3902,6 +3911,7 @@ fn parse_implicit_join() {
name: ObjectName(vec!["t2".into()]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![],
Expand All @@ -3919,13 +3929,15 @@ fn parse_implicit_join() {
name: ObjectName(vec!["t1a".into()]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![Join {
relation: TableFactor::Table {
name: ObjectName(vec!["t1b".into()]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
Expand All @@ -3936,13 +3948,15 @@ fn parse_implicit_join() {
name: ObjectName(vec!["t2a".into()]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![Join {
relation: TableFactor::Table {
name: ObjectName(vec!["t2b".into()]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
Expand All @@ -3963,6 +3977,7 @@ fn parse_cross_join() {
name: ObjectName(vec![Ident::new("t2")]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
join_operator: JoinOperator::CrossJoin,
Expand All @@ -3983,6 +3998,7 @@ fn parse_joins_on() {
name: ObjectName(vec![Ident::new(relation.into())]),
alias,
args: None,
columns_definition: None,
with_hints: vec![],
},
join_operator: f(JoinConstraint::On(Expr::BinaryOp {
Expand Down Expand Up @@ -4052,6 +4068,7 @@ fn parse_joins_using() {
name: ObjectName(vec![Ident::new(relation.into())]),
alias,
args: None,
columns_definition: None,
with_hints: vec![],
},
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),
Expand Down Expand Up @@ -4113,6 +4130,7 @@ fn parse_natural_join() {
name: ObjectName(vec![Ident::new("t2")]),
alias,
args: None,
columns_definition: None,
with_hints: vec![],
},
join_operator: f(JoinConstraint::Natural),
Expand Down Expand Up @@ -4377,6 +4395,7 @@ fn parse_derived_tables() {
name: ObjectName(vec!["t2".into()]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
join_operator: JoinOperator::Inner(JoinConstraint::Natural),
Expand Down Expand Up @@ -5668,6 +5687,7 @@ fn parse_merge() {
columns: vec![],
}),
args: None,
columns_definition: None,
with_hints: vec![],
}
);
Expand All @@ -5691,6 +5711,7 @@ fn parse_merge() {
name: ObjectName(vec![Ident::new("s"), Ident::new("foo")]),
alias: None,
args: None,
columns_definition: None,
with_hints: vec![],
},
joins: vec![],
Expand Down
2 changes: 2 additions & 0 deletions tests/sqlparser_hive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,13 @@ fn parse_delimited_identifiers() {
name,
alias,
args,
columns_definition,
with_hints,
} => {
assert_eq!(vec![Ident::with_quote('"', "a table")], name.0);
assert_eq!(Ident::with_quote('"', "alias"), alias.unwrap().name);
assert!(args.is_none());
assert!(columns_definition.is_none());
assert!(with_hints.is_empty());
}
_ => panic!("Expecting TableFactor::Table"),
Expand Down
2 changes: 2 additions & 0 deletions tests/sqlparser_mssql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,13 @@ fn parse_delimited_identifiers() {
name,
alias,
args,
columns_definition,
with_hints,
} => {
assert_eq!(vec![Ident::with_quote('"', "a table")], name.0);
assert_eq!(Ident::with_quote('"', "alias"), alias.unwrap().name);
assert!(args.is_none());
assert!(columns_definition.is_none());
assert!(with_hints.is_empty());
}
_ => panic!("Expecting TableFactor::Table"),
Expand Down
Loading