Skip to content

Commit 7ad8868

Browse files
committed
Add support for MySQL MEMBER OF
1 parent 9ffc546 commit 7ad8868

File tree

5 files changed

+28
-0
lines changed

5 files changed

+28
-0
lines changed

src/ast/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,14 @@ pub enum Expr {
11241124
/// [Databricks](https://docs.databricks.com/en/sql/language-manual/sql-ref-lambda-functions.html)
11251125
/// [DuckDb](https://duckdb.org/docs/sql/functions/lambda.html)
11261126
Lambda(LambdaFunction),
1127+
/// Checks membership of a value in a JSON array
1128+
///
1129+
/// Syntax:
1130+
/// ```sql
1131+
/// <value> MEMBER OF(<array>)
1132+
/// ```
1133+
/// [MySQL](https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html#operator_member-of)
1134+
MemberOf(Box<Expr>, Box<Expr>),
11271135
}
11281136

11291137
impl Expr {
@@ -1912,6 +1920,7 @@ impl fmt::Display for Expr {
19121920
}
19131921
Expr::Prior(expr) => write!(f, "PRIOR {expr}"),
19141922
Expr::Lambda(lambda) => write!(f, "{lambda}"),
1923+
Expr::MemberOf(value, array) => write!(f, "{} MEMBER OF({})", value, array),
19151924
}
19161925
}
19171926
}

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,7 @@ impl Spanned for Expr {
16191619
Expr::OuterJoin(expr) => expr.span(),
16201620
Expr::Prior(expr) => expr.span(),
16211621
Expr::Lambda(_) => Span::empty(),
1622+
Expr::MemberOf(value, array) => value.span().union(&array.span()),
16221623
}
16231624
}
16241625
}

src/dialect/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ pub trait Dialect: Debug + Any {
649649
Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
650650
Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
651651
Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
652+
Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
652653
_ => Ok(self.prec_unknown()),
653654
},
654655
Token::Word(w) if w.keyword == Keyword::IS => Ok(p!(Is)),
@@ -661,6 +662,7 @@ pub trait Dialect: Debug + Any {
661662
Token::Word(w) if w.keyword == Keyword::REGEXP => Ok(p!(Like)),
662663
Token::Word(w) if w.keyword == Keyword::MATCH => Ok(p!(Like)),
663664
Token::Word(w) if w.keyword == Keyword::SIMILAR => Ok(p!(Like)),
665+
Token::Word(w) if w.keyword == Keyword::MEMBER => Ok(p!(Like)),
664666
Token::Word(w) if w.keyword == Keyword::OPERATOR => Ok(p!(Between)),
665667
Token::Word(w) if w.keyword == Keyword::DIV => Ok(p!(MulDivModOp)),
666668
Token::Period => Ok(p!(Period)),

src/parser/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3609,6 +3609,16 @@ impl<'a> Parser<'a> {
36093609
self.expected("IN or BETWEEN after NOT", self.peek_token())
36103610
}
36113611
}
3612+
Keyword::MEMBER => {
3613+
if self.parse_keyword(Keyword::OF) {
3614+
let _ = self.expect_token(&Token::LParen);
3615+
let expr2 = self.parse_expr()?;
3616+
let _ = self.expect_token(&Token::RParen);
3617+
Ok(Expr::MemberOf(Box::new(expr), Box::new(expr2)))
3618+
} else {
3619+
self.expected("OF after MEMBER", self.peek_token())
3620+
}
3621+
}
36123622
// Can only happen if `get_next_precedence` got out of sync with this function
36133623
_ => parser_err!(
36143624
format!("No infix parser for token {:?}", tok.token),

tests/sqlparser_mysql.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4109,3 +4109,9 @@ fn parse_alter_table_drop_index() {
41094109
AlterTableOperation::DropIndex { name } if name.value == "idx_index"
41104110
);
41114111
}
4112+
4113+
#[test]
4114+
fn parse_json_member_of() {
4115+
mysql().verified_stmt(r#"SELECT 17 MEMBER OF('[23, "abc", 17, "ab", 10]')"#);
4116+
mysql().verified_stmt(r#"SELECT 'ab' MEMBER OF('[23, "abc", 17, "ab", 10]')"#);
4117+
}

0 commit comments

Comments
 (0)