From d97f065a950ba87c7e6e417b4c01ee47e8a4c45f Mon Sep 17 00:00:00 2001 From: Abdulla Abdurakhmanov Date: Mon, 9 Nov 2026 19:50:38 +0100 Subject: [PATCH 1/2] Support `TABLESAMPLE RESERVOIR` --- fuzz/fuzz_seeds/bigquery_tablesample_reservoir.sql | 1 + src/ast/query.rs | 3 +++ src/keywords.rs | 1 + src/parser/mod.rs | 2 ++ tests/sqlparser_common.rs | 8 ++++++++ 5 files changed, 15 insertions(+) create mode 100644 fuzz/fuzz_seeds/bigquery_tablesample_reservoir.sql diff --git a/fuzz/fuzz_seeds/bigquery_tablesample_reservoir.sql b/fuzz/fuzz_seeds/bigquery_tablesample_reservoir.sql new file mode 100644 index 0000000000..9146b156dd --- /dev/null +++ b/fuzz/fuzz_seeds/bigquery_tablesample_reservoir.sql @@ -0,0 +1 @@ +SELECT * FROM t TABLESAMPLE RESERVOIR (100 ROWS) REPEATABLE (10) \ No newline at end of file diff --git a/src/ast/query.rs b/src/ast/query.rs index e2364dbe9a..fcc7379768 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -1883,6 +1883,8 @@ pub enum TableSampleMethod { System, /// `BLOCK` sampling method. Block, + /// `RESERVOIR` sampling method. + Reservoir, } impl fmt::Display for TableSampleMethod { @@ -1892,6 +1894,7 @@ impl fmt::Display for TableSampleMethod { TableSampleMethod::Row => write!(f, "ROW"), TableSampleMethod::System => write!(f, "SYSTEM"), TableSampleMethod::Block => write!(f, "BLOCK"), + TableSampleMethod::Reservoir => write!(f, "RESERVOIR"), } } } diff --git a/src/keywords.rs b/src/keywords.rs index 4a2fbca681..2f943d9e6f 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -912,6 +912,7 @@ define_keywords!( REPLICATE, REPLICATION, REQUIRE, + RESERVOIR, RESET, RESOLVE, RESOURCE, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 1d6cc53417..f6f0a6cd74 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -17941,11 +17941,13 @@ impl<'a> Parser<'a> { Keyword::ROW, Keyword::SYSTEM, Keyword::BLOCK, + Keyword::RESERVOIR, ]) { Some(Keyword::BERNOULLI) => Some(TableSampleMethod::Bernoulli), Some(Keyword::ROW) => Some(TableSampleMethod::Row), Some(Keyword::SYSTEM) => Some(TableSampleMethod::System), Some(Keyword::BLOCK) => Some(TableSampleMethod::Block), + Some(Keyword::RESERVOIR) => Some(TableSampleMethod::Reservoir), _ => None, }; diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index aeb3e67a47..cf1547f1b0 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -17628,6 +17628,14 @@ fn test_table_sample() { dialects.verified_stmt("SELECT * FROM tbl AS t TABLESAMPLE BERNOULLI (50)"); dialects.verified_stmt("SELECT * FROM tbl AS t TABLESAMPLE SYSTEM (50)"); dialects.verified_stmt("SELECT * FROM tbl AS t TABLESAMPLE SYSTEM (50) REPEATABLE (10)"); + dialects.verified_stmt("SELECT * FROM tbl AS t TABLESAMPLE RESERVOIR (50 ROWS)"); + + assert_eq!( + dialects + .parse_sql_statements("SELECT * FROM tbl TABLESAMPLE RESERVOIR ()") + .unwrap_err(), + ParserError::ParserError("Expecting number or byte length e.g. 100M".to_string()) + ); } #[test] From 90a12f31a985ba87faec1a5a911f16a88bd13d66 Mon Sep 17 00:00:00 2001 From: Abdulla Abdurakhmanov Date: Wed, 11 Nov 2026 19:53:46 +0100 Subject: [PATCH 2/2] Link the Spanner documentation for RESERVOIR --- src/ast/query.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ast/query.rs b/src/ast/query.rs index fcc7379768..65b62396b6 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -1884,6 +1884,10 @@ pub enum TableSampleMethod { /// `BLOCK` sampling method. Block, /// `RESERVOIR` sampling method. + /// + /// Picks a fixed number of rows (`n ROWS`) at random, or every row when the input has fewer. + /// + /// [Spanner](https://cloud.google.com/spanner/docs/reference/standard-sql/query-syntax#tablesample_operator) Reservoir, }