This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git
The following commit(s) were added to refs/heads/master by this push:
new f91eddfdc Implement current_date scalar function (#4022)
f91eddfdc is described below
commit f91eddfdc9f3e805abc1cb7186aec31ed211c22e
Author: comphead <[email protected]>
AuthorDate: Mon Oct 31 03:32:36 2022 -0700
Implement current_date scalar function (#4022)
* current_date impl
* Update datafusion/expr/src/expr_fn.rs
Co-authored-by: Andrew Lamb <[email protected]>
* Update datafusion/physical-expr/src/functions.rs
Co-authored-by: Andrew Lamb <[email protected]>
Co-authored-by: Andrew Lamb <[email protected]>
---
datafusion/core/tests/sql/timestamp.rs | 32 ++++++++++++++++++++++
datafusion/expr/src/built_in_function.rs | 8 +++++-
datafusion/expr/src/expr_fn.rs | 8 ++++++
datafusion/expr/src/function.rs | 1 +
.../physical-expr/src/datetime_expressions.rs | 15 ++++++++++
datafusion/physical-expr/src/functions.rs | 6 ++++
datafusion/proto/proto/datafusion.proto | 1 +
datafusion/proto/src/from_proto.rs | 1 +
datafusion/proto/src/generated/pbjson.rs | 3 ++
datafusion/proto/src/generated/prost.rs | 2 ++
datafusion/proto/src/to_proto.rs | 1 +
11 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/datafusion/core/tests/sql/timestamp.rs
b/datafusion/core/tests/sql/timestamp.rs
index b6cf2bb67..890950200 100644
--- a/datafusion/core/tests/sql/timestamp.rs
+++ b/datafusion/core/tests/sql/timestamp.rs
@@ -1619,3 +1619,35 @@ async fn test_cast_to_timetz_should_not_work() ->
Result<()> {
);
Ok(())
}
+
+#[tokio::test]
+async fn test_current_date() -> Result<()> {
+ let ctx = SessionContext::new();
+
+ let sql = "select current_date() dt";
+ let results = execute_to_batches(&ctx, sql).await;
+ assert_eq!(
+ results[0]
+ .schema()
+ .field_with_name("dt")
+ .unwrap()
+ .data_type()
+ .to_owned(),
+ DataType::Date32
+ );
+
+ let sql = "select case when current_date() = cast(now() as date) then 'OK'
else 'FAIL' end result";
+ let results = execute_to_batches(&ctx, sql).await;
+
+ let expected = vec![
+ "+--------+",
+ "| result |",
+ "+--------+",
+ "| OK |",
+ "+--------+",
+ ];
+
+ assert_batches_eq!(expected, &results);
+
+ Ok(())
+}
diff --git a/datafusion/expr/src/built_in_function.rs
b/datafusion/expr/src/built_in_function.rs
index fa3adbab6..796f0c909 100644
--- a/datafusion/expr/src/built_in_function.rs
+++ b/datafusion/expr/src/built_in_function.rs
@@ -156,6 +156,8 @@ pub enum BuiltinScalarFunction {
FromUnixtime,
///now
Now,
+ ///current_date
+ CurrentDate,
/// translate
Translate,
/// trim
@@ -176,7 +178,9 @@ impl BuiltinScalarFunction {
pub fn supports_zero_argument(&self) -> bool {
matches!(
self,
- BuiltinScalarFunction::Random | BuiltinScalarFunction::Now
+ BuiltinScalarFunction::Random
+ | BuiltinScalarFunction::Now
+ | BuiltinScalarFunction::CurrentDate
)
}
/// Returns the [Volatility] of the builtin function.
@@ -254,6 +258,7 @@ impl BuiltinScalarFunction {
// Stable builtin functions
BuiltinScalarFunction::Now => Volatility::Stable,
+ BuiltinScalarFunction::CurrentDate => Volatility::Stable,
// Volatile builtin functions
BuiltinScalarFunction::Random => Volatility::Volatile,
@@ -309,6 +314,7 @@ impl FromStr for BuiltinScalarFunction {
"concat" => BuiltinScalarFunction::Concat,
"concat_ws" => BuiltinScalarFunction::ConcatWithSeparator,
"chr" => BuiltinScalarFunction::Chr,
+ "current_date" => BuiltinScalarFunction::CurrentDate,
"date_part" | "datepart" => BuiltinScalarFunction::DatePart,
"date_trunc" | "datetrunc" => BuiltinScalarFunction::DateTrunc,
"date_bin" => BuiltinScalarFunction::DateBin,
diff --git a/datafusion/expr/src/expr_fn.rs b/datafusion/expr/src/expr_fn.rs
index 0685ec835..cfd043a3a 100644
--- a/datafusion/expr/src/expr_fn.rs
+++ b/datafusion/expr/src/expr_fn.rs
@@ -452,6 +452,14 @@ pub fn now() -> Expr {
}
}
+/// Returns current UTC date as a [`DataType::Date32`] value
+pub fn current_date() -> Expr {
+ Expr::ScalarFunction {
+ fun: BuiltinScalarFunction::CurrentDate,
+ args: vec![],
+ }
+}
+
/// Create a CASE WHEN statement with literal WHEN expressions for comparison
to the base expression.
pub fn case(expr: Expr) -> CaseBuilder {
CaseBuilder::new(Some(Box::new(expr)), vec![], vec![], None)
diff --git a/datafusion/expr/src/function.rs b/datafusion/expr/src/function.rs
index e39339c20..4a47d8209 100644
--- a/datafusion/expr/src/function.rs
+++ b/datafusion/expr/src/function.rs
@@ -221,6 +221,7 @@ pub fn return_type(
TimeUnit::Nanosecond,
Some("UTC".to_owned()),
)),
+ BuiltinScalarFunction::CurrentDate => Ok(DataType::Date32),
BuiltinScalarFunction::Translate => {
utf8_to_str_type(&input_expr_types[0], "translate")
}
diff --git a/datafusion/physical-expr/src/datetime_expressions.rs
b/datafusion/physical-expr/src/datetime_expressions.rs
index 0214d1bfb..c243cf587 100644
--- a/datafusion/physical-expr/src/datetime_expressions.rs
+++ b/datafusion/physical-expr/src/datetime_expressions.rs
@@ -184,6 +184,21 @@ pub fn make_now(
}
}
+/// Create an implementation of `current_date()` that always returns the
+/// specified current date.
+///
+/// The semantics of `current_date()` require it to return the same value
+/// wherever it appears within a single statement. This value is
+/// chosen during planning time.
+pub fn make_current_date(
+ now_ts: DateTime<Utc>,
+) -> impl Fn(&[ColumnarValue]) -> Result<ColumnarValue> {
+ let days = Some(
+ now_ts.num_days_from_ce() - NaiveDate::from_ymd(1970, 1,
1).num_days_from_ce(),
+ );
+ move |_arg| Ok(ColumnarValue::Scalar(ScalarValue::Date32(days)))
+}
+
fn quarter_month(date: &NaiveDateTime) -> u32 {
1 + 3 * ((date.month() - 1) / 3)
}
diff --git a/datafusion/physical-expr/src/functions.rs
b/datafusion/physical-expr/src/functions.rs
index 6f7b864ef..f7c3cbef9 100644
--- a/datafusion/physical-expr/src/functions.rs
+++ b/datafusion/physical-expr/src/functions.rs
@@ -427,6 +427,12 @@ pub fn create_physical_fun(
execution_props.query_execution_start_time,
))
}
+ BuiltinScalarFunction::CurrentDate => {
+ // bind value for current_date at plan time
+ Arc::new(datetime_expressions::make_current_date(
+ execution_props.query_execution_start_time,
+ ))
+ }
BuiltinScalarFunction::InitCap => Arc::new(|args| match
args[0].data_type() {
DataType::Utf8 => {
make_scalar_function(string_expressions::initcap::<i32>)(args)
diff --git a/datafusion/proto/proto/datafusion.proto
b/datafusion/proto/proto/datafusion.proto
index e0f8f5160..1ff2952df 100644
--- a/datafusion/proto/proto/datafusion.proto
+++ b/datafusion/proto/proto/datafusion.proto
@@ -495,6 +495,7 @@ enum ScalarFunction {
Atan2=67;
DateBin=68;
ArrowTypeof=69;
+ CurrentDate=70;
}
message ScalarFunctionNode {
diff --git a/datafusion/proto/src/from_proto.rs
b/datafusion/proto/src/from_proto.rs
index f1e8a9f21..cd61bba7a 100644
--- a/datafusion/proto/src/from_proto.rs
+++ b/datafusion/proto/src/from_proto.rs
@@ -429,6 +429,7 @@ impl From<&protobuf::ScalarFunction> for
BuiltinScalarFunction {
ScalarFunction::ToTimestampMicros => Self::ToTimestampMicros,
ScalarFunction::ToTimestampSeconds => Self::ToTimestampSeconds,
ScalarFunction::Now => Self::Now,
+ ScalarFunction::CurrentDate => Self::CurrentDate,
ScalarFunction::Translate => Self::Translate,
ScalarFunction::RegexpMatch => Self::RegexpMatch,
ScalarFunction::Coalesce => Self::Coalesce,
diff --git a/datafusion/proto/src/generated/pbjson.rs
b/datafusion/proto/src/generated/pbjson.rs
index 71502f812..941cc461f 100644
--- a/datafusion/proto/src/generated/pbjson.rs
+++ b/datafusion/proto/src/generated/pbjson.rs
@@ -9620,6 +9620,7 @@ impl serde::Serialize for ScalarFunction {
Self::Atan2 => "Atan2",
Self::DateBin => "DateBin",
Self::ArrowTypeof => "ArrowTypeof",
+ Self::CurrentDate => "CurrentDate",
};
serializer.serialize_str(variant)
}
@@ -9701,6 +9702,7 @@ impl<'de> serde::Deserialize<'de> for ScalarFunction {
"Atan2",
"DateBin",
"ArrowTypeof",
+ "CurrentDate",
];
struct GeneratedVisitor;
@@ -9813,6 +9815,7 @@ impl<'de> serde::Deserialize<'de> for ScalarFunction {
"Atan2" => Ok(ScalarFunction::Atan2),
"DateBin" => Ok(ScalarFunction::DateBin),
"ArrowTypeof" => Ok(ScalarFunction::ArrowTypeof),
+ "CurrentDate" => Ok(ScalarFunction::CurrentDate),
_ => Err(serde::de::Error::unknown_variant(value, FIELDS)),
}
}
diff --git a/datafusion/proto/src/generated/prost.rs
b/datafusion/proto/src/generated/prost.rs
index 8287d1289..038195c94 100644
--- a/datafusion/proto/src/generated/prost.rs
+++ b/datafusion/proto/src/generated/prost.rs
@@ -1224,6 +1224,7 @@ pub enum ScalarFunction {
Atan2 = 67,
DateBin = 68,
ArrowTypeof = 69,
+ CurrentDate = 70,
}
impl ScalarFunction {
/// String value of the enum field names used in the ProtoBuf definition.
@@ -1302,6 +1303,7 @@ impl ScalarFunction {
ScalarFunction::Atan2 => "Atan2",
ScalarFunction::DateBin => "DateBin",
ScalarFunction::ArrowTypeof => "ArrowTypeof",
+ ScalarFunction::CurrentDate => "CurrentDate",
}
}
}
diff --git a/datafusion/proto/src/to_proto.rs b/datafusion/proto/src/to_proto.rs
index 14a5f24e5..a089f0768 100644
--- a/datafusion/proto/src/to_proto.rs
+++ b/datafusion/proto/src/to_proto.rs
@@ -1178,6 +1178,7 @@ impl TryFrom<&BuiltinScalarFunction> for
protobuf::ScalarFunction {
BuiltinScalarFunction::ToTimestampMicros =>
Self::ToTimestampMicros,
BuiltinScalarFunction::ToTimestampSeconds =>
Self::ToTimestampSeconds,
BuiltinScalarFunction::Now => Self::Now,
+ BuiltinScalarFunction::CurrentDate => Self::CurrentDate,
BuiltinScalarFunction::Translate => Self::Translate,
BuiltinScalarFunction::RegexpMatch => Self::RegexpMatch,
BuiltinScalarFunction::Coalesce => Self::Coalesce,