in datafusion/sql/src/unparser/expr.rs [98:518]
fn expr_to_sql_inner(&self, expr: &Expr) -> Result<ast::Expr> {
match expr {
Expr::InList(InList {
expr,
list,
negated,
}) => {
let list_expr = list
.iter()
.map(|e| self.expr_to_sql_inner(e))
.collect::<Result<Vec<_>>>()?;
Ok(ast::Expr::InList {
expr: Box::new(self.expr_to_sql_inner(expr)?),
list: list_expr,
negated: *negated,
})
}
Expr::ScalarFunction(ScalarFunction { func, args }) => {
let func_name = func.name();
if let Some(expr) = self
.dialect
.scalar_function_to_sql_overrides(self, func_name, args)?
{
return Ok(expr);
}
self.scalar_function_to_sql(func_name, args)
}
Expr::Between(Between {
expr,
negated,
low,
high,
}) => {
let sql_parser_expr = self.expr_to_sql_inner(expr)?;
let sql_low = self.expr_to_sql_inner(low)?;
let sql_high = self.expr_to_sql_inner(high)?;
Ok(ast::Expr::Nested(Box::new(self.between_op_to_sql(
sql_parser_expr,
*negated,
sql_low,
sql_high,
))))
}
Expr::Column(col) => self.col_to_sql(col),
Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
let l = self.expr_to_sql_inner(left.as_ref())?;
let r = self.expr_to_sql_inner(right.as_ref())?;
let op = self.op_to_sql(op)?;
Ok(ast::Expr::Nested(Box::new(self.binary_op_to_sql(l, r, op))))
}
Expr::Case(Case {
expr,
when_then_expr,
else_expr,
}) => {
let conditions = when_then_expr
.iter()
.map(|(cond, result)| {
Ok(CaseWhen {
condition: self.expr_to_sql_inner(cond)?,
result: self.expr_to_sql_inner(result)?,
})
})
.collect::<Result<Vec<CaseWhen>>>()?;
let operand = match expr.as_ref() {
Some(e) => match self.expr_to_sql_inner(e) {
Ok(sql_expr) => Some(Box::new(sql_expr)),
Err(_) => None,
},
None => None,
};
let else_result = match else_expr.as_ref() {
Some(e) => match self.expr_to_sql_inner(e) {
Ok(sql_expr) => Some(Box::new(sql_expr)),
Err(_) => None,
},
None => None,
};
Ok(ast::Expr::Case {
operand,
conditions,
else_result,
})
}
Expr::Cast(Cast { expr, data_type }) => {
Ok(self.cast_to_sql(expr, data_type)?)
}
Expr::Literal(value) => Ok(self.scalar_to_sql(value)?),
Expr::Alias(Alias { expr, name: _, .. }) => self.expr_to_sql_inner(expr),
Expr::WindowFunction(WindowFunction {
fun,
params:
WindowFunctionParams {
args,
partition_by,
order_by,
window_frame,
..
},
}) => {
let func_name = fun.name();
let args = self.function_args_to_sql(args)?;
let units = match window_frame.units {
datafusion_expr::window_frame::WindowFrameUnits::Rows => {
ast::WindowFrameUnits::Rows
}
datafusion_expr::window_frame::WindowFrameUnits::Range => {
ast::WindowFrameUnits::Range
}
datafusion_expr::window_frame::WindowFrameUnits::Groups => {
ast::WindowFrameUnits::Groups
}
};
let order_by = order_by
.iter()
.map(|sort_expr| self.sort_to_sql(sort_expr))
.collect::<Result<Vec<_>>>()?;
let start_bound = self.convert_bound(&window_frame.start_bound)?;
let end_bound = self.convert_bound(&window_frame.end_bound)?;
let window_frame = if self.dialect.window_func_support_window_frame(
func_name,
&start_bound,
&end_bound,
) {
Some(ast::WindowFrame {
units,
start_bound,
end_bound: Some(end_bound),
})
} else {
None
};
let over = Some(ast::WindowType::WindowSpec(ast::WindowSpec {
window_name: None,
partition_by: partition_by
.iter()
.map(|e| self.expr_to_sql_inner(e))
.collect::<Result<Vec<_>>>()?,
order_by,
window_frame,
}));
Ok(ast::Expr::Function(Function {
name: ObjectName::from(vec![Ident {
value: func_name.to_string(),
quote_style: None,
span: Span::empty(),
}]),
args: ast::FunctionArguments::List(ast::FunctionArgumentList {
duplicate_treatment: None,
args,
clauses: vec![],
}),
filter: None,
null_treatment: None,
over,
within_group: vec![],
parameters: ast::FunctionArguments::None,
uses_odbc_syntax: false,
}))
}
Expr::SimilarTo(Like {
negated,
expr,
pattern,
escape_char,
case_insensitive: _,
}) => Ok(ast::Expr::Like {
negated: *negated,
expr: Box::new(self.expr_to_sql_inner(expr)?),
pattern: Box::new(self.expr_to_sql_inner(pattern)?),
escape_char: escape_char.map(|c| c.to_string()),
any: false,
}),
Expr::Like(Like {
negated,
expr,
pattern,
escape_char,
case_insensitive,
}) => {
if *case_insensitive {
Ok(ast::Expr::ILike {
negated: *negated,
expr: Box::new(self.expr_to_sql_inner(expr)?),
pattern: Box::new(self.expr_to_sql_inner(pattern)?),
escape_char: escape_char.map(|c| c.to_string()),
any: false,
})
} else {
Ok(ast::Expr::Like {
negated: *negated,
expr: Box::new(self.expr_to_sql_inner(expr)?),
pattern: Box::new(self.expr_to_sql_inner(pattern)?),
escape_char: escape_char.map(|c| c.to_string()),
any: false,
})
}
}
Expr::AggregateFunction(agg) => {
let func_name = agg.func.name();
let AggregateFunctionParams {
distinct,
args,
filter,
order_by,
..
} = &agg.params;
let args = self.function_args_to_sql(args)?;
let filter = match filter {
Some(filter) => Some(Box::new(self.expr_to_sql_inner(filter)?)),
None => None,
};
let within_group = if agg.func.is_ordered_set_aggregate() {
order_by
.as_ref()
.unwrap_or(&Vec::new())
.iter()
.map(|sort_expr| self.sort_to_sql(sort_expr))
.collect::<Result<Vec<_>>>()?
} else {
Vec::new()
};
Ok(ast::Expr::Function(Function {
name: ObjectName::from(vec![Ident {
value: func_name.to_string(),
quote_style: None,
span: Span::empty(),
}]),
args: ast::FunctionArguments::List(ast::FunctionArgumentList {
duplicate_treatment: distinct
.then_some(ast::DuplicateTreatment::Distinct),
args,
clauses: vec![],
}),
filter,
null_treatment: None,
over: None,
within_group,
parameters: ast::FunctionArguments::None,
uses_odbc_syntax: false,
}))
}
Expr::ScalarSubquery(subq) => {
let sub_statement = self.plan_to_sql(subq.subquery.as_ref())?;
let sub_query = if let ast::Statement::Query(inner_query) = sub_statement
{
inner_query
} else {
return plan_err!(
"Subquery must be a Query, but found {sub_statement:?}"
);
};
Ok(ast::Expr::Subquery(sub_query))
}
Expr::InSubquery(insubq) => {
let inexpr = Box::new(self.expr_to_sql_inner(insubq.expr.as_ref())?);
let sub_statement =
self.plan_to_sql(insubq.subquery.subquery.as_ref())?;
let sub_query = if let ast::Statement::Query(inner_query) = sub_statement
{
inner_query
} else {
return plan_err!(
"Subquery must be a Query, but found {sub_statement:?}"
);
};
Ok(ast::Expr::InSubquery {
expr: inexpr,
subquery: sub_query,
negated: insubq.negated,
})
}
Expr::Exists(Exists { subquery, negated }) => {
let sub_statement = self.plan_to_sql(subquery.subquery.as_ref())?;
let sub_query = if let ast::Statement::Query(inner_query) = sub_statement
{
inner_query
} else {
return plan_err!(
"Subquery must be a Query, but found {sub_statement:?}"
);
};
Ok(ast::Expr::Exists {
subquery: sub_query,
negated: *negated,
})
}
Expr::IsNull(expr) => {
Ok(ast::Expr::IsNull(Box::new(self.expr_to_sql_inner(expr)?)))
}
Expr::IsNotNull(expr) => Ok(ast::Expr::IsNotNull(Box::new(
self.expr_to_sql_inner(expr)?,
))),
Expr::IsTrue(expr) => {
Ok(ast::Expr::IsTrue(Box::new(self.expr_to_sql_inner(expr)?)))
}
Expr::IsNotTrue(expr) => Ok(ast::Expr::IsNotTrue(Box::new(
self.expr_to_sql_inner(expr)?,
))),
Expr::IsFalse(expr) => {
Ok(ast::Expr::IsFalse(Box::new(self.expr_to_sql_inner(expr)?)))
}
Expr::IsNotFalse(expr) => Ok(ast::Expr::IsNotFalse(Box::new(
self.expr_to_sql_inner(expr)?,
))),
Expr::IsUnknown(expr) => Ok(ast::Expr::IsUnknown(Box::new(
self.expr_to_sql_inner(expr)?,
))),
Expr::IsNotUnknown(expr) => Ok(ast::Expr::IsNotUnknown(Box::new(
self.expr_to_sql_inner(expr)?,
))),
Expr::Not(expr) => {
let sql_parser_expr = self.expr_to_sql_inner(expr)?;
Ok(AstExpr::UnaryOp {
op: UnaryOperator::Not,
expr: Box::new(sql_parser_expr),
})
}
Expr::Negative(expr) => {
let sql_parser_expr = self.expr_to_sql_inner(expr)?;
Ok(AstExpr::UnaryOp {
op: UnaryOperator::Minus,
expr: Box::new(sql_parser_expr),
})
}
Expr::ScalarVariable(_, ids) => {
if ids.is_empty() {
return internal_err!("Not a valid ScalarVariable");
}
Ok(if ids.len() == 1 {
ast::Expr::Identifier(
self.new_ident_without_quote_style(ids[0].to_string()),
)
} else {
ast::Expr::CompoundIdentifier(
ids.iter()
.map(|i| self.new_ident_without_quote_style(i.to_string()))
.collect(),
)
})
}
Expr::TryCast(TryCast { expr, data_type }) => {
let inner_expr = self.expr_to_sql_inner(expr)?;
Ok(ast::Expr::Cast {
kind: ast::CastKind::TryCast,
expr: Box::new(inner_expr),
data_type: self.arrow_dtype_to_ast_dtype(data_type)?,
format: None,
})
}
// TODO: unparsing wildcard addition options
#[expect(deprecated)]
Expr::Wildcard { qualifier, .. } => {
let attached_token = AttachedToken::empty();
if let Some(qualifier) = qualifier {
let idents: Vec<Ident> =
qualifier.to_vec().into_iter().map(Ident::new).collect();
Ok(ast::Expr::QualifiedWildcard(
ObjectName::from(idents),
attached_token,
))
} else {
Ok(ast::Expr::Wildcard(attached_token))
}
}
Expr::GroupingSet(grouping_set) => match grouping_set {
GroupingSet::GroupingSets(grouping_sets) => {
let expr_ast_sets = grouping_sets
.iter()
.map(|set| {
set.iter()
.map(|e| self.expr_to_sql_inner(e))
.collect::<Result<Vec<_>>>()
})
.collect::<Result<Vec<_>>>()?;
Ok(ast::Expr::GroupingSets(expr_ast_sets))
}
GroupingSet::Cube(cube) => {
let expr_ast_sets = cube
.iter()
.map(|e| {
let sql = self.expr_to_sql_inner(e)?;
Ok(vec![sql])
})
.collect::<Result<Vec<_>>>()?;
Ok(ast::Expr::Cube(expr_ast_sets))
}
GroupingSet::Rollup(rollup) => {
let expr_ast_sets: Vec<Vec<AstExpr>> = rollup
.iter()
.map(|e| {
let sql = self.expr_to_sql_inner(e)?;
Ok(vec![sql])
})
.collect::<Result<Vec<_>>>()?;
Ok(ast::Expr::Rollup(expr_ast_sets))
}
},
Expr::Placeholder(p) => {
Ok(ast::Expr::value(ast::Value::Placeholder(p.id.to_string())))
}
Expr::OuterReferenceColumn(_, col) => self.col_to_sql(col),
Expr::Unnest(unnest) => self.unnest_to_sql(unnest),
}
}