From a71d0385321698df33a4bcb446107f411e858ad9 Mon Sep 17 00:00:00 2001 From: Wei-Ting Kuo Date: Sat, 27 Aug 2022 05:11:21 +0800 Subject: [PATCH] add with/without time zone (#589) --- src/ast/data_type.rs | 5 ++++- src/dialect/keywords.rs | 2 ++ src/parser.rs | 11 ++++++++--- src/tokenizer.rs | 2 +- tests/sqlparser_common.rs | 33 ++++++++++++++++++++++++++++----- 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs index 388703e76..9d68feba1 100644 --- a/src/ast/data_type.rs +++ b/src/ast/data_type.rs @@ -53,8 +53,10 @@ pub enum DataType { Date, /// Time Time, - /// Timestamp + /// Timestamp [Without Time Zone] Timestamp, + /// Timestamp With Time Zone + TimestampTz, /// Interval Interval, /// Regclass used in postgresql serial @@ -100,6 +102,7 @@ impl fmt::Display for DataType { DataType::Date => write!(f, "DATE"), DataType::Time => write!(f, "TIME"), DataType::Timestamp => write!(f, "TIMESTAMP"), + DataType::TimestampTz => write!(f, "TIMESTAMPTZ"), DataType::Interval => write!(f, "INTERVAL"), DataType::Regclass => write!(f, "REGCLASS"), DataType::Text => write!(f, "TEXT"), diff --git a/src/dialect/keywords.rs b/src/dialect/keywords.rs index 1c481a882..c4337c7ed 100644 --- a/src/dialect/keywords.rs +++ b/src/dialect/keywords.rs @@ -445,6 +445,8 @@ define_keywords!( TIES, TIME, TIMESTAMP, + TIMESTAMPTZ, + TIMEZONE, TIMEZONE_HOUR, TIMEZONE_MINUTE, TO, diff --git a/src/parser.rs b/src/parser.rs index 5fc3846dc..84432e135 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2024,12 +2024,17 @@ impl<'a> Parser<'a> { Keyword::UUID => Ok(DataType::Uuid), Keyword::DATE => Ok(DataType::Date), Keyword::TIMESTAMP => { - // TBD: we throw away "with/without timezone" information - if self.parse_keyword(Keyword::WITH) || self.parse_keyword(Keyword::WITHOUT) { + if self.parse_keyword(Keyword::WITH) { self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; + Ok(DataType::TimestampTz) + } else if self.parse_keyword(Keyword::WITHOUT) { + self.expect_keywords(&[Keyword::TIME, Keyword::ZONE])?; + Ok(DataType::Timestamp) + } else { + Ok(DataType::Timestamp) } - Ok(DataType::Timestamp) } + Keyword::TIMESTAMPTZ => Ok(DataType::TimestampTz), Keyword::TIME => { // TBD: we throw away "with/without timezone" information if self.parse_keyword(Keyword::WITH) || self.parse_keyword(Keyword::WITHOUT) { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index d04e1d8f7..4222eecca 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -616,7 +616,7 @@ impl<'a> Tokenizer<'a> { 'r' => s.push('\r'), 't' => s.push('\t'), 'Z' => s.push('\x1a'), - x => s.push(x) + x => s.push(x), } } } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 4739f146d..768059b24 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1893,7 +1893,7 @@ fn parse_literal_time() { } #[test] -fn parse_literal_timestamp() { +fn parse_literal_timestamp_without_time_zone() { let sql = "SELECT TIMESTAMP '1999-01-01 01:23:34'"; let select = verified_only_select(sql); assert_eq!( @@ -1903,6 +1903,29 @@ fn parse_literal_timestamp() { }, expr_from_projection(only(&select.projection)), ); + + one_statement_parses_to( + "SELECT TIMESTAMP WITHOUT TIME ZONE '1999-01-01 01:23:34'", + sql, + ); +} + +#[test] +fn parse_literal_timestamp_with_time_zone() { + let sql = "SELECT TIMESTAMPTZ '1999-01-01 01:23:34Z'"; + let select = verified_only_select(sql); + assert_eq!( + &Expr::TypedString { + data_type: DataType::TimestampTz, + value: "1999-01-01 01:23:34Z".into() + }, + expr_from_projection(only(&select.projection)), + ); + + one_statement_parses_to( + "SELECT TIMESTAMP WITH TIME ZONE '1999-01-01 01:23:34Z'", + sql, + ); } #[test] @@ -2715,10 +2738,10 @@ fn parse_scalar_subqueries() { assert_matches!( verified_expr(sql), Expr::BinaryOp { - op: BinaryOperator::Plus, .. - //left: box Subquery { .. }, - //right: box Subquery { .. }, - } + op: BinaryOperator::Plus, + .. //left: box Subquery { .. }, + //right: box Subquery { .. }, + } ); }