mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-11 17:58:00 +00:00
fix: Support expr
instead of string
for argument to interval
(#517)
* fix: use expr instead of string in interval * chore: resolve CI Co-authored-by: togami2864 <yoshiaki.togami@plaid.co.jp>
This commit is contained in:
parent
99697d26e1
commit
d981f70143
3 changed files with 52 additions and 15 deletions
|
@ -10,6 +10,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
use alloc::boxed::Box;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
@ -19,6 +21,8 @@ use bigdecimal::BigDecimal;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::Expr;
|
||||||
|
|
||||||
/// Primitive SQL values such as number and string
|
/// Primitive SQL values such as number and string
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
@ -50,7 +54,7 @@ pub enum Value {
|
||||||
/// that the `<leading_field>` units >= the units in `<last_field>`,
|
/// that the `<leading_field>` units >= the units in `<last_field>`,
|
||||||
/// so the user will have to reject intervals like `HOUR TO YEAR`.
|
/// so the user will have to reject intervals like `HOUR TO YEAR`.
|
||||||
Interval {
|
Interval {
|
||||||
value: String,
|
value: Box<Expr>,
|
||||||
leading_field: Option<DateTimeField>,
|
leading_field: Option<DateTimeField>,
|
||||||
leading_precision: Option<u64>,
|
leading_precision: Option<u64>,
|
||||||
last_field: Option<DateTimeField>,
|
last_field: Option<DateTimeField>,
|
||||||
|
@ -88,10 +92,8 @@ impl fmt::Display for Value {
|
||||||
assert!(last_field.is_none());
|
assert!(last_field.is_none());
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"INTERVAL '{}' SECOND ({}, {})",
|
"INTERVAL {} SECOND ({}, {})",
|
||||||
escape_single_quote_string(value),
|
value, leading_precision, fractional_seconds_precision
|
||||||
leading_precision,
|
|
||||||
fractional_seconds_precision
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Value::Interval {
|
Value::Interval {
|
||||||
|
@ -101,7 +103,7 @@ impl fmt::Display for Value {
|
||||||
last_field,
|
last_field,
|
||||||
fractional_seconds_precision,
|
fractional_seconds_precision,
|
||||||
} => {
|
} => {
|
||||||
write!(f, "INTERVAL '{}'", escape_single_quote_string(value))?;
|
write!(f, "INTERVAL {}", value)?;
|
||||||
if let Some(leading_field) = leading_field {
|
if let Some(leading_field) = leading_field {
|
||||||
write!(f, " {}", leading_field)?;
|
write!(f, " {}", leading_field)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -994,6 +994,7 @@ impl<'a> Parser<'a> {
|
||||||
/// 4. `INTERVAL '1:1:1.1' HOUR (5) TO SECOND (5)`
|
/// 4. `INTERVAL '1:1:1.1' HOUR (5) TO SECOND (5)`
|
||||||
/// 5. `INTERVAL '1.1' SECOND (2, 2)`
|
/// 5. `INTERVAL '1.1' SECOND (2, 2)`
|
||||||
/// 6. `INTERVAL '1:1' HOUR (5) TO MINUTE (5)`
|
/// 6. `INTERVAL '1:1' HOUR (5) TO MINUTE (5)`
|
||||||
|
/// 7. (MySql and BigQuey only):`INTERVAL 1 DAY`
|
||||||
///
|
///
|
||||||
/// Note that we do not currently attempt to parse the quoted value.
|
/// Note that we do not currently attempt to parse the quoted value.
|
||||||
pub fn parse_literal_interval(&mut self) -> Result<Expr, ParserError> {
|
pub fn parse_literal_interval(&mut self) -> Result<Expr, ParserError> {
|
||||||
|
@ -1004,13 +1005,13 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// The first token in an interval is a string literal which specifies
|
// The first token in an interval is a string literal which specifies
|
||||||
// the duration of the interval.
|
// the duration of the interval.
|
||||||
let value = self.parse_literal_string()?;
|
let value = self.parse_expr()?;
|
||||||
|
|
||||||
// Following the string literal is a qualifier which indicates the units
|
// Following the string literal is a qualifier which indicates the units
|
||||||
// of the duration specified in the string literal.
|
// of the duration specified in the string literal.
|
||||||
//
|
//
|
||||||
// Note that PostgreSQL allows omitting the qualifier, so we provide
|
// Note that PostgreSQL allows omitting the qualifier, so we provide
|
||||||
// this more general implemenation.
|
// this more general implementation.
|
||||||
let leading_field = match self.peek_token() {
|
let leading_field = match self.peek_token() {
|
||||||
Token::Word(kw)
|
Token::Word(kw)
|
||||||
if [
|
if [
|
||||||
|
@ -1071,7 +1072,7 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Expr::Value(Value::Interval {
|
Ok(Expr::Value(Value::Interval {
|
||||||
value,
|
value: Box::new(value),
|
||||||
leading_field,
|
leading_field,
|
||||||
leading_precision,
|
leading_precision,
|
||||||
last_field,
|
last_field,
|
||||||
|
|
|
@ -2649,7 +2649,7 @@ fn parse_literal_interval() {
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::Value(Value::Interval {
|
&Expr::Value(Value::Interval {
|
||||||
value: "1-1".into(),
|
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("1-1")))),
|
||||||
leading_field: Some(DateTimeField::Year),
|
leading_field: Some(DateTimeField::Year),
|
||||||
leading_precision: None,
|
leading_precision: None,
|
||||||
last_field: Some(DateTimeField::Month),
|
last_field: Some(DateTimeField::Month),
|
||||||
|
@ -2662,7 +2662,9 @@ fn parse_literal_interval() {
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::Value(Value::Interval {
|
&Expr::Value(Value::Interval {
|
||||||
value: "01:01.01".into(),
|
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from(
|
||||||
|
"01:01.01"
|
||||||
|
)))),
|
||||||
leading_field: Some(DateTimeField::Minute),
|
leading_field: Some(DateTimeField::Minute),
|
||||||
leading_precision: Some(5),
|
leading_precision: Some(5),
|
||||||
last_field: Some(DateTimeField::Second),
|
last_field: Some(DateTimeField::Second),
|
||||||
|
@ -2675,7 +2677,7 @@ fn parse_literal_interval() {
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::Value(Value::Interval {
|
&Expr::Value(Value::Interval {
|
||||||
value: "1".into(),
|
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("1")))),
|
||||||
leading_field: Some(DateTimeField::Second),
|
leading_field: Some(DateTimeField::Second),
|
||||||
leading_precision: Some(5),
|
leading_precision: Some(5),
|
||||||
last_field: None,
|
last_field: None,
|
||||||
|
@ -2688,7 +2690,7 @@ fn parse_literal_interval() {
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::Value(Value::Interval {
|
&Expr::Value(Value::Interval {
|
||||||
value: "10".into(),
|
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("10")))),
|
||||||
leading_field: Some(DateTimeField::Hour),
|
leading_field: Some(DateTimeField::Hour),
|
||||||
leading_precision: None,
|
leading_precision: None,
|
||||||
last_field: None,
|
last_field: None,
|
||||||
|
@ -2697,11 +2699,41 @@ fn parse_literal_interval() {
|
||||||
expr_from_projection(only(&select.projection)),
|
expr_from_projection(only(&select.projection)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let sql = "SELECT INTERVAL 5 DAY";
|
||||||
|
let select = verified_only_select(sql);
|
||||||
|
assert_eq!(
|
||||||
|
&Expr::Value(Value::Interval {
|
||||||
|
value: Box::new(Expr::Value(number("5"))),
|
||||||
|
leading_field: Some(DateTimeField::Day),
|
||||||
|
leading_precision: None,
|
||||||
|
last_field: None,
|
||||||
|
fractional_seconds_precision: None,
|
||||||
|
}),
|
||||||
|
expr_from_projection(only(&select.projection)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = "SELECT INTERVAL 1 + 1 DAY";
|
||||||
|
let select = verified_only_select(sql);
|
||||||
|
assert_eq!(
|
||||||
|
&Expr::Value(Value::Interval {
|
||||||
|
value: Box::new(Expr::BinaryOp {
|
||||||
|
left: Box::new(Expr::Value(number("1"))),
|
||||||
|
op: BinaryOperator::Plus,
|
||||||
|
right: Box::new(Expr::Value(number("1")))
|
||||||
|
}),
|
||||||
|
leading_field: Some(DateTimeField::Day),
|
||||||
|
leading_precision: None,
|
||||||
|
last_field: None,
|
||||||
|
fractional_seconds_precision: None,
|
||||||
|
}),
|
||||||
|
expr_from_projection(only(&select.projection)),
|
||||||
|
);
|
||||||
|
|
||||||
let sql = "SELECT INTERVAL '10' HOUR (1)";
|
let sql = "SELECT INTERVAL '10' HOUR (1)";
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::Value(Value::Interval {
|
&Expr::Value(Value::Interval {
|
||||||
value: "10".into(),
|
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("10")))),
|
||||||
leading_field: Some(DateTimeField::Hour),
|
leading_field: Some(DateTimeField::Hour),
|
||||||
leading_precision: Some(1),
|
leading_precision: Some(1),
|
||||||
last_field: None,
|
last_field: None,
|
||||||
|
@ -2714,7 +2746,9 @@ fn parse_literal_interval() {
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::Value(Value::Interval {
|
&Expr::Value(Value::Interval {
|
||||||
value: "1 DAY".into(),
|
value: Box::new(Expr::Value(Value::SingleQuotedString(String::from(
|
||||||
|
"1 DAY"
|
||||||
|
)))),
|
||||||
leading_field: None,
|
leading_field: None,
|
||||||
leading_precision: None,
|
leading_precision: None,
|
||||||
last_field: None,
|
last_field: None,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue