pub struct Unparser<'a> {
dialect: &'a dyn Dialect,
pretty: bool,
extension_unparsers: Vec<Arc<dyn UserDefinedLogicalNodeUnparser>>,
}Expand description
Convert a DataFusion Expr to [sqlparser::ast::Expr]
See expr_to_sql for background. Unparser allows greater control of
the conversion, but with a more complicated API.
To get more human-readable output, see Self::with_pretty
§Example
use datafusion_expr::{col, lit};
use datafusion_sql::unparser::Unparser;
let expr = col("a").gt(lit(4)); // form an expression `a > 4`
let unparser = Unparser::default();
let sql = unparser.expr_to_sql(&expr).unwrap();// convert to AST
// use the Display impl to convert to SQL text
assert_eq!(sql.to_string(), "(a > 4)");
// now convert to pretty sql
let unparser = unparser.with_pretty(true);
let sql = unparser.expr_to_sql(&expr).unwrap();
assert_eq!(sql.to_string(), "a > 4"); // note lack of parenthesisFields§
§dialect: &'a dyn Dialect§pretty: bool§extension_unparsers: Vec<Arc<dyn UserDefinedLogicalNodeUnparser>>Implementations§
Source§impl Unparser<'_>
impl Unparser<'_>
pub fn expr_to_sql(&self, expr: &Expr) -> Result<Expr>
fn expr_to_sql_inner(&self, expr: &Expr) -> Result<Expr>
pub fn scalar_function_to_sql( &self, func_name: &str, args: &[Expr], ) -> Result<Expr>
fn scalar_function_to_sql_internal( &self, func_name: &str, args: &[Expr], ) -> Result<Expr>
fn make_array_to_sql(&self, args: &[Expr]) -> Result<Expr>
fn scalar_value_list_to_sql(&self, array: &ArrayRef) -> Result<Expr>
fn array_element_to_sql(&self, args: &[Expr]) -> Result<Expr>
fn named_struct_to_sql(&self, args: &[Expr]) -> Result<Expr>
fn get_field_to_sql(&self, args: &[Expr]) -> Result<Expr>
fn map_to_sql(&self, args: &[Expr]) -> Result<Expr>
pub fn sort_to_sql(&self, sort: &Sort) -> Result<OrderByExpr>
fn ast_type_for_date64_in_cast(&self) -> DataType
pub fn col_to_sql(&self, col: &Column) -> Result<Expr>
fn convert_bound(&self, bound: &WindowFrameBound) -> Result<WindowFrameBound>
pub(crate) fn function_args_to_sql( &self, args: &[Expr], ) -> Result<Vec<FunctionArg>>
Sourcepub(super) fn new_ident_quoted_if_needs(&self, ident: String) -> Ident
pub(super) fn new_ident_quoted_if_needs(&self, ident: String) -> Ident
This function can create an identifier with or without quotes based on the dialect rules
pub(super) fn new_ident_without_quote_style(&self, str: String) -> Ident
pub(super) fn binary_op_to_sql( &self, lhs: Expr, rhs: Expr, op: BinaryOperator, ) -> Expr
Sourcefn remove_unnecessary_nesting(
&self,
expr: Expr,
left_op: &BinaryOperator,
right_op: &BinaryOperator,
) -> Expr
fn remove_unnecessary_nesting( &self, expr: Expr, left_op: &BinaryOperator, right_op: &BinaryOperator, ) -> Expr
Given an expression of the form ((a + b) * (c * d)),
the parenthesis is redundant if the precedence of the nested expression is already higher
than the surrounding operators’ precedence. The above expression would become
(a + b) * c * d.
Also note that when fetching the precedence of a nested expression, we ignore other nested
expressions, so precedence of expr (a * (b + c)) equals * and not +.
fn inner_precedence(&self, expr: &Expr) -> u8
pub(super) fn between_op_to_sql( &self, expr: Expr, negated: bool, low: Expr, high: Expr, ) -> Expr
fn sql_op_precedence(&self, op: &BinaryOperator) -> u8
fn sql_to_op(&self, op: &BinaryOperator) -> Result<Operator>
fn op_to_sql(&self, op: &Operator) -> Result<BinaryOperator>
fn handle_timestamp<T: ArrowTemporalType>( &self, v: &ScalarValue, tz: &Option<Arc<str>>, ) -> Result<Expr>
fn handle_time<T: ArrowTemporalType>(&self, v: &ScalarValue) -> Result<Expr>
fn cast_to_sql(&self, expr: &Expr, data_type: &DataType) -> Result<Expr>
Sourcefn scalar_to_sql(&self, v: &ScalarValue) -> Result<Expr>
fn scalar_to_sql(&self, v: &ScalarValue) -> Result<Expr>
DataFusion ScalarValues sometimes require a ast::Expr to construct. For example ScalarValue::Date32(d) corresponds to the ast::Expr CAST(‘datestr’ as DATE)
Sourcefn interval_to_mysql_expr(
&self,
months: i32,
days: i32,
microseconds: i64,
) -> Result<Expr>
fn interval_to_mysql_expr( &self, months: i32, days: i32, microseconds: i64, ) -> Result<Expr>
MySQL requires INTERVAL sql to be in the format: INTERVAL 1 YEAR + INTERVAL 1 MONTH + INTERVAL 1 DAY etc
<https://dev.mysql.com/doc/refman/8.4/en/expressions.html#temporal-intervals>
Interval sequence can’t be wrapped in brackets - (INTERVAL 1 YEAR + INTERVAL 1 MONTH …) so we need to generate
a single INTERVAL expression so it works correct for interval subtraction cases
MySQL supports the DAY_MICROSECOND unit type (format is DAYS HOURS:MINUTES:SECONDS.MICROSECONDS), but it is not supported by sqlparser
so we calculate the best single interval to represent the provided duration
fn interval_scalar_to_sql(&self, v: &ScalarValue) -> Result<Expr>
Sourcefn unnest_to_sql(&self, unnest: &Unnest) -> Result<Expr>
fn unnest_to_sql(&self, unnest: &Unnest) -> Result<Expr>
Converts an UNNEST operation to an AST expression by wrapping it as a function call, since there is no direct representation for UNNEST in the AST.
fn arrow_dtype_to_ast_dtype(&self, data_type: &DataType) -> Result<DataType>
Source§impl Unparser<'_>
impl Unparser<'_>
pub fn plan_to_sql(&self, plan: &LogicalPlan) -> Result<Statement>
Sourcefn extension_to_statement(
&self,
node: &dyn UserDefinedLogicalNode,
) -> Result<Statement>
fn extension_to_statement( &self, node: &dyn UserDefinedLogicalNode, ) -> Result<Statement>
Try to unparse a UserDefinedLogicalNode to a SQL statement. If multiple unparsers are registered for the same UserDefinedLogicalNode, the first unparsing result will be returned.
Sourcefn extension_to_sql(
&self,
node: &dyn UserDefinedLogicalNode,
query: &mut Option<&mut QueryBuilder>,
select: &mut Option<&mut SelectBuilder>,
relation: &mut Option<&mut RelationBuilder>,
) -> Result<()>
fn extension_to_sql( &self, node: &dyn UserDefinedLogicalNode, query: &mut Option<&mut QueryBuilder>, select: &mut Option<&mut SelectBuilder>, relation: &mut Option<&mut RelationBuilder>, ) -> Result<()>
Try to unparse a UserDefinedLogicalNode to a SQL statement. If multiple unparsers are registered for the same UserDefinedLogicalNode, the first unparser supporting the node will be used.
fn select_to_sql_statement(&self, plan: &LogicalPlan) -> Result<Statement>
fn select_to_sql_expr( &self, plan: &LogicalPlan, query: &mut Option<QueryBuilder>, ) -> Result<SetExpr>
Sourcefn reconstruct_select_statement(
&self,
plan: &LogicalPlan,
p: &Projection,
select: &mut SelectBuilder,
) -> Result<()>
fn reconstruct_select_statement( &self, plan: &LogicalPlan, p: &Projection, select: &mut SelectBuilder, ) -> Result<()>
Reconstructs a SELECT SQL statement from a logical plan by unprojecting column expressions found in a Projection node. This requires scanning the plan tree for relevant Aggregate and Window nodes and matching column expressions to the appropriate agg or window expressions.
fn derive( &self, plan: &LogicalPlan, relation: &mut RelationBuilder, alias: Option<TableAlias>, lateral: bool, ) -> Result<()>
fn derive_with_dialect_alias( &self, alias: &str, plan: &LogicalPlan, relation: &mut RelationBuilder, lateral: bool, columns: Vec<Ident>, ) -> Result<()>
fn select_to_sql_recursively( &self, plan: &LogicalPlan, query: &mut Option<QueryBuilder>, select: &mut SelectBuilder, relation: &mut RelationBuilder, ) -> Result<()>
Sourcefn check_unnest_placeholder_with_outer_ref(
expr: &Expr,
) -> Option<UnnestInputType>
fn check_unnest_placeholder_with_outer_ref( expr: &Expr, ) -> Option<UnnestInputType>
Try to find the placeholder column name generated by RecursiveUnnestRewriter.
- If the column is a placeholder column match the pattern
Expr::Alias(Expr::Column("__unnest_placeholder(...)")), it means it is a scalar column, return UnnestInputType::Scalar. - If the column is a placeholder column match the pattern
Expr::Alias(Expr::Column("__unnest_placeholder(outer_ref(...)))"), it means it is an outer reference column, return UnnestInputType::OuterReference. - If the column is not a placeholder column, return None.
outer_ref is the display result of Expr::OuterReferenceColumn
fn try_unnest_to_table_factor_sql( &self, unnest: &Unnest, ) -> Result<Option<UnnestRelationBuilder>>
fn is_scan_with_pushdown(scan: &TableScan) -> bool
Sourcefn unparse_table_scan_pushdown(
plan: &LogicalPlan,
alias: Option<TableReference>,
already_projected: bool,
) -> Result<Option<LogicalPlan>>
fn unparse_table_scan_pushdown( plan: &LogicalPlan, alias: Option<TableReference>, already_projected: bool, ) -> Result<Option<LogicalPlan>>
Try to unparse a table scan with pushdown operations into a new subquery plan. If the table scan is without any pushdown operations, return None.
fn select_item_to_sql(&self, expr: &Expr) -> Result<SelectItem>
fn sorts_to_sql(&self, sort_exprs: &[SortExpr]) -> Result<OrderByKind>
fn join_operator_to_sql( &self, join_type: JoinType, constraint: JoinConstraint, ) -> Result<JoinOperator>
Sourcefn join_using_to_sql(
&self,
join_conditions: &[(Expr, Expr)],
) -> Option<JoinConstraint>
fn join_using_to_sql( &self, join_conditions: &[(Expr, Expr)], ) -> Option<JoinConstraint>
Convert the components of a USING clause to the USING AST. Returns ‘None’ if the conditions are not compatible with a USING expression, e.g. non-column expressions or non-matching names.
Sourcefn join_constraint_to_sql(
&self,
constraint: JoinConstraint,
conditions: &[(Expr, Expr)],
filter: Option<&Expr>,
) -> Result<JoinConstraint>
fn join_constraint_to_sql( &self, constraint: JoinConstraint, conditions: &[(Expr, Expr)], filter: Option<&Expr>, ) -> Result<JoinConstraint>
Convert a join constraint and associated conditions and filter to a SQL AST node
fn join_conditions_to_sql_on( &self, join_conditions: &[(Expr, Expr)], filter: Option<&Expr>, ) -> Result<JoinConstraint>
fn and_op_to_sql(&self, lhs: Expr, rhs: Expr) -> Expr
fn new_table_alias(&self, alias: String, columns: Vec<Ident>) -> TableAlias
fn dml_to_sql(&self, plan: &LogicalPlan) -> Result<Statement>
Source§impl<'a> Unparser<'a>
impl<'a> Unparser<'a>
pub fn new(dialect: &'a dyn Dialect) -> Self
Sourcepub fn with_pretty(self, pretty: bool) -> Self
pub fn with_pretty(self, pretty: bool) -> Self
Create pretty SQL output, better suited for human consumption
See example on the struct level documentation
§Pretty Output
By default, Unparser generates SQL text that will parse back to the
same parsed Expr, which is useful for creating machine readable
expressions to send to other systems. However, the resulting expressions are
not always nice to read for humans.
For example
((a + 4) > 5)This method removes parenthesis using to the precedence rules of
DataFusion. If the output is reparsed, the resulting Expr produces
same value as the original in DataFusion, but with a potentially
different order of operations.
Note that this setting may create invalid SQL for other SQL query engines with different precedence rules
§Example
use datafusion_expr::{col, lit};
use datafusion_sql::unparser::Unparser;
let expr = col("a").gt(lit(4)).and(col("b").lt(lit(5))); // form an expression `a > 4 AND b < 5`
let unparser = Unparser::default().with_pretty(true);
let sql = unparser.expr_to_sql(&expr).unwrap();
assert_eq!(sql.to_string(), "a > 4 AND b < 5"); // note lack of parenthesisSourcepub fn with_extension_unparsers(
self,
extension_unparsers: Vec<Arc<dyn UserDefinedLogicalNodeUnparser>>,
) -> Self
pub fn with_extension_unparsers( self, extension_unparsers: Vec<Arc<dyn UserDefinedLogicalNodeUnparser>>, ) -> Self
Add a custom unparser for user defined logical nodes
DataFusion allows user to define custom logical nodes. This method allows to add custom child unparsers for these nodes.
Implementation of UserDefinedLogicalNodeUnparser can be added to the root unparser to handle custom logical nodes.
The child unparsers are called iteratively.
There are two methods in Unparser will be called:
extension_to_statement: This method is called when the custom logical node is a custom statement. If multiple child unparsers return a non-None value, the last unparsing result will be returned.extension_to_sql: This method is called when the custom logical node is part of a statement. If multiple child unparsers are registered for the same custom logical node, all of them will be called in order.
Trait Implementations§
Auto Trait Implementations§
impl<'a> Freeze for Unparser<'a>
impl<'a> !RefUnwindSafe for Unparser<'a>
impl<'a> !Send for Unparser<'a>
impl<'a> !Sync for Unparser<'a>
impl<'a> Unpin for Unparser<'a>
impl<'a> !UnwindSafe for Unparser<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more