Skip to content

Commit 3ac1bb5

Browse files
authored
Move Value::Interval to Expr::Interval (#609)
* refactor(value): convert Value::Interval to Expr::Interval * test(sqlparser_common): modify test case * refactor(parser): rename func parse_interval * refactor(tests) rename parse_interval test func
1 parent d971a02 commit 3ac1bb5

File tree

4 files changed

+81
-83
lines changed

4 files changed

+81
-83
lines changed

src/ast/mod.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,25 @@ pub enum Expr {
410410
ArrayIndex { obj: Box<Expr>, indexes: Vec<Expr> },
411411
/// An array expression e.g. `ARRAY[1, 2]`
412412
Array(Array),
413+
/// INTERVAL literals, roughly in the following format:
414+
/// `INTERVAL '<value>' [ <leading_field> [ (<leading_precision>) ] ]
415+
/// [ TO <last_field> [ (<fractional_seconds_precision>) ] ]`,
416+
/// e.g. `INTERVAL '123:45.67' MINUTE(3) TO SECOND(2)`.
417+
///
418+
/// The parser does not validate the `<value>`, nor does it ensure
419+
/// that the `<leading_field>` units >= the units in `<last_field>`,
420+
/// so the user will have to reject intervals like `HOUR TO YEAR`.
421+
Interval {
422+
value: Box<Expr>,
423+
leading_field: Option<DateTimeField>,
424+
leading_precision: Option<u64>,
425+
last_field: Option<DateTimeField>,
426+
/// The seconds precision can be specified in SQL source as
427+
/// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field`
428+
/// will be `Second` and the `last_field` will be `None`),
429+
/// or as `__ TO SECOND(x)`.
430+
fractional_seconds_precision: Option<u64>,
431+
},
413432
}
414433

415434
impl fmt::Display for Expr {
@@ -722,6 +741,44 @@ impl fmt::Display for Expr {
722741
} => {
723742
write!(f, "{} AT TIME ZONE '{}'", timestamp, time_zone)
724743
}
744+
Expr::Interval {
745+
value,
746+
leading_field: Some(DateTimeField::Second),
747+
leading_precision: Some(leading_precision),
748+
last_field,
749+
fractional_seconds_precision: Some(fractional_seconds_precision),
750+
} => {
751+
// When the leading field is SECOND, the parser guarantees that
752+
// the last field is None.
753+
assert!(last_field.is_none());
754+
write!(
755+
f,
756+
"INTERVAL {} SECOND ({}, {})",
757+
value, leading_precision, fractional_seconds_precision
758+
)
759+
}
760+
Expr::Interval {
761+
value,
762+
leading_field,
763+
leading_precision,
764+
last_field,
765+
fractional_seconds_precision,
766+
} => {
767+
write!(f, "INTERVAL {}", value)?;
768+
if let Some(leading_field) = leading_field {
769+
write!(f, " {}", leading_field)?;
770+
}
771+
if let Some(leading_precision) = leading_precision {
772+
write!(f, " ({})", leading_precision)?;
773+
}
774+
if let Some(last_field) = last_field {
775+
write!(f, " TO {}", last_field)?;
776+
}
777+
if let Some(fractional_seconds_precision) = fractional_seconds_precision {
778+
write!(f, " ({})", fractional_seconds_precision)?;
779+
}
780+
Ok(())
781+
}
725782
}
726783
}
727784
}

src/ast/value.rs

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ use bigdecimal::BigDecimal;
2121
#[cfg(feature = "serde")]
2222
use serde::{Deserialize, Serialize};
2323

