diff --git a/src/ast/operator.rs b/src/ast/operator.rs index 14d91362..0ab9c66a 100644 --- a/src/ast/operator.rs +++ b/src/ast/operator.rs @@ -85,6 +85,8 @@ pub enum BinaryOperator { BitwiseOr, BitwiseAnd, BitwiseXor, + /// MySQL [`DIV`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html) integer division + MyIntegerDivide, /// Support for custom operators (built by parsers outside this crate) Custom(String), PGBitwiseXor, @@ -124,6 +126,7 @@ impl fmt::Display for BinaryOperator { BinaryOperator::BitwiseOr => f.write_str("|"), BinaryOperator::BitwiseAnd => f.write_str("&"), BinaryOperator::BitwiseXor => f.write_str("^"), + BinaryOperator::MyIntegerDivide => f.write_str("DIV"), BinaryOperator::Custom(s) => f.write_str(s), BinaryOperator::PGBitwiseXor => f.write_str("#"), BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"), diff --git a/src/dialect/mysql.rs b/src/dialect/mysql.rs index ceab3481..0f914ed0 100644 --- a/src/dialect/mysql.rs +++ b/src/dialect/mysql.rs @@ -10,7 +10,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::dialect::Dialect; +#[cfg(not(feature = "std"))] +use alloc::boxed::Box; + +use crate::{ + ast::{BinaryOperator, Expr}, + dialect::Dialect, + keywords::Keyword, +}; /// [MySQL](https://www.mysql.com/) #[derive(Debug)] @@ -35,4 +42,22 @@ impl Dialect for MySqlDialect { fn is_delimited_identifier_start(&self, ch: char) -> bool { ch == '`' } + + fn parse_infix( + &self, + parser: &mut crate::parser::Parser, + expr: &crate::ast::Expr, + _precedence: u8, + ) -> Option> { + // Parse DIV as an operator + if parser.parse_keyword(Keyword::DIV) { + Some(Ok(Expr::BinaryOp { + left: Box::new(expr.clone()), + op: BinaryOperator::MyIntegerDivide, + right: Box::new(parser.parse_expr().unwrap()), + })) + } else { + None + } + } } diff --git a/src/keywords.rs b/src/keywords.rs index a0c5b68c..6132b31f 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -211,6 +211,7 @@ define_keywords!( DISCONNECT, DISTINCT, DISTRIBUTE, + DIV, DO, DOUBLE, DOW, diff --git a/src/parser.rs b/src/parser.rs index 45639eef..af577ce5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1982,6 +1982,8 @@ impl<'a> Parser<'a> { const AND_PREC: u8 = 10; const OR_PREC: u8 = 5; + const DIV_OP_PREC: u8 = 40; + /// Get the precedence of the next token pub fn get_next_precedence(&self) -> Result { // allow the dialect to override precedence logic @@ -2031,6 +2033,7 @@ impl<'a> Parser<'a> { Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(Self::LIKE_PREC), Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(Self::LIKE_PREC), Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(Self::BETWEEN_PREC), + Token::Word(w) if w.keyword == Keyword::DIV => Ok(Self::DIV_OP_PREC), Token::Eq | Token::Lt | Token::LtEq diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 1c479bb1..c70f2cb9 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -1407,3 +1407,8 @@ fn parse_string_introducers() { mysql().one_statement_parses_to("SELECT _utf8mb4'abc'", "SELECT _utf8mb4 'abc'"); mysql().verified_stmt("SELECT _binary 'abc', _utf8mb4 'abc'"); } + +#[test] +fn parse_div_infix() { + mysql().verified_stmt(r#"SELECT 5 DIV 2"#); +}