This is an automated email from the ASF dual-hosted git repository.
iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 5da702fc Add support for Snowflake AT/BEFORE (#1667)
5da702fc is described below
commit 5da702fc19f9dc73559d9a6f0408729f1121444a
Author: Yoav Cohen <[email protected]>
AuthorDate: Sun Jan 19 12:08:45 2025 +0100
Add support for Snowflake AT/BEFORE (#1667)
---
src/ast/query.rs | 6 ++++++
src/dialect/bigquery.rs | 5 +++++
src/dialect/mod.rs | 6 ++++++
src/dialect/mssql.rs | 5 +++++
src/dialect/snowflake.rs | 5 +++++
src/parser/mod.rs | 26 ++++++++++++++------------
tests/sqlparser_snowflake.rs | 7 +++++++
7 files changed, 48 insertions(+), 12 deletions(-)
diff --git a/src/ast/query.rs b/src/ast/query.rs
index 66c70b46..4053dd23 100644
--- a/src/ast/query.rs
+++ b/src/ast/query.rs
@@ -1873,13 +1873,19 @@ impl fmt::Display for TableAliasColumnDef {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TableVersion {
+ /// When the table version is defined using `FOR SYSTEM_TIME AS OF`.
+ /// For example: `SELECT * FROM tbl FOR SYSTEM_TIME AS OF
TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)`
ForSystemTimeAsOf(Expr),
+ /// When the table version is defined using a function.
+ /// For example: `SELECT * FROM tbl AT(TIMESTAMP => '2020-08-14 09:30:00')`
+ Function(Expr),
}
impl Display for TableVersion {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TableVersion::ForSystemTimeAsOf(e) => write!(f, " FOR SYSTEM_TIME
AS OF {e}")?,
+ TableVersion::Function(func) => write!(f, " {func}")?,
}
Ok(())
}
diff --git a/src/dialect/bigquery.rs b/src/dialect/bigquery.rs
index 66d7d206..e92169a3 100644
--- a/src/dialect/bigquery.rs
+++ b/src/dialect/bigquery.rs
@@ -77,4 +77,9 @@ impl Dialect for BigQueryDialect {
fn supports_struct_literal(&self) -> bool {
true
}
+
+ // See <https://cloud.google.com/bigquery/docs/access-historical-data>
+ fn supports_timestamp_versioning(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index c69253b7..119bb3cf 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -834,6 +834,12 @@ pub trait Dialect: Debug + Any {
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, _parser:
&mut Parser) -> bool {
explicit || !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
}
+
+ /// Returns true if this dialect supports querying historical table data
+ /// by specifying which version of the data to query.
+ fn supports_timestamp_versioning(&self) -> bool {
+ false
+ }
}
/// This represents the operators for which precedence must be defined
diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs
index 67a64894..7d8611cb 100644
--- a/src/dialect/mssql.rs
+++ b/src/dialect/mssql.rs
@@ -90,4 +90,9 @@ impl Dialect for MsSqlDialect {
fn supports_set_stmt_without_operator(&self) -> bool {
true
}
+
+ /// See:
<https://learn.microsoft.com/en-us/sql/relational-databases/tables/querying-data-in-a-system-versioned-temporal-table>
+ fn supports_timestamp_versioning(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs
index f6e9c9eb..78237acd 100644
--- a/src/dialect/snowflake.rs
+++ b/src/dialect/snowflake.rs
@@ -296,6 +296,11 @@ impl Dialect for SnowflakeDialect {
_ => true,
}
}
+
+ /// See: <https://docs.snowflake.com/en/sql-reference/constructs/at-before>
+ fn supports_timestamp_versioning(&self) -> bool {
+ true
+ }
}
fn parse_file_staging_command(kw: Keyword, parser: &mut Parser) ->
Result<Statement, ParserError> {
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index a3adb023..51bbcfab 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -11208,7 +11208,7 @@ impl<'a> Parser<'a> {
};
// Parse potential version qualifier
- let version = self.parse_table_version()?;
+ let version = self.maybe_parse_table_version()?;
// Postgres, MSSQL, ClickHouse: table-valued functions:
let args = if self.consume_token(&Token::LParen) {
@@ -11639,18 +11639,20 @@ impl<'a> Parser<'a> {
}
}
- /// Parse a given table version specifier.
- ///
- /// For now it only supports timestamp versioning for BigQuery and MSSQL
dialects.
- pub fn parse_table_version(&mut self) -> Result<Option<TableVersion>,
ParserError> {
- if dialect_of!(self is BigQueryDialect | MsSqlDialect)
- && self.parse_keywords(&[Keyword::FOR, Keyword::SYSTEM_TIME,
Keyword::AS, Keyword::OF])
- {
- let expr = self.parse_expr()?;
- Ok(Some(TableVersion::ForSystemTimeAsOf(expr)))
- } else {
- Ok(None)
+ /// Parses a the timestamp version specifier (i.e. query historical data)
+ pub fn maybe_parse_table_version(&mut self) ->
Result<Option<TableVersion>, ParserError> {
+ if self.dialect.supports_timestamp_versioning() {
+ if self.parse_keywords(&[Keyword::FOR, Keyword::SYSTEM_TIME,
Keyword::AS, Keyword::OF])
+ {
+ let expr = self.parse_expr()?;
+ return Ok(Some(TableVersion::ForSystemTimeAsOf(expr)));
+ } else if self.peek_keyword(Keyword::AT) ||
self.peek_keyword(Keyword::BEFORE) {
+ let func_name = self.parse_object_name(true)?;
+ let func = self.parse_function(func_name)?;
+ return Ok(Some(TableVersion::Function(func)));
+ }
}
+ Ok(None)
}
/// Parses MySQL's JSON_TABLE column definition.
diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs
index fe6439b3..0c4bdf14 100644
--- a/tests/sqlparser_snowflake.rs
+++ b/tests/sqlparser_snowflake.rs
@@ -3051,3 +3051,10 @@ fn test_sql_keywords_as_select_item_aliases() {
.is_err());
}
}
+
+#[test]
+fn test_timetravel_at_before() {
+ snowflake().verified_only_select("SELECT * FROM tbl AT(TIMESTAMP =>
'2024-12-15 00:00:00')");
+ snowflake()
+ .verified_only_select("SELECT * FROM tbl BEFORE(TIMESTAMP =>
'2024-12-15 00:00:00')");
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]