Skip to content

Commit e972f2f

Browse files
finchxxiaayman-sigma
authored andcommitted
Snowflake: Support SAMPLE clause on subqueries (apache#2164)
1 parent c00914f commit e972f2f

5 files changed

Lines changed: 37 additions & 1 deletion

File tree

src/ast/query.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,8 @@ pub enum TableFactor {
13251325
subquery: Box<Query>,
13261326
/// Optional alias for the derived table.
13271327
alias: Option<TableAlias>,
1328+
/// Optional table sample modifier
1329+
sample: Option<TableSampleKind>,
13281330
},
13291331
/// A pass-through query string that is not parsed.
13301332
/// This is useful while building/rewriting queries with a known valid SQL string and to avoid parsing it.
@@ -2077,6 +2079,7 @@ impl fmt::Display for TableFactor {
20772079
lateral,
20782080
subquery,
20792081
alias,
2082+
sample,
20802083
} => {
20812084
if *lateral {
20822085
write!(f, "LATERAL ")?;
@@ -2089,6 +2092,9 @@ impl fmt::Display for TableFactor {
20892092
if let Some(alias) = alias {
20902093
write!(f, " {alias}")?;
20912094
}
2095+
if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
2096+
write!(f, " {sample}")?;
2097+
}
20922098
Ok(())
20932099
}
20942100
TableFactor::PassThroughQuery { query, alias } => {

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,7 @@ impl Spanned for TableFactor {
19221922
lateral: _,
19231923
subquery,
19241924
alias,
1925+
sample: _,
19251926
} => subquery
19261927
.span()
19271928
.union_opt(&alias.as_ref().map(|alias| alias.span())),

src/parser/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15105,6 +15105,7 @@ impl<'a> Parser<'a> {
1510515105
pipe_operators: vec![],
1510615106
}),
1510715107
alias,
15108+
sample: None,
1510815109
})
1510915110
} else if dialect_of!(self is BigQueryDialect | PostgreSqlDialect | GenericDialect)
1511015111
&& self.parse_keyword(Keyword::UNNEST)
@@ -15912,13 +15913,20 @@ impl<'a> Parser<'a> {
1591215913
let subquery = self.parse_query()?;
1591315914
self.expect_token(&Token::RParen)?;
1591415915
let alias = self.maybe_parse_table_alias()?;
15916+
15917+
// Parse optional SAMPLE clause after alias
15918+
let sample = self
15919+
.maybe_parse_table_sample()?
15920+
.map(TableSampleKind::AfterTableAlias);
15921+
1591515922
Ok(TableFactor::Derived {
1591615923
lateral: match lateral {
1591715924
Lateral => true,
1591815925
NotLateral => false,
1591915926
},
1592015927
subquery,
1592115928
alias,
15929+
sample,
1592215930
})
1592315931
}
1592415932

tests/sqlparser_common.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,8 @@ fn parse_update_set_from() {
512512
format_clause: None,
513513
pipe_operators: vec![],
514514
}),
515-
alias: table_alias(true, "t2")
515+
alias: table_alias(true, "t2"),
516+
sample: None,
516517
},
517518
joins: vec![]
518519
}])),
@@ -7864,6 +7865,7 @@ fn parse_derived_tables() {
78647865
lateral: false,
78657866
subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
78667867
alias: table_alias(true, "t1"),
7868+
sample: None,
78677869
},
78687870
joins: vec![Join {
78697871
relation: table_from_name(ObjectName::from(vec!["t2".into()])),
@@ -8872,6 +8874,7 @@ fn lateral_derived() {
88728874
lateral,
88738875
ref subquery,
88748876
alias: Some(ref alias),
8877+
sample: _,
88758878
} = join.relation
88768879
{
88778880
assert_eq!(lateral_in, lateral);
@@ -9951,6 +9954,7 @@ fn parse_merge() {
99519954
pipe_operators: vec![],
99529955
}),
99539956
alias: table_alias(true, "stg"),
9957+
sample: None,
99549958
}
99559959
);
99569960
assert_eq!(source, source_no_into);

tests/sqlparser_snowflake.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3538,6 +3538,23 @@ fn test_table_sample() {
35383538
snowflake_and_generic().verified_stmt("SELECT id FROM mytable TABLESAMPLE (10) SEED (1)");
35393539
}
35403540

3541+
#[test]
3542+
fn test_subquery_sample() {
3543+
// Test SAMPLE clause on subqueries (derived tables)
3544+
snowflake_and_generic().verified_stmt("SELECT * FROM (SELECT * FROM mytable) SAMPLE (10)");
3545+
snowflake_and_generic()
3546+
.verified_stmt("SELECT * FROM (SELECT * FROM mytable) SAMPLE (10000 ROWS)");
3547+
snowflake_and_generic()
3548+
.verified_stmt("SELECT * FROM (SELECT * FROM mytable) AS t SAMPLE (50 PERCENT)");
3549+
// Nested subquery with SAMPLE
3550+
snowflake_and_generic().verified_stmt(
3551+
"SELECT * FROM (SELECT * FROM (SELECT report_from FROM mytable) SAMPLE (10000 ROWS)) AS anon_1",
3552+
);
3553+
// SAMPLE with SEED on subquery
3554+
snowflake_and_generic()
3555+
.verified_stmt("SELECT * FROM (SELECT * FROM mytable) SAMPLE (10) SEED (42)");
3556+
}
3557+
35413558
#[test]
35423559
fn parse_ls_and_rm() {
35433560
snowflake().one_statement_parses_to("LS @~", "LIST @~");

0 commit comments

Comments
 (0)