Skip to content

Commit df91402

Browse files
committed
fix: stop generate_series at terminal boundary
1 parent f88086c commit df91402

2 files changed

Lines changed: 60 additions & 1 deletion

File tree

datafusion/functions-table/src/generate_series.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ impl GenerateSeriesTable {
275275
end: *end,
276276
step: *step,
277277
current: *start,
278+
finished: false,
278279
batch_size,
279280
include_end: *include_end,
280281
name,
@@ -315,6 +316,7 @@ impl GenerateSeriesTable {
315316
parsed_tz: Some(parsed_tz),
316317
tz_str: tz.clone(),
317318
},
319+
finished: false,
318320
batch_size,
319321
include_end: *include_end,
320322
name,
@@ -344,6 +346,7 @@ impl GenerateSeriesTable {
344346
parsed_tz: None,
345347
tz_str: None,
346348
},
349+
finished: false,
347350
batch_size,
348351
include_end: *include_end,
349352
name,
@@ -385,6 +388,7 @@ pub struct GenericSeriesState<T: SeriesValue> {
385388
step: T::StepType,
386389
batch_size: usize,
387390
current: T,
391+
finished: bool,
388392
include_end: bool,
389393
name: &'static str,
390394
}
@@ -425,6 +429,10 @@ impl<T: SeriesValue> LazyBatchGenerator for GenericSeriesState<T> {
425429
}
426430

427431
fn generate_next_batch(&mut self) -> Result<Option<RecordBatch>> {
432+
if self.finished {
433+
return Ok(None);
434+
}
435+
428436
let mut buf = Vec::with_capacity(self.batch_size);
429437

430438
while buf.len() < self.batch_size
@@ -437,11 +445,20 @@ impl<T: SeriesValue> LazyBatchGenerator for GenericSeriesState<T> {
437445
.current
438446
.should_stop(self.end.clone(), &self.step, false)
439447
{
440-
self.current.advance(&mut self.end, &self.step)?;
448+
self.finished = true;
441449
break;
442450
}
443451

452+
let original_end = self.end.clone();
444453
self.current.advance(&mut self.end, &self.step)?;
454+
if self
455+
.current
456+
.should_stop(self.end.clone(), &self.step, self.include_end)
457+
{
458+
self.end = original_end;
459+
self.finished = true;
460+
break;
461+
}
445462
}
446463

447464
if buf.is_empty() {
@@ -456,6 +473,7 @@ impl<T: SeriesValue> LazyBatchGenerator for GenericSeriesState<T> {
456473
fn reset_state(&self) -> Arc<RwLock<dyn LazyBatchGenerator>> {
457474
let mut new = self.clone();
458475
new.current = new.start.clone();
476+
new.finished = false;
459477
Arc::new(RwLock::new(new))
460478
}
461479
}
@@ -840,11 +858,40 @@ mod generate_series_tests {
840858
end: 5,
841859
step: 1,
842860
current: 1,
861+
finished: false,
862+
batch_size: 8192,
863+
include_end: true,
864+
name: "test",
865+
};
866+
let batch = state.generate_next_batch()?.expect("missing batch");
867+
868+
let state_reset = state.reset_state();
869+
let reset_batch = state_reset
870+
.write()
871+
.generate_next_batch()?
872+
.expect("missing reset batch");
873+
874+
assert_eq!(batch, reset_batch);
875+
876+
Ok(())
877+
}
878+
879+
#[test]
880+
fn test_generic_series_state_reset_after_overflow() -> Result<()> {
881+
let schema = Arc::new(Schema::new(vec![Field::new("a", DataType::Int64, false)]));
882+
let mut state = GenericSeriesState::<i64> {
883+
schema,
884+
start: i64::MAX - 1,
885+
end: i64::MAX,
886+
step: 2,
887+
current: i64::MAX - 1,
888+
finished: false,
843889
batch_size: 8192,
844890
include_end: true,
845891
name: "test",
846892
};
847893
let batch = state.generate_next_batch()?.expect("missing batch");
894+
assert!(state.generate_next_batch()?.is_none());
848895

849896
let state_reset = state.reset_state();
850897
let reset_batch = state_reset

datafusion/sqllogictest/test_files/table_functions.slt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,18 @@ SELECT * FROM generate_series(DATE '0001-01-01', DATE '2000-01-01', INTERVAL '1'
234234
statement error DataFusion error: Error during planning: Second argument for generate_series is out of range of nanosecond timestamps
235235
SELECT * FROM generate_series(DATE '2000-01-01', DATE '3000-01-01', INTERVAL '1' DAY)
236236

237+
# Reaching the maximum representable date must not attempt to advance beyond it.
238+
query P
239+
SELECT * FROM generate_series(DATE '2262-04-11', DATE '2262-04-11', INTERVAL '1' DAY)
240+
----
241+
2262-04-11T00:00:00
242+
243+
# Same for the maximum representable nanosecond timestamp.
244+
query P
245+
SELECT * FROM generate_series(TIMESTAMP '2262-04-11T23:47:16.854775807', TIMESTAMP '2262-04-11T23:47:16.854775807', INTERVAL '1' NANOSECOND)
246+
----
247+
2262-04-11T23:47:16.854775807
248+
237249
# UDF and UDTF `generate_series` can be used simultaneously
238250
query ? rowsort
239251
SELECT generate_series(1, t1.end) FROM generate_series(3, 5) as t1(end)

0 commit comments

Comments
 (0)