@@ -6723,6 +6723,7 @@ generate_series_timestamp(PG_FUNCTION_ARGS)
67236723 FuncCallContext * funcctx ;
67246724 generate_series_timestamp_fctx * fctx ;
67256725 Timestamp result ;
6726+ Timestamp nextval = 0 ;
67266727
67276728 /* stuff done only on the first call of the function */
67286729 if (SRF_IS_FIRSTCALL ())
@@ -6751,18 +6752,25 @@ generate_series_timestamp(PG_FUNCTION_ARGS)
67516752 fctx -> finish = finish ;
67526753 fctx -> step = * step ;
67536754
6754- /* Determine sign of the interval */
6755- fctx -> step_sign = interval_sign (& fctx -> step );
6756-
6757- if (fctx -> step_sign == 0 )
6755+ if (INTERVAL_NOT_FINITE ((& fctx -> step )))
67586756 ereport (ERROR ,
67596757 (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6760- errmsg ("step size cannot equal zero " )));
6758+ errmsg ("step size cannot be infinite " )));
67616759
6762- if (INTERVAL_NOT_FINITE ((& fctx -> step )))
6760+ /*
6761+ * Compute the next series value so that we can identify the step
6762+ * direction. This seems more reliable than trusting interval_sign().
6763+ */
6764+ nextval =
6765+ DatumGetTimestamp (DirectFunctionCall2 (timestamp_pl_interval ,
6766+ TimestampGetDatum (start ),
6767+ PointerGetDatum (& fctx -> step )));
6768+ fctx -> step_sign = timestamp_cmp_internal (nextval , start );
6769+
6770+ if (fctx -> step_sign == 0 )
67636771 ereport (ERROR ,
67646772 (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6765- errmsg ("step size cannot be infinite " )));
6773+ errmsg ("step size cannot equal zero " )));
67666774
67676775 funcctx -> user_fctx = fctx ;
67686776 MemoryContextSwitchTo (oldcontext );
@@ -6782,9 +6790,18 @@ generate_series_timestamp(PG_FUNCTION_ARGS)
67826790 timestamp_cmp_internal (result , fctx -> finish ) >= 0 )
67836791 {
67846792 /* increment current in preparation for next iteration */
6785- fctx -> current = DatumGetTimestamp (DirectFunctionCall2 (timestamp_pl_interval ,
6786- TimestampGetDatum (fctx -> current ),
6787- PointerGetDatum (& fctx -> step )));
6793+ if (nextval )
6794+ fctx -> current = nextval ; /* already calculated it */
6795+ else
6796+ fctx -> current =
6797+ DatumGetTimestamp (DirectFunctionCall2 (timestamp_pl_interval ,
6798+ TimestampGetDatum (result ),
6799+ PointerGetDatum (& fctx -> step )));
6800+ /* check for directional instability */
6801+ if (fctx -> step_sign != timestamp_cmp_internal (fctx -> current , result ))
6802+ ereport (ERROR ,
6803+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
6804+ errmsg ("step size changed sign" )));
67886805
67896806 /* do when there is more left to send */
67906807 SRF_RETURN_NEXT (funcctx , TimestampGetDatum (result ));
0 commit comments