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]