24-
use super::Expr;
25-
2624
/// Primitive SQL values such as number and string
2725
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2826
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -45,25 +43,6 @@ pub enum Value {
4543
DoubleQuotedString(String),
4644
/// Boolean value true or false
4745
Boolean(bool),
48-
/// INTERVAL literals, roughly in the following format:
49-
/// `INTERVAL '<value>' [ <leading_field> [ (<leading_precision>) ] ]
50-
/// [ TO <last_field> [ (<fractional_seconds_precision>) ] ]`,
51-
/// e.g. `INTERVAL '123:45.67' MINUTE(3) TO SECOND(2)`.
52-
///
53-
/// The parser does not validate the `<value>`, nor does it ensure
54-
/// that the `<leading_field>` units >= the units in `<last_field>`,
55-
/// so the user will have to reject intervals like `HOUR TO YEAR`.
56-
Interval {
57-
value: Box<Expr>,
58-
leading_field: Option<DateTimeField>,
59-
leading_precision: Option<u64>,
60-
last_field: Option<DateTimeField>,
61-
/// The seconds precision can be specified in SQL source as
62-
/// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field`
63-
/// will be `Second` and the `last_field` will be `None`),
64-
/// or as `__ TO SECOND(x)`.
65-
fractional_seconds_precision: Option<u64>,
66-
},
6746
/// `NULL` value
6847
Null,
6948
/// `?` or `$` Prepared statement arg placeholder
@@ -80,44 +59,6 @@ impl fmt::Display for Value {
8059
Value::NationalStringLiteral(v) => write!(f, "N'{}'", v),
8160
Value::HexStringLiteral(v) => write!(f, "X'{}'", v),
8261
Value::Boolean(v) => write!(f, "{}", v),
83-
Value::Interval {
84-
value,
85-
leading_field: Some(DateTimeField::Second),
86-
leading_precision: Some(leading_precision),
87-
last_field,
88-
fractional_seconds_precision: Some(fractional_seconds_precision),
89-
} => {
90-
// When the leading field is SECOND, the parser guarantees that
91-
// the last field is None.
92-
assert!(last_field.is_none());
93-
write!(
94-
f,
95-
"INTERVAL {} SECOND ({}, {})",
96-
value, leading_precision, fractional_seconds_precision
97-
)
98-
}
99-
Value::Interval {
100-
value,
101-
leading_field,
102-
leading_precision,
103-
last_field,
104-
fractional_seconds_precision,
105-
} => {
106-
write!(f, "INTERVAL {}", value)?;
107-
if let Some(leading_field) = leading_field {
108-
write!(f, " {}", leading_field)?;
109-
}
110-
if let Some(leading_precision) = leading_precision {
111-
write!(f, " ({})", leading_precision)?;
112-
}
113-
if let Some(last_field) = last_field {
114-
write!(f, " TO {}", last_field)?;
115-
}
116-
if let Some(fractional_seconds_precision) = fractional_seconds_precision {
117-
write!(f, " ({})", fractional_seconds_precision)?;
118-
}
119-
Ok(())
120-
}
12162
Value::Null => write!(f, "NULL"),
12263
Value::Placeholder(v) => write!(f, "{}", v),
12364
}

src/parser.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ impl<'a> Parser<'a> {
402402
// expression that should parse as the column name "date".
403403
return_ok_if_some!(self.maybe_parse(|parser| {
404404
match parser.parse_data_type()? {
405-
DataType::Interval => parser.parse_literal_interval(),
405+
DataType::Interval => parser.parse_interval(),
406406
// PostgreSQL allows almost any identifier to be used as custom data type name,
407407
// and we support that in `parse_data_type()`. But unlike Postgres we don't
408408
// have a list of globally reserved keywords (since they vary across dialects),
@@ -455,7 +455,7 @@ impl<'a> Parser<'a> {
455455
Keyword::SUBSTRING => self.parse_substring_expr(),
456456
Keyword::OVERLAY => self.parse_overlay_expr(),
457457
Keyword::TRIM => self.parse_trim_expr(),
458-
Keyword::INTERVAL => self.parse_literal_interval(),
458+
Keyword::INTERVAL => self.parse_interval(),
459459
Keyword::LISTAGG => self.parse_listagg_expr(),
460460
// Treat ARRAY[1,2,3] as an array [1,2,3], otherwise try as subquery or a function call
461461
Keyword::ARRAY if self.peek_token() == Token::LBracket => {
@@ -1096,7 +1096,7 @@ impl<'a> Parser<'a> {
10961096
}
10971097
}
10981098

1099-
/// Parse an INTERVAL literal.
1099+
/// Parse an INTERVAL expression.
11001100
///
11011101
/// Some syntactically valid intervals:
11021102
///
@@ -1109,7 +1109,7 @@ impl<'a> Parser<'a> {
11091109
/// 7. (MySql and BigQuey only):`INTERVAL 1 DAY`
11101110
///
11111111
/// Note that we do not currently attempt to parse the quoted value.
1112-
pub fn parse_literal_interval(&mut self) -> Result<Expr, ParserError> {
1112+
pub fn parse_interval(&mut self) -> Result<Expr, ParserError> {
11131113
// The SQL standard allows an optional sign before the value string, but
11141114
// it is not clear if any implementations support that syntax, so we
11151115
// don't currently try to parse it. (The sign can instead be included
@@ -1183,13 +1183,13 @@ impl<'a> Parser<'a> {
11831183
}
11841184
};
11851185

1186-
Ok(Expr::Value(Value::Interval {
1186+
Ok(Expr::Interval {
11871187
value: Box::new(value),
11881188
leading_field,
11891189
leading_precision,
11901190
last_field,
11911191
fractional_seconds_precision: fsec_precision,
1192-
}))
1192+
})
11931193
}
11941194

11951195
/// Parse an operator following an expression
@@ -3178,7 +3178,7 @@ impl<'a> Parser<'a> {
31783178
}
31793179
// Interval types can be followed by a complicated interval
31803180
// qualifier that we don't currently support. See
3181-
// parse_interval_literal for a taste.
3181+
// parse_interval for a taste.
31823182
Keyword::INTERVAL => Ok(DataType::Interval),
31833183
Keyword::REGCLASS => Ok(DataType::Regclass),
31843184
Keyword::STRING => Ok(DataType::String),

tests/sqlparser_common.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2930,78 +2930,78 @@ fn parse_literal_timestamp_with_time_zone() {
29302930
}
29312931

29322932
#[test]
2933-
fn parse_literal_interval() {
2933+
fn parse_interval() {
29342934
let sql = "SELECT INTERVAL '1-1' YEAR TO MONTH";
29352935
let select = verified_only_select(sql);
29362936
assert_eq!(
2937-
&Expr::Value(Value::Interval {
2937+
&Expr::Interval {
29382938
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("1-1")))),
29392939
leading_field: Some(DateTimeField::Year),
29402940
leading_precision: None,
29412941
last_field: Some(DateTimeField::Month),
29422942
fractional_seconds_precision: None,
2943-
}),
2943+
},
29442944
expr_from_projection(only(&select.projection)),
29452945
);
29462946

29472947
let sql = "SELECT INTERVAL '01:01.01' MINUTE (5) TO SECOND (5)";
29482948
let select = verified_only_select(sql);
29492949
assert_eq!(
2950-
&Expr::Value(Value::Interval {
2950+
&Expr::Interval {
29512951
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from(
29522952
"01:01.01"
29532953
)))),
29542954
leading_field: Some(DateTimeField::Minute),
29552955
leading_precision: Some(5),
29562956
last_field: Some(DateTimeField::Second),
29572957
fractional_seconds_precision: Some(5),
2958-
}),
2958+
},
29592959
expr_from_projection(only(&select.projection)),
29602960
);
29612961

29622962
let sql = "SELECT INTERVAL '1' SECOND (5, 4)";
29632963
let select = verified_only_select(sql);
29642964
assert_eq!(
2965-
&Expr::Value(Value::Interval {
2965+
&Expr::Interval {
29662966
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("1")))),
29672967
leading_field: Some(DateTimeField::Second),
29682968
leading_precision: Some(5),
29692969
last_field: None,
29702970
fractional_seconds_precision: Some(4),
2971-
}),
2971+
},
29722972
expr_from_projection(only(&select.projection)),
29732973
);
29742974

29752975
let sql = "SELECT INTERVAL '10' HOUR";
29762976
let select = verified_only_select(sql);
29772977
assert_eq!(
2978-
&Expr::Value(Value::Interval {
2978+
&Expr::Interval {
29792979
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("10")))),
29802980
leading_field: Some(DateTimeField::Hour),
29812981
leading_precision: None,
29822982
last_field: None,
29832983
fractional_seconds_precision: None,
2984-
}),
2984+
},
29852985
expr_from_projection(only(&select.projection)),
29862986
);
29872987

