This is an automated email from the ASF dual-hosted git repository. github-bot pushed a commit to branch gh-readonly-queue/main/pr-2155-46f2234c1596d8763db3955ec50d6343ca2f77a5 in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 6060a11d1f728d1639f761d3bb90e136911934f9 Author: James Vorderbruggen <[email protected]> AuthorDate: Tue Jan 20 06:30:35 2026 -0600 Databricks: Support Timetravel With "VERSION AS OF" (#2155) --- src/ast/query.rs | 5 +++++ src/dialect/bigquery.rs | 2 +- src/dialect/databricks.rs | 2 +- src/dialect/mod.rs | 2 +- src/dialect/mssql.rs | 2 +- src/dialect/snowflake.rs | 2 +- src/parser/mod.rs | 5 ++++- tests/sqlparser_databricks.rs | 11 +++++++++-- 8 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/ast/query.rs b/src/ast/query.rs index d8af243f..a1fc33b6 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -2398,6 +2398,10 @@ pub enum TableVersion { /// Databricks supports this syntax. /// For example: `SELECT * FROM tbl TIMESTAMP AS OF CURRENT_TIMESTAMP() - INTERVAL 1 HOUR` TimestampAsOf(Expr), + /// When the table version is defined using `VERSION AS OF`. + /// Databricks supports this syntax. + /// For example: `SELECT * FROM tbl VERSION AS OF 2` + VersionAsOf(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), @@ -2408,6 +2412,7 @@ impl Display for TableVersion { match self { TableVersion::ForSystemTimeAsOf(e) => write!(f, "FOR SYSTEM_TIME AS OF {e}")?, TableVersion::TimestampAsOf(e) => write!(f, "TIMESTAMP AS OF {e}")?, + TableVersion::VersionAsOf(e) => write!(f, "VERSION AS OF {e}")?, TableVersion::Function(func) => write!(f, "{func}")?, } Ok(()) diff --git a/src/dialect/bigquery.rs b/src/dialect/bigquery.rs index 27fd3cca..6ad8a508 100644 --- a/src/dialect/bigquery.rs +++ b/src/dialect/bigquery.rs @@ -136,7 +136,7 @@ impl Dialect for BigQueryDialect { } // See <https://cloud.google.com/bigquery/docs/access-historical-data> - fn supports_timestamp_versioning(&self) -> bool { + fn supports_table_versioning(&self) -> bool { true } diff --git a/src/dialect/databricks.rs b/src/dialect/databricks.rs index ec866295..029709fe 100644 --- a/src/dialect/databricks.rs +++ b/src/dialect/databricks.rs @@ -48,7 +48,7 @@ impl Dialect for DatabricksDialect { } /// <https://docs.databricks.com/gcp/en/delta/history#delta-time-travel-syntax> - fn supports_timestamp_versioning(&self) -> bool { + fn supports_table_versioning(&self) -> bool { true } diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index d1728566..cd7fdee1 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -1072,7 +1072,7 @@ pub trait Dialect: Debug + Any { /// 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 { + fn supports_table_versioning(&self) -> bool { false } diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs index a2854525..9f8e7265 100644 --- a/src/dialect/mssql.rs +++ b/src/dialect/mssql.rs @@ -107,7 +107,7 @@ impl Dialect for MsSqlDialect { } /// 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 { + fn supports_table_versioning(&self) -> bool { true } diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index eade01c0..1e571d0f 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -540,7 +540,7 @@ impl Dialect for SnowflakeDialect { } /// See: <https://docs.snowflake.com/en/sql-reference/constructs/at-before> - fn supports_timestamp_versioning(&self) -> bool { + fn supports_table_versioning(&self) -> bool { true } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 6fd7b5ca..149365c4 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -15731,7 +15731,7 @@ impl<'a> Parser<'a> { /// 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.dialect.supports_table_versioning() { if self.parse_keywords(&[Keyword::FOR, Keyword::SYSTEM_TIME, Keyword::AS, Keyword::OF]) { let expr = self.parse_expr()?; @@ -15743,6 +15743,9 @@ impl<'a> Parser<'a> { } else if self.parse_keywords(&[Keyword::TIMESTAMP, Keyword::AS, Keyword::OF]) { let expr = self.parse_expr()?; return Ok(Some(TableVersion::TimestampAsOf(expr))); + } else if self.parse_keywords(&[Keyword::VERSION, Keyword::AS, Keyword::OF]) { + let expr = Expr::Value(self.parse_number_value()?); + return Ok(Some(TableVersion::VersionAsOf(expr))); } } Ok(None) diff --git a/tests/sqlparser_databricks.rs b/tests/sqlparser_databricks.rs index 9064c8dc..7f5ec6c3 100644 --- a/tests/sqlparser_databricks.rs +++ b/tests/sqlparser_databricks.rs @@ -371,14 +371,21 @@ fn data_type_timestamp_ntz() { #[test] fn parse_table_time_travel() { - all_dialects_where(|d| d.supports_timestamp_versioning()) + all_dialects_where(|d| d.supports_table_versioning()) .verified_only_select("SELECT 1 FROM t1 TIMESTAMP AS OF '2018-10-18T22:15:12.013Z'"); - all_dialects_where(|d| d.supports_timestamp_versioning()).verified_only_select( + all_dialects_where(|d| d.supports_table_versioning()).verified_only_select( "SELECT 1 FROM t1 TIMESTAMP AS OF CURRENT_TIMESTAMP() - INTERVAL 12 HOURS", ); + all_dialects_where(|d| d.supports_table_versioning()) + .verified_only_select("SELECT 1 FROM t1 VERSION AS OF 1"); + assert!(databricks() .parse_sql_statements("SELECT 1 FROM t1 FOR TIMESTAMP AS OF 'some_timestamp'") .is_err()); + + assert!(all_dialects_where(|d| d.supports_table_versioning()) + .parse_sql_statements("SELECT 1 FROM t1 VERSION AS OF 1 - 2",) + .is_err()) } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
