diff --git a/examples/cli.rs b/examples/cli.rs index 72f963b1e..40bd447d3 100644 --- a/examples/cli.rs +++ b/examples/cli.rs @@ -31,7 +31,7 @@ Usage: $ cargo run --example cli FILENAME.sql [--dialectname] To print the parse results as JSON: -$ cargo run --feature json_example --example cli FILENAME.sql [--dialectname] +$ cargo run --features json_example --example cli FILENAME.sql [--dialectname] "#, ); diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index df3022adc..986689a05 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -482,6 +482,7 @@ pub trait Dialect: Debug + Any { Precedence::UnaryNot => 15, Precedence::And => 10, Precedence::Or => 5, + Precedence::Interval => self.prec_unknown(), } } @@ -522,6 +523,7 @@ pub enum Precedence { UnaryNot, And, Or, + Interval, } impl dyn Dialect { diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index c25a80f67..22444a9ad 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -21,6 +21,8 @@ use crate::tokenizer::Token; #[derive(Debug)] pub struct PostgreSqlDialect {} +// matches +const INTERVAL_COLON_PREC: u8 = 150; const DOUBLE_COLON_PREC: u8 = 140; const BRACKET_PREC: u8 = 130; const COLLATE_PREC: u8 = 120; @@ -136,6 +138,7 @@ impl Dialect for PostgreSqlDialect { fn prec_value(&self, prec: Precedence) -> u8 { match prec { + Precedence::Interval => INTERVAL_COLON_PREC, Precedence::DoubleColon => DOUBLE_COLON_PREC, Precedence::AtTz => AT_TZ_PREC, Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 2632d807a..7266d8609 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -897,7 +897,7 @@ impl<'a> Parser<'a> { } pub fn parse_interval_expr(&mut self) -> Result { - let precedence = self.dialect.prec_unknown(); + let precedence = self.dialect.prec_value(Precedence::Interval); let mut expr = self.parse_prefix()?; loop { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 517e978b4..6a794d70e 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -4955,7 +4955,8 @@ fn parse_interval() { ); let sql = "SELECT INTERVAL 1 + 1 DAY"; - let select = verified_only_select(sql); + let all_except_pg = all_dialects_except(|d| d.is::()); + let select = all_except_pg.verified_only_select(sql); assert_eq!( &Expr::Interval(Interval { value: Box::new(Expr::BinaryOp { diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 2f9fe86c9..1c297f7f1 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -4949,6 +4949,52 @@ fn test_unicode_string_literal() { } } +#[test] +fn interval_precedence_gt() { + let expr = pg().verified_expr("INTERVAL '1 second' > x"); + assert_eq!( + expr, + Expr::BinaryOp { + left: Box::new(Expr::Interval(Interval { + value: Box::new(Expr::Value(Value::SingleQuotedString( + "1 second".to_string() + ))), + leading_field: None, + leading_precision: None, + last_field: None, + fractional_seconds_precision: None, + },)), + op: BinaryOperator::Gt, + right: Box::new(Expr::Identifier(Ident { + value: "x".to_string(), + quote_style: None, + })), + } + ) +} + +#[test] +fn interval_precedence_double_colon() { + let expr = pg().verified_expr("INTERVAL '1 second'::TEXT"); + assert_eq!( + expr, + Expr::Cast { + kind: CastKind::DoubleColon, + expr: Box::new(Expr::Interval(Interval { + value: Box::new(Expr::Value(Value::SingleQuotedString( + "1 second".to_string() + ))), + leading_field: None, + leading_precision: None, + last_field: None, + fractional_seconds_precision: None, + })), + data_type: DataType::Text, + format: None, + } + ) +} + fn check_arrow_precedence(sql: &str, arrow_operator: BinaryOperator) { assert_eq!( pg().verified_expr(sql),