This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 0cd7c25a37 feat: Add DateFieldExtractStyle::Strftime support for 
SqliteDialect unparser (#12161)
0cd7c25a37 is described below

commit 0cd7c25a37ae5d7fa27e5cf49a5aa258d73e9efa
Author: peasee <[email protected]>
AuthorDate: Wed Sep 4 06:59:19 2024 +1000

    feat: Add DateFieldExtractStyle::Strftime support for SqliteDialect 
unparser (#12161)
    
    * feat: Add DateFieldExtractStyle::Strftime support for SqliteDialect (#26)
    
    * feat: Add DateFieldExtractStyle::Strftime support for SqliteDialect
    
    * refactor: Refactor DateFieldExtractStyle if checks into if/match
    
    * Fix merge issue
    
    ---------
    
    Co-authored-by: Andrew Lamb <[email protected]>
---
 datafusion/sql/src/unparser/dialect.rs |  5 ++
 datafusion/sql/src/unparser/expr.rs    | 97 ++++++++++++++++++++++++++--------
 2 files changed, 81 insertions(+), 21 deletions(-)

diff --git a/datafusion/sql/src/unparser/dialect.rs 
b/datafusion/sql/src/unparser/dialect.rs
index 706b7633cb..2a8e61add1 100644
--- a/datafusion/sql/src/unparser/dialect.rs
+++ b/datafusion/sql/src/unparser/dialect.rs
@@ -130,6 +130,7 @@ pub enum IntervalStyle {
 pub enum DateFieldExtractStyle {
     DatePart,
     Extract,
+    Strftime,
 }
 
 pub struct DefaultDialect {}
@@ -213,6 +214,10 @@ impl Dialect for SqliteDialect {
         Some('`')
     }
 
+    fn date_field_extract_style(&self) -> DateFieldExtractStyle {
+        DateFieldExtractStyle::Strftime
+    }
+
     fn date32_cast_dtype(&self) -> sqlparser::ast::DataType {
         sqlparser::ast::DataType::Text
     }
diff --git a/datafusion/sql/src/unparser/expr.rs 
b/datafusion/sql/src/unparser/expr.rs
index 8ff4773e8e..fe34d87bfe 100644
--- a/datafusion/sql/src/unparser/expr.rs
+++ b/datafusion/sql/src/unparser/expr.rs
@@ -524,30 +524,78 @@ impl Unparser<'_> {
         _func: &Arc<ScalarUDF>,
         args: &[Expr],
     ) -> Option<ast::Expr> {
-        if func_name.to_lowercase() == "date_part"
-            && self.dialect.date_field_extract_style() == 
DateFieldExtractStyle::Extract
-            && args.len() == 2
-        {
-            let date_expr = self.expr_to_sql(&args[1]).ok()?;
-
-            if let Expr::Literal(ScalarValue::Utf8(Some(field))) = &args[0] {
-                let field = match field.to_lowercase().as_str() {
-                    "year" => ast::DateTimeField::Year,
-                    "month" => ast::DateTimeField::Month,
-                    "day" => ast::DateTimeField::Day,
-                    "hour" => ast::DateTimeField::Hour,
-                    "minute" => ast::DateTimeField::Minute,
-                    "second" => ast::DateTimeField::Second,
-                    _ => return None,
-                };
+        if func_name.to_lowercase() == "date_part" {
+            match (self.dialect.date_field_extract_style(), args.len()) {
+                (DateFieldExtractStyle::Extract, 2) => {
+                    let date_expr = self.expr_to_sql(&args[1]).ok()?;
+
+                    if let Expr::Literal(ScalarValue::Utf8(Some(field))) = 
&args[0] {
+                        let field = match field.to_lowercase().as_str() {
+                            "year" => ast::DateTimeField::Year,
+                            "month" => ast::DateTimeField::Month,
+                            "day" => ast::DateTimeField::Day,
+                            "hour" => ast::DateTimeField::Hour,
+                            "minute" => ast::DateTimeField::Minute,
+                            "second" => ast::DateTimeField::Second,
+                            _ => return None,
+                        };
+
+                        return Some(ast::Expr::Extract {
+                            field,
+                            expr: Box::new(date_expr),
+                            syntax: ast::ExtractSyntax::From,
+                        });
+                    }
+                }
+                (DateFieldExtractStyle::Strftime, 2) => {
+                    let column = self.expr_to_sql(&args[1]).ok()?;
+
+                    if let Expr::Literal(ScalarValue::Utf8(Some(field))) = 
&args[0] {
+                        let field = match field.to_lowercase().as_str() {
+                            "year" => "%Y",
+                            "month" => "%m",
+                            "day" => "%d",
+                            "hour" => "%H",
+                            "minute" => "%M",
+                            "second" => "%S",
+                            _ => return None,
+                        };
 
-                return Some(ast::Expr::Extract {
-                    field,
-                    expr: Box::new(date_expr),
-                    syntax: ast::ExtractSyntax::From,
-                });
+                        return Some(ast::Expr::Function(ast::Function {
+                            name: ast::ObjectName(vec![ast::Ident {
+                                value: "strftime".to_string(),
+                                quote_style: None,
+                            }]),
+                            args: ast::FunctionArguments::List(
+                                ast::FunctionArgumentList {
+                                    duplicate_treatment: None,
+                                    args: vec![
+                                        ast::FunctionArg::Unnamed(
+                                            
ast::FunctionArgExpr::Expr(ast::Expr::Value(
+                                                ast::Value::SingleQuotedString(
+                                                    field.to_string(),
+                                                ),
+                                            )),
+                                        ),
+                                        ast::FunctionArg::Unnamed(
+                                            ast::FunctionArgExpr::Expr(column),
+                                        ),
+                                    ],
+                                    clauses: vec![],
+                                },
+                            ),
+                            filter: None,
+                            null_treatment: None,
+                            over: None,
+                            within_group: vec![],
+                            parameters: ast::FunctionArguments::None,
+                        }));
+                    }
+                }
+                _ => {} // no overrides for DateFieldExtractStyle::DatePart, 
because it's already a date_part
             }
         }
+
         None
     }
 
@@ -2178,6 +2226,7 @@ mod tests {
                 "YEAR",
                 "EXTRACT(YEAR FROM x)",
             ),
+            (DateFieldExtractStyle::Strftime, "YEAR", "strftime('%Y', x)"),
             (
                 DateFieldExtractStyle::DatePart,
                 "MONTH",
@@ -2188,11 +2237,17 @@ mod tests {
                 "MONTH",
                 "EXTRACT(MONTH FROM x)",
             ),
+            (
+                DateFieldExtractStyle::Strftime,
+                "MONTH",
+                "strftime('%m', x)",
+            ),
             (
                 DateFieldExtractStyle::DatePart,
                 "DAY",
                 "date_part('DAY', x)",
             ),
+            (DateFieldExtractStyle::Strftime, "DAY", "strftime('%d', x)"),
             (DateFieldExtractStyle::Extract, "DAY", "EXTRACT(DAY FROM x)"),
         ] {
             let dialect = CustomDialectBuilder::new()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to