Skip to content

Commit 9e9a3d8

Browse files
committed
avoid overloaded function
1 parent 6eb4f41 commit 9e9a3d8

1 file changed

Lines changed: 84 additions & 7 deletions

File tree

datafusion/physical-expr/src/datetime_expressions.rs

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,20 +319,97 @@ fn date_bin_single(stride: i64, source: i64, origin: i64) -> i64 {
319319

320320
/// DATE_BIN sql function
321321
pub fn date_bin(args: &[ColumnarValue]) -> Result<ColumnarValue> {
322-
if args.len() != 2 && args.len() != 3 {
323-
return Err(DataFusionError::Execution(
322+
if args.len() == 2 {
323+
date_bin_2args(args)
324+
} else if args.len() == 3 {
325+
date_bin_3args(args)
326+
} else {
327+
Err(DataFusionError::Execution(
324328
"DATE_BIN expected two or three arguments".to_string(),
325-
));
329+
))
326330
}
331+
}
327332

328-
let (stride, array) = (&args[0], &args[1]);
333+
fn date_bin_3args(args: &[ColumnarValue]) -> Result<ColumnarValue> {
334+
let (stride, array, origin) = (&args[0], &args[1], &args[2]);
329335

330-
// If the origin is not provided, use the Unix epoch
331-
let origin = ColumnarValue::Scalar(ScalarValue::TimestampNanosecond(
336+
let stride = match stride {
337+
ColumnarValue::Scalar(ScalarValue::IntervalDayTime(Some(v))) => {
338+
let (days, ms) = IntervalDayTimeType::to_parts(*v);
339+
let nanos = (Duration::days(days as i64) + Duration::milliseconds(ms as i64))
340+
.num_nanoseconds();
341+
match nanos {
342+
Some(v) => v,
343+
_ => {
344+
return Err(DataFusionError::Execution(
345+
"DATE_BIN stride argument is too large".to_string(),
346+
))
347+
}
348+
}
349+
}
350+
ColumnarValue::Scalar(v) => {
351+
return Err(DataFusionError::Execution(format!(
352+
"DATE_BIN expects stride argument to be an INTERVAL but got {}",
353+
v.get_datatype()
354+
)))
355+
}
356+
ColumnarValue::Array(_) => return Err(DataFusionError::NotImplemented(
357+
"DATE_BIN only supports literal values for the stride argument, not arrays"
358+
.to_string(),
359+
)),
360+
};
361+
362+
let origin = match origin {
363+
ColumnarValue::Scalar(ScalarValue::TimestampNanosecond(Some(v), _)) => *v,
364+
ColumnarValue::Scalar(v) => {
365+
return Err(DataFusionError::Execution(format!(
366+
"DATE_BIN expects origin argument to be a TIMESTAMP but got {}",
367+
v.get_datatype()
368+
)))
369+
}
370+
ColumnarValue::Array(_) => return Err(DataFusionError::NotImplemented(
371+
"DATE_BIN only supports literal values for the origin argument, not arrays"
372+
.to_string(),
373+
)),
374+
};
375+
376+
let f = |x: Option<i64>| x.map(|x| date_bin_single(stride, x, origin));
377+
378+
Ok(match array {
379+
ColumnarValue::Scalar(ScalarValue::TimestampNanosecond(v, tz_opt)) => {
380+
ColumnarValue::Scalar(ScalarValue::TimestampNanosecond(f(*v), tz_opt.clone()))
381+
}
382+
ColumnarValue::Array(array) => match array.data_type() {
383+
DataType::Timestamp(TimeUnit::Nanosecond, _) => {
384+
let array = as_timestamp_nanosecond_array(array)?
385+
.iter()
386+
.map(f)
387+
.collect::<TimestampNanosecondArray>();
388+
389+
ColumnarValue::Array(Arc::new(array))
390+
}
391+
_ => {
392+
return Err(DataFusionError::Execution(format!(
393+
"DATE_BIN expects source argument to be a TIMESTAMP but got {}",
394+
array.data_type()
395+
)))
396+
}
397+
},
398+
_ => {
399+
return Err(DataFusionError::Execution(
400+
"DATE_BIN expects source argument to be a TIMESTAMP scalar or array"
401+
.to_string(),
402+
));
403+
}
404+
})
405+
}
406+
407+
fn date_bin_2args(args: &[ColumnarValue]) -> Result<ColumnarValue> {
408+
let origin = &ColumnarValue::Scalar(ScalarValue::TimestampNanosecond(
332409
Some(0),
333410
Some("+00:00".to_owned()),
334411
));
335-
let origin = if args.len() == 3 { &args[2] } else { &origin };
412+
let (stride, array) = (&args[0], &args[1]);
336413

337414
let stride = match stride {
338415
ColumnarValue::Scalar(ScalarValue::IntervalDayTime(Some(v))) => {

0 commit comments

Comments
 (0)