Skip to content

Commit 097e7ad

Browse files
eitsupialamb
andauthored
feat: Support MySQL's DIV operator (apache#876)
* feat: MySQL's DIV operator * fix: do not use `_` prefix for used variable --------- Co-authored-by: Andrew Lamb <[email protected]>
1 parent feaa13c commit 097e7ad

File tree

5 files changed

+38
-1
lines changed

5 files changed

+38
-1
lines changed

src/ast/operator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ pub enum BinaryOperator {
8585
BitwiseOr,
8686
BitwiseAnd,
8787
BitwiseXor,
88+
/// MySQL [`DIV`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html) integer division
89+
MyIntegerDivide,
8890
/// Support for custom operators (built by parsers outside this crate)
8991
Custom(String),
9092
PGBitwiseXor,
@@ -124,6 +126,7 @@ impl fmt::Display for BinaryOperator {
124126
BinaryOperator::BitwiseOr => f.write_str("|"),
125127
BinaryOperator::BitwiseAnd => f.write_str("&"),
126128
BinaryOperator::BitwiseXor => f.write_str("^"),
129+
BinaryOperator::MyIntegerDivide => f.write_str("DIV"),
127130
BinaryOperator::Custom(s) => f.write_str(s),
128131
BinaryOperator::PGBitwiseXor => f.write_str("#"),
129132
BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"),

src/dialect/mysql.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@
1010
// See the License for the specific language governing permissions and
1111
// limitations under the License.
1212

13-
use crate::dialect::Dialect;
13+
#[cfg(not(feature = "std"))]
14+
use alloc::boxed::Box;
15+
16+
use crate::{
17+
ast::{BinaryOperator, Expr},
18+
dialect::Dialect,
19+
keywords::Keyword,
20+
};
1421

1522
/// [MySQL](https://www.mysql.com/)
1623
#[derive(Debug)]
@@ -35,4 +42,22 @@ impl Dialect for MySqlDialect {
3542
fn is_delimited_identifier_start(&self, ch: char) -> bool {
3643
ch == '`'
3744
}
45+
46+
fn parse_infix(
47+
&self,
48+
parser: &mut crate::parser::Parser,
49+
expr: &crate::ast::Expr,
50+
_precedence: u8,
51+
) -> Option<Result<crate::ast::Expr, crate::parser::ParserError>> {
52+
// Parse DIV as an operator
53+
if parser.parse_keyword(Keyword::DIV) {
54+
Some(Ok(Expr::BinaryOp {
55+
left: Box::new(expr.clone()),
56+
op: BinaryOperator::MyIntegerDivide,
57+
right: Box::new(parser.parse_expr().unwrap()),
58+
}))
59+
} else {
60+
None
61+
}
62+
}
3863
}

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ define_keywords!(
211211
DISCONNECT,
212212
DISTINCT,
213213
DISTRIBUTE,
214+
DIV,
214215
DO,
215216
DOUBLE,
216217
DOW,

src/parser.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,6 +1982,8 @@ impl<'a> Parser<'a> {
19821982
const AND_PREC: u8 = 10;
19831983
const OR_PREC: u8 = 5;
19841984

1985+
const DIV_OP_PREC: u8 = 40;
1986+
19851987
/// Get the precedence of the next token
19861988
pub fn get_next_precedence(&self) -> Result<u8, ParserError> {
19871989
// allow the dialect to override precedence logic
@@ -2031,6 +2033,7 @@ impl<'a> Parser<'a> {
20312033
Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(Self::LIKE_PREC),
20322034
Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(Self::LIKE_PREC),
20332035
Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(Self::BETWEEN_PREC),
2036+
Token::Word(w) if w.keyword == Keyword::DIV => Ok(Self::DIV_OP_PREC),
20342037
Token::Eq
20352038
| Token::Lt
20362039
| Token::LtEq

tests/sqlparser_mysql.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,3 +1407,8 @@ fn parse_string_introducers() {
14071407
mysql().one_statement_parses_to("SELECT _utf8mb4'abc'", "SELECT _utf8mb4 'abc'");
14081408
mysql().verified_stmt("SELECT _binary 'abc', _utf8mb4 'abc'");
14091409
}
1410+
1411+
#[test]
1412+
fn parse_div_infix() {
1413+
mysql().verified_stmt(r#"SELECT 5 DIV 2"#);
1414+
}

0 commit comments

Comments
 (0)