Skip to content

Commit a8bde39

Browse files
Add support for TABLESAMPLE pipe operator (#1860)
1 parent eacf00d commit a8bde39

File tree

3 files changed

+29
-5
lines changed

3 files changed

+29
-5
lines changed

src/ast/query.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,7 @@ impl fmt::Display for TableSampleBucket {
15591559
}
15601560
impl fmt::Display for TableSample {
15611561
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1562-
write!(f, " {}", self.modifier)?;
1562+
write!(f, "{}", self.modifier)?;
15631563
if let Some(name) = &self.name {
15641564
write!(f, " {}", name)?;
15651565
}
@@ -1862,7 +1862,7 @@ impl fmt::Display for TableFactor {
18621862
write!(f, " WITH ORDINALITY")?;
18631863
}
18641864
if let Some(TableSampleKind::BeforeTableAlias(sample)) = sample {
1865-
write!(f, "{sample}")?;
1865+
write!(f, " {sample}")?;
18661866
}
18671867
if let Some(alias) = alias {
18681868
write!(f, " AS {alias}")?;
@@ -1877,7 +1877,7 @@ impl fmt::Display for TableFactor {
18771877
write!(f, "{version}")?;
18781878
}
18791879
if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
1880-
write!(f, "{sample}")?;
1880+
write!(f, " {sample}")?;
18811881
}
18821882
Ok(())
18831883
}
@@ -2680,6 +2680,10 @@ pub enum PipeOperator {
26802680
full_table_exprs: Vec<ExprWithAliasAndOrderBy>,
26812681
group_by_expr: Vec<ExprWithAliasAndOrderBy>,
26822682
},
2683+
/// Selects a random sample of rows from the input table.
2684+
/// Syntax: `|> TABLESAMPLE SYSTEM (10 PERCENT)
2685+
/// See more at <https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax#tablesample_pipe_operator>
2686+
TableSample { sample: Box<TableSample> },
26832687
}
26842688

26852689
impl fmt::Display for PipeOperator {
@@ -2731,6 +2735,10 @@ impl fmt::Display for PipeOperator {
27312735
PipeOperator::OrderBy { exprs } => {
27322736
write!(f, "ORDER BY {}", display_comma_separated(exprs.as_slice()))
27332737
}
2738+
2739+
PipeOperator::TableSample { sample } => {
2740+
write!(f, "{}", sample)
2741+
}
27342742
}
27352743
}
27362744
}

src/parser/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11054,6 +11054,7 @@ impl<'a> Parser<'a> {
1105411054
Keyword::LIMIT,
1105511055
Keyword::AGGREGATE,
1105611056
Keyword::ORDER,
11057+
Keyword::TABLESAMPLE,
1105711058
])?;
1105811059
match kw {
1105911060
Keyword::SELECT => {
@@ -11116,6 +11117,10 @@ impl<'a> Parser<'a> {
1111611117
let exprs = self.parse_comma_separated(Parser::parse_order_by_expr)?;
1111711118
pipe_operators.push(PipeOperator::OrderBy { exprs })
1111811119
}
11120+
Keyword::TABLESAMPLE => {
11121+
let sample = self.parse_table_sample(TableSampleModifier::TableSample)?;
11122+
pipe_operators.push(PipeOperator::TableSample { sample });
11123+
}
1111911124
unhandled => {
1112011125
return Err(ParserError::ParserError(format!(
1112111126
"`expect_one_of_keywords` further up allowed unhandled keyword: {unhandled:?}"
@@ -12760,7 +12765,13 @@ impl<'a> Parser<'a> {
1276012765
} else {
1276112766
return Ok(None);
1276212767
};
12768+
self.parse_table_sample(modifier).map(Some)
12769+
}
1276312770

12771+
fn parse_table_sample(
12772+
&mut self,
12773+
modifier: TableSampleModifier,
12774+
) -> Result<Box<TableSample>, ParserError> {
1276412775
let name = match self.parse_one_of_keywords(&[
1276512776
Keyword::BERNOULLI,
1276612777
Keyword::ROW,
@@ -12842,14 +12853,14 @@ impl<'a> Parser<'a> {
1284212853
None
1284312854
};
1284412855

12845-
Ok(Some(Box::new(TableSample {
12856+
Ok(Box::new(TableSample {
1284612857
modifier,
1284712858
name,
1284812859
quantity,
1284912860
seed,
1285012861
bucket,
1285112862
offset,
12852-
})))
12863+
}))
1285312864
}
1285412865

1285512866
fn parse_table_sample_seed(

tests/sqlparser_common.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15156,6 +15156,11 @@ fn parse_pipeline_operator() {
1515615156
dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC");
1515715157
dialects.verified_stmt("SELECT * FROM users |> ORDER BY id DESC, name ASC");
1515815158

15159+
// tablesample pipe operator
15160+
dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE BERNOULLI (50)");
15161+
dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50 PERCENT)");
15162+
dialects.verified_stmt("SELECT * FROM tbl |> TABLESAMPLE SYSTEM (50) REPEATABLE (10)");
15163+
1515915164
// many pipes
1516015165
dialects.verified_stmt(
1516115166
"SELECT * FROM CustomerOrders |> AGGREGATE SUM(cost) AS total_cost GROUP BY customer_id, state, item_type |> EXTEND COUNT(*) OVER (PARTITION BY customer_id) AS num_orders |> WHERE num_orders > 1 |> AGGREGATE AVG(total_cost) AS average GROUP BY state DESC, item_type ASC",

0 commit comments

Comments
 (0)