feat: Support MySQL's DIV operator (#876)

* feat: MySQL's DIV operator

* fix: do not use `_` prefix for used variable

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
eitsupi 2023-05-18 02:26:14 +09:00 committed by GitHub
parent feaa13c9a9
commit 097e7ad56e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 38 additions and 1 deletions

View file

@ -85,6 +85,8 @@ pub enum BinaryOperator {
BitwiseOr, BitwiseOr,
BitwiseAnd, BitwiseAnd,
BitwiseXor, 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) /// Support for custom operators (built by parsers outside this crate)
Custom(String), Custom(String),
PGBitwiseXor, PGBitwiseXor,
@ -124,6 +126,7 @@ impl fmt::Display for BinaryOperator {
BinaryOperator::BitwiseOr => f.write_str("|"), BinaryOperator::BitwiseOr => f.write_str("|"),
BinaryOperator::BitwiseAnd => f.write_str("&"), BinaryOperator::BitwiseAnd => f.write_str("&"),
BinaryOperator::BitwiseXor => f.write_str("^"), BinaryOperator::BitwiseXor => f.write_str("^"),
BinaryOperator::MyIntegerDivide => f.write_str("DIV"),
BinaryOperator::Custom(s) => f.write_str(s), BinaryOperator::Custom(s) => f.write_str(s),
BinaryOperator::PGBitwiseXor => f.write_str("#"), BinaryOperator::PGBitwiseXor => f.write_str("#"),
BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"), BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"),

View file

@ -10,7 +10,14 @@
// 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.
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/) /// [MySQL](https://www.mysql.com/)
#[derive(Debug)] #[derive(Debug)]
@ -35,4 +42,22 @@ impl Dialect for MySqlDialect {
fn is_delimited_identifier_start(&self, ch: char) -> bool { fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '`' ch == '`'
} }
fn parse_infix(
&self,
parser: &mut crate::parser::Parser,
expr: &crate::ast::Expr,
_precedence: u8,
) -> Option<Result<crate::ast::Expr, crate::parser::ParserError>> {
// 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
}
}
} }

View file

@ -211,6 +211,7 @@ define_keywords!(
DISCONNECT, DISCONNECT,
DISTINCT, DISTINCT,
DISTRIBUTE, DISTRIBUTE,
DIV,
DO, DO,
DOUBLE, DOUBLE,
DOW, DOW,

View file

@ -1982,6 +1982,8 @@ impl<'a> Parser<'a> {
const AND_PREC: u8 = 10; const AND_PREC: u8 = 10;
const OR_PREC: u8 = 5; const OR_PREC: u8 = 5;
const DIV_OP_PREC: u8 = 40;
/// Get the precedence of the next token /// Get the precedence of the next token
pub fn get_next_precedence(&self) -> Result<u8, ParserError> { pub fn get_next_precedence(&self) -> Result<u8, ParserError> {
// allow the dialect to override precedence logic // 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::ILIKE => Ok(Self::LIKE_PREC),
Token::Word(w) if w.keyword == Keyword::SIMILAR => 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::OPERATOR => Ok(Self::BETWEEN_PREC),
Token::Word(w) if w.keyword == Keyword::DIV => Ok(Self::DIV_OP_PREC),
Token::Eq Token::Eq
| Token::Lt | Token::Lt
| Token::LtEq | Token::LtEq

View file

@ -1407,3 +1407,8 @@ fn parse_string_introducers() {
mysql().one_statement_parses_to("SELECT _utf8mb4'abc'", "SELECT _utf8mb4 'abc'"); mysql().one_statement_parses_to("SELECT _utf8mb4'abc'", "SELECT _utf8mb4 'abc'");
mysql().verified_stmt("SELECT _binary 'abc', _utf8mb4 'abc'"); mysql().verified_stmt("SELECT _binary 'abc', _utf8mb4 'abc'");
} }
#[test]
fn parse_div_infix() {
mysql().verified_stmt(r#"SELECT 5 DIV 2"#);
}