1use crate::fuzz_sql::{SQLExpr, SQLJoin, SQLSelect, SQLSubqueryAlias};
16use crate::SQLRelation;
17use datafusion::common::Result;
18
19pub fn plan_to_sql(plan: &SQLRelation, indent: usize) -> Result<String> {
21 let indent_str = " ".repeat(indent);
22 match plan {
23 SQLRelation::Select(SQLSelect {
24 projection,
25 filter,
26 input,
27 }) => {
28 let expr: Vec<String> = projection
29 .iter()
30 .map(|e| expr_to_sql(e, indent))
31 .collect::<Result<Vec<_>>>()?;
32 let input = plan_to_sql(input, indent + 1)?;
33 let where_clause = if let Some(predicate) = filter {
34 let predicate = expr_to_sql(predicate, indent)?;
35 format!("\n{}WHERE {}", indent_str, predicate)
36 } else {
37 "".to_string()
38 };
39 Ok(format!(
40 "SELECT {}\n{}FROM ({}){}",
41 expr.join(", "),
42 indent_str,
43 input,
44 where_clause
45 ))
46 }
47 SQLRelation::TableScan(scan) => Ok(scan.table_name.clone()),
48 SQLRelation::Join(SQLJoin {
49 left,
50 right,
51 on,
52 join_type,
53 ..
54 }) => {
55 let l = plan_to_sql(left, indent + 1)?;
56 let r = plan_to_sql(right, indent + 1)?;
57 let join_condition = on
58 .iter()
59 .map(|(l, r)| format!("{} = {}", l.flat_name(), r.flat_name()))
60 .collect::<Vec<_>>()
61 .join(" AND ");
62 Ok(format!(
63 "\n{}({})\n{}{} JOIN\n{}({})\n{}ON {}",
64 indent_str,
65 l,
66 indent_str,
67 join_type.to_string().to_uppercase(),
68 indent_str,
69 r,
70 indent_str,
71 join_condition
72 ))
73 }
74 SQLRelation::SubqueryAlias(SQLSubqueryAlias { input, alias, .. }) => {
75 let sql = plan_to_sql(input, indent + 1)?;
76 Ok(format!("({}) {}", sql, alias))
77 }
78 }
79}
80
81fn expr_to_sql(expr: &SQLExpr, indent: usize) -> Result<String> {
83 Ok(match expr {
84 SQLExpr::Alias { expr, alias } => format!("{} AS {}", expr_to_sql(expr, indent)?, alias),
85 SQLExpr::Column(col) => col.flat_name(),
86 SQLExpr::BinaryExpr { left, op, right } => {
87 let l = expr_to_sql(left, indent)?;
88 let r = expr_to_sql(right, indent)?;
89 format!("{} {} {}", l, op, r)
90 }
91 SQLExpr::Exists { subquery, negated } => {
92 let sql = plan_to_sql(&SQLRelation::Select(subquery.as_ref().clone()), indent)?;
93 if *negated {
94 format!("NOT EXISTS ({})", sql)
95 } else {
96 format!("EXISTS ({})", sql)
97 }
98 }
99 })
100}