in datafusion/functions-nested/src/range.rs [511:609]
fn gen_range_timestamp(args: &[ArrayRef], include_upper_bound: bool) -> Result<ArrayRef> {
let func_name = if include_upper_bound {
"GENERATE_SERIES"
} else {
"RANGE"
};
let [start, stop, step] = take_function_args(func_name, args)?;
// coerce_types fn should coerce all types to Timestamp(Nanosecond, tz)
let (start_arr, start_tz_opt) = cast_timestamp_arg(start, include_upper_bound)?;
let (stop_arr, stop_tz_opt) = cast_timestamp_arg(stop, include_upper_bound)?;
let step_arr = as_interval_mdn_array(step)?;
let start_tz = parse_tz(start_tz_opt)?;
let stop_tz = parse_tz(stop_tz_opt)?;
// values are timestamps
let values_builder = start_tz_opt
.clone()
.map_or_else(TimestampNanosecondBuilder::new, |start_tz_str| {
TimestampNanosecondBuilder::new().with_timezone(start_tz_str)
});
let mut list_builder = ListBuilder::new(values_builder);
for idx in 0..start_arr.len() {
if start_arr.is_null(idx) || stop_arr.is_null(idx) || step_arr.is_null(idx) {
list_builder.append_null();
continue;
}
let start = start_arr.value(idx);
let stop = stop_arr.value(idx);
let step = step_arr.value(idx);
let (months, days, ns) = IntervalMonthDayNanoType::to_parts(step);
if months == 0 && days == 0 && ns == 0 {
return exec_err!(
"Interval argument to {} must not be 0",
if include_upper_bound {
"GENERATE_SERIES"
} else {
"RANGE"
}
);
}
let neg = TSNT::add_month_day_nano(start, step, start_tz)
.ok_or(exec_datafusion_err!(
"Cannot generate timestamp range where start + step overflows"
))?
.cmp(&start)
== Ordering::Less;
let stop_dt = as_datetime_with_timezone::<TSNT>(stop, stop_tz).ok_or(
exec_datafusion_err!(
"Cannot generate timestamp for stop: {}: {:?}",
stop,
stop_tz
),
)?;
let mut current = start;
let mut current_dt = as_datetime_with_timezone::<TSNT>(current, start_tz).ok_or(
exec_datafusion_err!(
"Cannot generate timestamp for start: {}: {:?}",
current,
start_tz
),
)?;
let values = from_fn(|| {
if (include_upper_bound
&& ((neg && current_dt < stop_dt) || (!neg && current_dt > stop_dt)))
|| (!include_upper_bound
&& ((neg && current_dt <= stop_dt)
|| (!neg && current_dt >= stop_dt)))
{
return None;
}
let prev_current = current;
if let Some(ts) = TSNT::add_month_day_nano(current, step, start_tz) {
current = ts;
current_dt = as_datetime_with_timezone::<TSNT>(current, start_tz)?;
Some(Some(prev_current))
} else {
// we failed to parse the timestamp here so terminate the series
None
}
});
list_builder.append_value(values);
}
let arr = Arc::new(list_builder.finish());
Ok(arr)
}