Skip to content

Commit bf8142a

Browse files
MohamedAbdeen21findepi
authored andcommitted
Implement prettier SQL unparsing (more human readable) (apache#11186)
* initial prettier unparse * bug fix * handling minus and divide * cleaning references and comments * moved tests * Update precedence of BETWEEN * rerun CI * Change precedence to match PGSQLs * more pretty unparser tests * Update operator precedence to match latest PGSQL * directly prettify expr_to_sql * handle IS operator * correct IS precedence * update unparser tests * update unparser example * update more unparser examples * add with_pretty builder to unparser
1 parent ae5051a commit bf8142a

File tree

6 files changed

+319
-76
lines changed

6 files changed

+319
-76
lines changed

datafusion-examples/examples/parse_sql_expr.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,14 @@ async fn round_trip_parse_sql_expr_demo() -> Result<()> {
153153

154154
assert_eq!(sql, round_trip_sql);
155155

156+
// enable pretty-unparsing. This make the output more human-readable
157+
// but can be problematic when passed to other SQL engines due to
158+
// difference in precedence rules between DataFusion and target engines.
159+
let unparser = Unparser::default().with_pretty(true);
160+
161+
let pretty = "int_col < 5 OR double_col = 8";
162+
let pretty_round_trip_sql = unparser.expr_to_sql(&parsed_expr)?.to_string();
163+
assert_eq!(pretty, pretty_round_trip_sql);
164+
156165
Ok(())
157166
}

datafusion-examples/examples/plan_to_sql.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ use datafusion_sql::unparser::{plan_to_sql, Unparser};
3131
/// 1. [`simple_expr_to_sql_demo`]: Create a simple expression [`Exprs`] with
3232
/// fluent API and convert to sql suitable for passing to another database
3333
///
34-
/// 2. [`simple_expr_to_sql_demo_no_escape`] Create a simple expression
35-
/// [`Exprs`] with fluent API and convert to sql without escaping column names
36-
/// more suitable for displaying to humans.
34+
/// 2. [`simple_expr_to_pretty_sql_demo`] Create a simple expression
35+
/// [`Exprs`] with fluent API and convert to sql without extra parentheses,
36+
/// suitable for displaying to humans
3737
///
3838
/// 3. [`simple_expr_to_sql_demo_escape_mysql_style`]" Create a simple
3939
/// expression [`Exprs`] with fluent API and convert to sql escaping column
@@ -49,6 +49,7 @@ use datafusion_sql::unparser::{plan_to_sql, Unparser};
4949
async fn main() -> Result<()> {
5050
// See how to evaluate expressions
5151
simple_expr_to_sql_demo()?;
52+
simple_expr_to_pretty_sql_demo()?;
5253
simple_expr_to_sql_demo_escape_mysql_style()?;
5354
simple_plan_to_sql_demo().await?;
5455
round_trip_plan_to_sql_demo().await?;
@@ -64,6 +65,17 @@ fn simple_expr_to_sql_demo() -> Result<()> {
6465
Ok(())
6566
}
6667

68+
/// DataFusioon can remove parentheses when converting an expression to SQL.
69+
/// Note that output is intended for humans, not for other SQL engines,
70+
/// as difference in precedence rules can cause expressions to be parsed differently.
71+
fn simple_expr_to_pretty_sql_demo() -> Result<()> {
72+
let expr = col("a").lt(lit(5)).or(col("a").eq(lit(8)));
73+
let unparser = Unparser::default().with_pretty(true);
74+
let sql = unparser.expr_to_sql(&expr)?.to_string();
75+
assert_eq!(sql, r#"a < 5 OR a = 8"#);
76+
Ok(())
77+
}
78+
6779
/// DataFusion can convert expressions to SQL without escaping column names using
6880
/// using a custom dialect and an explicit unparser
6981
fn simple_expr_to_sql_demo_escape_mysql_style() -> Result<()> {

datafusion/expr/src/operator.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -218,37 +218,33 @@ impl Operator {
218218
}
219219

220220
/// Get the operator precedence
221-
/// use <https://www.postgresql.org/docs/7.0/operators.htm#AEN2026> as a reference
221+
/// use <https://www.postgresql.org/docs/7.2/sql-precedence.html> as a reference
222222
pub fn precedence(&self) -> u8 {
223223
match self {
224224
Operator::Or => 5,
225225
Operator::And => 10,
226-
Operator::NotEq
227-
| Operator::Eq
228-
| Operator::Lt
229-
| Operator::LtEq
230-
| Operator::Gt
231-
| Operator::GtEq => 20,
232-
Operator::Plus | Operator::Minus => 30,
233-
Operator::Multiply | Operator::Divide | Operator::Modulo => 40,
226+
Operator::Eq | Operator::NotEq | Operator::LtEq | Operator::GtEq => 15,
227+
Operator::Lt | Operator::Gt => 20,
228+
Operator::LikeMatch
229+
| Operator::NotLikeMatch
230+
| Operator::ILikeMatch
231+
| Operator::NotILikeMatch => 25,
234232
Operator::IsDistinctFrom
235233
| Operator::IsNotDistinctFrom
236234
| Operator::RegexMatch
237235
| Operator::RegexNotMatch
238236
| Operator::RegexIMatch
239237
| Operator::RegexNotIMatch
240-
| Operator::LikeMatch
241-
| Operator::ILikeMatch
242-
| Operator::NotLikeMatch
243-
| Operator::NotILikeMatch
244238
| Operator::BitwiseAnd
245239
| Operator::BitwiseOr
246240
| Operator::BitwiseShiftLeft
247241
| Operator::BitwiseShiftRight
248242
| Operator::BitwiseXor
249243
| Operator::StringConcat
250244
| Operator::AtArrow
251-
| Operator::ArrowAt => 0,
245+
| Operator::ArrowAt => 30,
246+
Operator::Plus | Operator::Minus => 40,
247+
Operator::Multiply | Operator::Divide | Operator::Modulo => 45,
252248
}
253249
}
254250
}

0 commit comments

Comments
 (0)