Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ pub use self::query::{
IlikeSelectItem, InputFormatClause, Interpolate, InterpolateExpr, Join, JoinConstraint,
JoinOperator, JsonTableColumn, JsonTableColumnErrorHandling, JsonTableNamedColumn,
JsonTableNestedColumn, LateralView, LimitClause, LockClause, LockType, MatchRecognizePattern,
MatchRecognizeSymbol, Measure, NamedWindowDefinition, NamedWindowExpr, NonBlock, Offset,
OffsetRows, OpenJsonTableColumn, OrderBy, OrderByExpr, OrderByKind, OrderByOptions,
PipeOperator, PivotValueSource, ProjectionSelect, Query, RenameSelectItem,
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,
SelectFlavor, SelectInto, SelectItem, SelectItemQualifiedWildcardKind, SelectModifiers,
MatchRecognizeSymbol, MatchRecognizeWindowSemantic, Measure, NamedWindowDefinition,
NamedWindowExpr, NonBlock, Offset, OffsetRows, OpenJsonTableColumn, OrderBy, OrderByExpr,
OrderByKind, OrderByOptions, PipeOperator, PivotValueSource, ProjectionSelect, Query,
RenameSelectItem, RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch,
Select, SelectFlavor, SelectInto, SelectItem, SelectItemQualifiedWildcardKind, SelectModifiers,
SetExpr, SetOperator, SetQuantifier, Setting, SymbolDefinition, Table, TableAlias,
TableAliasColumnDef, TableFactor, TableFunctionArgs, TableIndexHintForClause,
TableIndexHintType, TableIndexHints, TableIndexType, TableSample, TableSampleBucket,
Expand Down
28 changes: 28 additions & 0 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1987,6 +1987,9 @@ impl fmt::Display for PivotValueSource {
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
/// An item in the `MEASURES` clause of `MATCH_RECOGNIZE`.
pub struct Measure {
/// Explicit window-frame semantic for the measure.
#[cfg_attr(feature = "serde", serde(default))]
pub window_semantic: Option<MatchRecognizeWindowSemantic>,
/// Expression producing the measure value.
pub expr: Expr,
/// Alias for the measure column.
Expand All @@ -1995,10 +1998,35 @@ pub struct Measure {

impl fmt::Display for Measure {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(window_semantic) = self.window_semantic {
write!(f, "{window_semantic} ")?;
}
write!(f, "{} AS {}", self.expr, self.alias)
}
}

/// Window-frame semantic for a `MATCH_RECOGNIZE` measure.
///
/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#label-match-recognize-navigational-functions>.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum MatchRecognizeWindowSemantic {
/// The frame ends at the current row.
Running,
/// The frame ends at the last row of the match.
Final,
}

impl fmt::Display for MatchRecognizeWindowSemantic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Running => write!(f, "RUNNING"),
Self::Final => write!(f, "FINAL"),
}
}
}

/// The rows per match option in a `MATCH_RECOGNIZE` operation.
///
/// See <https://docs.snowflake.com/en/sql-reference/constructs/match_recognize#row-s-per-match-specifying-the-rows-to-return>.
Expand Down
6 changes: 5 additions & 1 deletion src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2116,7 +2116,11 @@ impl Spanned for SymbolDefinition {

impl Spanned for Measure {
fn span(&self) -> Span {
let Measure { expr, alias } = self;
let Measure {
window_semantic: _,
expr,
alias,
} = self;

expr.span().union(&alias.span)
}
Expand Down
1 change: 1 addition & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ define_keywords!(
ROW_NUMBER,
RULE,
RUN,
RUNNING,
SAFE,
SAFE_CAST,
SAMPLE,
Expand Down
13 changes: 12 additions & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16709,10 +16709,21 @@ impl<'a> Parser<'a> {

let measures = if self.parse_keyword(Keyword::MEASURES) {
self.parse_comma_separated(|p| {
let window_semantic = if p.parse_keyword(Keyword::RUNNING) {
Some(MatchRecognizeWindowSemantic::Running)
} else if p.parse_keyword(Keyword::FINAL) {
Some(MatchRecognizeWindowSemantic::Final)
} else {
None
};
let expr = p.parse_expr()?;
let _ = p.parse_keyword(Keyword::AS);
let alias = p.parse_identifier()?;
Ok(Measure { expr, alias })
Ok(Measure {
window_semantic,
expr,
alias,
})
})?
} else {
vec![]
Expand Down
7 changes: 5 additions & 2 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13246,8 +13246,8 @@ fn test_match_recognize() {
"ORDER BY price_date ",
"MEASURES ",
"MATCH_NUMBER() AS match_number, ",
"FIRST(price_date) AS start_date, ",
"LAST(price_date) AS end_date ",
"FINAL FIRST(price_date) AS start_date, ",
"RUNNING LAST(price_date) AS end_date ",
"ONE ROW PER MATCH ",
"AFTER MATCH SKIP TO LAST row_with_price_increase ",
"PATTERN (row_before_decrease row_with_price_decrease+ row_with_price_increase+) ",
Expand All @@ -13268,14 +13268,17 @@ fn test_match_recognize() {
}],
measures: vec![
Measure {
window_semantic: None,
expr: call("MATCH_NUMBER", []),
alias: Ident::new("match_number"),
},
Measure {
window_semantic: Some(MatchRecognizeWindowSemantic::Final),
expr: call("FIRST", [Expr::Identifier(Ident::new("price_date"))]),
alias: Ident::new("start_date"),
},
Measure {
window_semantic: Some(MatchRecognizeWindowSemantic::Running),
expr: call("LAST", [Expr::Identifier(Ident::new("price_date"))]),
alias: Ident::new("end_date"),
},
Expand Down
Loading