-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat(unparser): support DISTINCT FROM operators in the MySQL dialect #22999
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,7 +30,7 @@ use std::sync::Arc; | |
| use std::vec; | ||
|
|
||
| use super::Unparser; | ||
| use super::dialect::IntervalStyle; | ||
| use super::dialect::{DistinctFromStyle, IntervalStyle}; | ||
| use arrow::array::{ | ||
| ArrayRef, Date32Array, Date64Array, PrimitiveArray, | ||
| types::{ | ||
|
|
@@ -156,10 +156,23 @@ impl Unparser<'_> { | |
| let l = self.expr_to_sql_inner(left.as_ref())?; | ||
| let r = self.expr_to_sql_inner(right.as_ref())?; | ||
|
|
||
| Ok(ast::Expr::Nested(Box::new(ast::Expr::IsDistinctFrom( | ||
| Box::new(l), | ||
| Box::new(r), | ||
| )))) | ||
| match self.dialect.distinct_from_style() { | ||
| DistinctFromStyle::FullText => Ok(ast::Expr::Nested(Box::new( | ||
| ast::Expr::IsDistinctFrom(Box::new(l), Box::new(r)), | ||
| ))), | ||
| DistinctFromStyle::Spaceship => { | ||
| Ok(ast::Expr::Nested(Box::new(ast::Expr::UnaryOp { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the MySQL spelling for IS DISTINCT FROM needs to force the <=> comparison to be parsed as the operand of NOT. As written, NOT <=> can be ambiguous with MySQL HIGH_NOT_PRECEDENCE, where NOT a <=> b may be parsed as (NOT a) <=> b. That is not equivalent to a IS DISTINCT FROM b. Could this build the unary expression over a nested spaceship comparison instead? For example: NOT (
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, I have added |
||
| op: UnaryOperator::Not, | ||
| expr: Box::new(ast::Expr::Nested(Box::new( | ||
| ast::Expr::BinaryOp { | ||
| left: Box::new(l), | ||
| right: Box::new(r), | ||
| op: BinaryOperator::Spaceship, | ||
| }, | ||
| ))), | ||
| }))) | ||
| } | ||
| } | ||
| } | ||
| Expr::BinaryExpr(BinaryExpr { | ||
| left, | ||
|
|
@@ -169,10 +182,18 @@ impl Unparser<'_> { | |
| let l = self.expr_to_sql_inner(left.as_ref())?; | ||
| let r = self.expr_to_sql_inner(right.as_ref())?; | ||
|
|
||
| Ok(ast::Expr::Nested(Box::new(ast::Expr::IsNotDistinctFrom( | ||
| Box::new(l), | ||
| Box::new(r), | ||
| )))) | ||
| match self.dialect.distinct_from_style() { | ||
| DistinctFromStyle::FullText => Ok(ast::Expr::Nested(Box::new( | ||
| ast::Expr::IsNotDistinctFrom(Box::new(l), Box::new(r)), | ||
| ))), | ||
| DistinctFromStyle::Spaceship => { | ||
| Ok(ast::Expr::Nested(Box::new(ast::Expr::BinaryOp { | ||
| left: Box::new(l), | ||
| right: Box::new(r), | ||
| op: BinaryOperator::Spaceship, | ||
| }))) | ||
| } | ||
| } | ||
| } | ||
| Expr::BinaryExpr(BinaryExpr { left, op, right }) => { | ||
| let l = self.expr_to_sql_inner(left.as_ref())?; | ||
|
|
@@ -1908,7 +1929,7 @@ mod tests { | |
| use std::ops::{Add, Sub}; | ||
| use std::{sync::Arc, vec}; | ||
|
|
||
| use crate::unparser::dialect::SqliteDialect; | ||
| use crate::unparser::dialect::{MySqlDialect, SqliteDialect}; | ||
| use arrow::array::{LargeListArray, LargeListViewArray, ListArray, ListViewArray}; | ||
| use arrow::datatypes::{DataType::Int8, Field, Int32Type, Schema, TimeUnit}; | ||
| use ast::ObjectName; | ||
|
|
@@ -3714,6 +3735,8 @@ mod tests { | |
|
|
||
| #[test] | ||
| fn test_is_distinct_from() { | ||
| let mysql_unparser = Unparser::new(&MySqlDialect {}); | ||
|
|
||
| let expr = Expr::BinaryExpr(BinaryExpr::new( | ||
| Box::new(col("c1")), | ||
| Operator::IsDistinctFrom, | ||
|
|
@@ -3722,6 +3745,8 @@ mod tests { | |
|
|
||
| let sql = expr_to_sql(&expr).unwrap().to_string(); | ||
| assert_eq!(sql, "(c1 IS DISTINCT FROM true)"); | ||
| let sql = mysql_unparser.expr_to_sql(&expr).unwrap().to_string(); | ||
| assert_eq!(sql, "(NOT (`c1` <=> true))"); | ||
|
|
||
| let expr = Expr::BinaryExpr(BinaryExpr::new( | ||
| Box::new(col("c1")), | ||
|
|
@@ -3731,6 +3756,8 @@ mod tests { | |
|
|
||
| let sql = expr_to_sql(&expr).unwrap().to_string(); | ||
| assert_eq!(sql, "(c1 IS NOT DISTINCT FROM true)"); | ||
| let sql = mysql_unparser.expr_to_sql(&expr).unwrap().to_string(); | ||
| assert_eq!(sql, "(`c1` <=> true)"); | ||
| } | ||
|
|
||
| #[test] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this new default changes existing behavior for downstream and custom dialects. Before this PR, a Dialect that did not override this area could still unparse IS DISTINCT FROM and IS NOT DISTINCT FROM using the standard full-text syntax.
With the default now set to Unsupported, those same dialects can start returning not_impl_err! for expressions that previously worked. The MySQL fix only needs a MySQL-specific override, so I think the trait default should preserve the old behavior. For example, this could default to DistinctFromStyle::FullText and only dialects that need a different spelling would override it.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I have therefore removed the
Unsupportedenum variant