29882988
let sql = "SELECT INTERVAL 5 DAY";
29892989
let select = verified_only_select(sql);
29902990
assert_eq!(
2991-
&Expr::Value(Value::Interval {
2991+
&Expr::Interval {
29922992
value: Box::new(Expr::Value(number("5"))),
29932993
leading_field: Some(DateTimeField::Day),
29942994
leading_precision: None,
29952995
last_field: None,
29962996
fractional_seconds_precision: None,
2997-
}),
2997+
},
29982998
expr_from_projection(only(&select.projection)),
29992999
);
30003000

30013001
let sql = "SELECT INTERVAL 1 + 1 DAY";
30023002
let select = verified_only_select(sql);
30033003
assert_eq!(
3004-
&Expr::Value(Value::Interval {
3004+
&Expr::Interval {
30053005
value: Box::new(Expr::BinaryOp {
30063006
left: Box::new(Expr::Value(number("1"))),
30073007
op: BinaryOperator::Plus,
@@ -3011,35 +3011,35 @@ fn parse_literal_interval() {
30113011
leading_precision: None,
30123012
last_field: None,
30133013
fractional_seconds_precision: None,
3014-
}),
3014+
},
30153015
expr_from_projection(only(&select.projection)),
30163016
);
30173017

30183018
let sql = "SELECT INTERVAL '10' HOUR (1)";
30193019
let select = verified_only_select(sql);
30203020
assert_eq!(
3021-
&Expr::Value(Value::Interval {
3021+
&Expr::Interval {
30223022
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("10")))),
30233023
leading_field: Some(DateTimeField::Hour),
30243024
leading_precision: Some(1),
30253025
last_field: None,
30263026
fractional_seconds_precision: None,
3027-
}),
3027+
},
30283028
expr_from_projection(only(&select.projection)),
30293029
);
30303030

30313031
let sql = "SELECT INTERVAL '1 DAY'";
30323032
let select = verified_only_select(sql);
30333033
assert_eq!(
3034-
&Expr::Value(Value::Interval {
3034+
&Expr::Interval {
30353035
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from(
30363036
"1 DAY"
30373037
)))),
30383038
leading_field: None,
30393039
leading_precision: None,
30403040
last_field: None,
30413041
fractional_seconds_precision: None,
3042-
}),
3042+
},
30433043
expr_from_projection(only(&select.projection)),
30443044
);
30453045

0 commit comments

Comments
 (0)