mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-26 15:39:12 +00:00
Accept WINDOW clause after QUALIFY when parsing (#1248)
Co-authored-by: ifeanyi <ifeanyi@validio.io>
This commit is contained in:
parent
71a7262e38
commit
8e64b73e9d
8 changed files with 86 additions and 14 deletions
|
@ -245,6 +245,11 @@ pub struct Select {
|
|||
pub named_window: Vec<NamedWindowDefinition>,
|
||||
/// QUALIFY (Snowflake)
|
||||
pub qualify: Option<Expr>,
|
||||
/// The positioning of QUALIFY and WINDOW clauses differ between dialects.
|
||||
/// e.g. BigQuery requires that WINDOW comes after QUALIFY, while DUCKDB accepts
|
||||
/// WINDOW before QUALIFY.
|
||||
/// We accept either positioning and flag the accepted variant.
|
||||
pub window_before_qualify: bool,
|
||||
/// BigQuery syntax: `SELECT AS VALUE | SELECT AS STRUCT`
|
||||
pub value_table_mode: Option<ValueTableMode>,
|
||||
/// STARTING WITH .. CONNECT BY
|
||||
|
@ -310,12 +315,21 @@ impl fmt::Display for Select {
|
|||
if let Some(ref having) = self.having {
|
||||
write!(f, " HAVING {having}")?;
|
||||
}
|
||||
if self.window_before_qualify {
|
||||
if !self.named_window.is_empty() {
|
||||
write!(f, " WINDOW {}", display_comma_separated(&self.named_window))?;
|
||||
}
|
||||
if let Some(ref qualify) = self.qualify {
|
||||
write!(f, " QUALIFY {qualify}")?;
|
||||
}
|
||||
} else {
|
||||
if let Some(ref qualify) = self.qualify {
|
||||
write!(f, " QUALIFY {qualify}")?;
|
||||
}
|
||||
if !self.named_window.is_empty() {
|
||||
write!(f, " WINDOW {}", display_comma_separated(&self.named_window))?;
|
||||
}
|
||||
}
|
||||
if let Some(ref connect_by) = self.connect_by {
|
||||
write!(f, " {connect_by}")?;
|
||||
}
|
||||
|
|
|
@ -7854,16 +7854,28 @@ impl<'a> Parser<'a> {
|
|||
None
|
||||
};
|
||||
|
||||
let named_windows = if self.parse_keyword(Keyword::WINDOW) {
|
||||
self.parse_comma_separated(Parser::parse_named_window)?
|
||||
// Accept QUALIFY and WINDOW in any order and flag accordingly.
|
||||
let (named_windows, qualify, window_before_qualify) = if self.parse_keyword(Keyword::WINDOW)
|
||||
{
|
||||
let named_windows = self.parse_comma_separated(Parser::parse_named_window)?;
|
||||
if self.parse_keyword(Keyword::QUALIFY) {
|
||||
(named_windows, Some(self.parse_expr()?), true)
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let qualify = if self.parse_keyword(Keyword::QUALIFY) {
|
||||
Some(self.parse_expr()?)
|
||||
(named_windows, None, true)
|
||||
}
|
||||
} else if self.parse_keyword(Keyword::QUALIFY) {
|
||||
let qualify = Some(self.parse_expr()?);
|
||||
if self.parse_keyword(Keyword::WINDOW) {
|
||||
(
|
||||
self.parse_comma_separated(Parser::parse_named_window)?,
|
||||
qualify,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
(Default::default(), qualify, false)
|
||||
}
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let connect_by = if self.dialect.supports_connect_by()
|
||||
|
@ -7891,6 +7903,7 @@ impl<'a> Parser<'a> {
|
|||
sort_by,
|
||||
having,
|
||||
named_window: named_windows,
|
||||
window_before_qualify,
|
||||
qualify,
|
||||
value_table_mode,
|
||||
connect_by,
|
||||
|
|
|
@ -114,6 +114,7 @@ fn parse_map_access_expr() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
|
|
|
@ -401,6 +401,7 @@ fn parse_update_set_from() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
@ -4546,12 +4547,34 @@ fn test_parse_named_window() {
|
|||
),
|
||||
],
|
||||
qualify: None,
|
||||
window_before_qualify: true,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
};
|
||||
assert_eq!(actual_select_only, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_window_and_qualify_clause() {
|
||||
let sql = "SELECT \
|
||||
MIN(c12) OVER window1 AS min1 \
|
||||
FROM aggregate_test_100 \
|
||||
QUALIFY ROW_NUMBER() OVER my_window \
|
||||
WINDOW window1 AS (ORDER BY C12), \
|
||||
window2 AS (PARTITION BY C11) \
|
||||
ORDER BY C3";
|
||||
verified_only_select(sql);
|
||||
|
||||
let sql = "SELECT \
|
||||
MIN(c12) OVER window1 AS min1 \
|
||||
FROM aggregate_test_100 \
|
||||
WINDOW window1 AS (ORDER BY C12), \
|
||||
window2 AS (PARTITION BY C11) \
|
||||
QUALIFY ROW_NUMBER() OVER my_window \
|
||||
ORDER BY C3";
|
||||
verified_only_select(sql);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_window_clause_named_window() {
|
||||
let sql = "SELECT * FROM mytable WINDOW window1 AS window2";
|
||||
|
@ -4918,6 +4941,7 @@ fn parse_interval_and_or_xor() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
@ -6872,6 +6896,7 @@ fn lateral_function() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
};
|
||||
|
@ -7516,6 +7541,7 @@ fn parse_merge() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
|
@ -8958,6 +8984,7 @@ fn parse_unload() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
|
@ -9112,6 +9139,7 @@ fn parse_connect_by() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: Some(ConnectBy {
|
||||
condition: Expr::BinaryOp {
|
||||
|
@ -9199,6 +9227,7 @@ fn parse_connect_by() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: Some(ConnectBy {
|
||||
condition: Expr::BinaryOp {
|
||||
|
|
|
@ -177,6 +177,7 @@ fn test_select_union_by_name() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
|
@ -214,6 +215,7 @@ fn test_select_union_by_name() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
|
|
|
@ -117,6 +117,7 @@ fn parse_create_procedure() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
|
@ -525,6 +526,7 @@ fn parse_substring_in_select() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
|
|
@ -908,6 +908,7 @@ fn parse_escaped_quote_identifiers_with_escape() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
@ -954,6 +955,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
@ -997,6 +999,7 @@ fn parse_escaped_backticks_with_escape() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
@ -1040,6 +1043,7 @@ fn parse_escaped_backticks_with_no_escape() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
@ -1745,6 +1749,7 @@ fn parse_select_with_numeric_prefix_column_name() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
})))
|
||||
|
@ -1797,6 +1802,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
})))
|
||||
|
@ -2291,6 +2297,7 @@ fn parse_substring_in_select() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
|
@ -2603,6 +2610,7 @@ fn parse_hex_string_introducer() {
|
|||
sort_by: vec![],
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
qualify: None,
|
||||
value_table_mode: None,
|
||||
into: None,
|
||||
|
|
|
@ -1078,6 +1078,7 @@ fn parse_copy_to() {
|
|||
group_by: GroupByExpr::Expressions(vec![]),
|
||||
having: None,
|
||||
named_window: vec![],
|
||||
window_before_qualify: false,
|
||||
cluster_by: vec![],
|
||||
distribute_by: vec![],
|
||||
sort_by: vec![],
|
||||
|
@ -2170,6 +2171,7 @@ fn parse_array_subquery_expr() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
@ -2188,6 +2190,7 @@ fn parse_array_subquery_expr() {
|
|||
having: None,
|
||||
named_window: vec![],
|
||||
qualify: None,
|
||||
window_before_qualify: false,
|
||||
value_table_mode: None,
|
||||
connect_by: None,
|
||||
}))),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue