Skip to content

Commit

Permalink
Handle negative values in saturating sub and add
Browse files Browse the repository at this point in the history
The functions for saturating addition and subtraction of time values
assumed positive intervals as input. This change generalizes the code
to also handle negative intervals being added or subtracted.
  • Loading branch information
erimatnor committed Oct 14, 2020
1 parent 3c801bf commit 9a46609
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 15 deletions.
38 changes: 26 additions & 12 deletions src/time_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,19 +460,26 @@ ts_time_get_noend_or_max(Oid timetype)
int64
ts_time_saturating_add(int64 timeval, int64 interval, Oid timetype)
{
int64 min_overflow_result;
int64 max_overflow_result;

if (IS_TIMESTAMP_TYPE(timetype))
{
if (timeval >= (ts_time_get_end(timetype) - interval))
return ts_time_get_noend(timetype);
min_overflow_result = ts_time_get_nobegin(timetype);
max_overflow_result = ts_time_get_noend(timetype);
}
else
{
int64 time_max = ts_time_get_max(timetype);

if (timeval > (time_max - interval))
return time_max;
min_overflow_result = ts_time_get_min(timetype);
max_overflow_result = ts_time_get_max(timetype);
}

if (timeval > 0 && interval > 0 && timeval > (ts_time_get_max(timetype) - interval))
return max_overflow_result;

if (timeval < 0 && interval < 0 && timeval < (ts_time_get_min(timetype) - interval))
return min_overflow_result;

return timeval + interval;
}

Expand All @@ -487,19 +494,26 @@ ts_time_saturating_add(int64 timeval, int64 interval, Oid timetype)
int64
ts_time_saturating_sub(int64 timeval, int64 interval, Oid timetype)
{
int64 min_overflow_result;
int64 max_overflow_result;

if (IS_TIMESTAMP_TYPE(timetype))
{
if (timeval < (ts_time_get_min(timetype) + interval))
return ts_time_get_nobegin(timetype);
min_overflow_result = ts_time_get_nobegin(timetype);
max_overflow_result = ts_time_get_noend(timetype);
}
else
{
int64 time_min = ts_time_get_min(timetype);

if (timeval < (time_min + interval))
return time_min;
min_overflow_result = ts_time_get_min(timetype);
max_overflow_result = ts_time_get_max(timetype);
}

if (timeval < 0 && interval > 0 && timeval < (ts_time_get_min(timetype) + interval))
return min_overflow_result;

if (timeval > 0 && interval < 0 && timeval > (ts_time_get_max(timetype) + interval))
return max_overflow_result;

return timeval - interval;
}

Expand Down
34 changes: 31 additions & 3 deletions test/src/test_time_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,11 @@ ts_test_time_utils(PG_FUNCTION_ARGS)
ts_time_get_max(INT8OID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_max(DATEOID), 1, DATEOID),
ts_time_get_noend(DATEOID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_end(DATEOID) - 1, 1, DATEOID),
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_max(DATEOID), 1, DATEOID),
ts_time_get_noend(DATEOID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_end(TIMESTAMPOID) - 1, 1, TIMESTAMPOID),
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_max(TIMESTAMPOID), 1, TIMESTAMPOID),
ts_time_get_noend(TIMESTAMPOID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_end(TIMESTAMPTZOID) - 1, 1, TIMESTAMPOID),
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_max(TIMESTAMPTZOID), 1, TIMESTAMPOID),
ts_time_get_noend(TIMESTAMPOID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_end(DATEOID) - 2, 1, DATEOID),
ts_time_get_max(DATEOID));
Expand All @@ -308,6 +308,21 @@ ts_test_time_utils(PG_FUNCTION_ARGS)
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_end(TIMESTAMPTZOID) - 2, 1, TIMESTAMPOID),
ts_time_get_max(TIMESTAMPOID));

TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_min(INT2OID), -1, INT2OID),
ts_time_get_min(INT2OID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_min(INT4OID), -1, INT4OID),
ts_time_get_min(INT4OID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_min(INT8OID), -1, INT8OID),
ts_time_get_min(INT8OID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_min(DATEOID), -1, DATEOID),
ts_time_get_nobegin(DATEOID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_min(DATEOID), -1, DATEOID),
ts_time_get_nobegin(DATEOID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_min(TIMESTAMPOID), -1, TIMESTAMPOID),
ts_time_get_nobegin(TIMESTAMPOID));
TestAssertInt64Eq(ts_time_saturating_add(ts_time_get_min(TIMESTAMPTZOID), -1, TIMESTAMPOID),
ts_time_get_nobegin(TIMESTAMPOID));

/* Test saturating subtraction */
TestAssertInt64Eq(ts_time_saturating_sub(ts_time_get_min(INT2OID), 1, INT2OID),
ts_time_get_min(INT2OID));
Expand All @@ -330,5 +345,18 @@ ts_test_time_utils(PG_FUNCTION_ARGS)
TIMESTAMPTZOID),
ts_time_get_min(TIMESTAMPTZOID));

TestAssertInt64Eq(ts_time_saturating_sub(ts_time_get_max(INT2OID), -1, INT2OID),
ts_time_get_max(INT2OID));
TestAssertInt64Eq(ts_time_saturating_sub(ts_time_get_max(INT4OID), -1, INT4OID),
ts_time_get_max(INT4OID));
TestAssertInt64Eq(ts_time_saturating_sub(ts_time_get_max(INT8OID), -1, INT8OID),
ts_time_get_max(INT8OID));
TestAssertInt64Eq(ts_time_saturating_sub(ts_time_get_max(DATEOID), -1, DATEOID),
ts_time_get_noend(DATEOID));
TestAssertInt64Eq(ts_time_saturating_sub(ts_time_get_max(TIMESTAMPOID), -1, TIMESTAMPOID),
ts_time_get_noend(TIMESTAMPOID));
TestAssertInt64Eq(ts_time_saturating_sub(ts_time_get_max(TIMESTAMPTZOID), -1, TIMESTAMPTZOID),
ts_time_get_noend(TIMESTAMPTZOID));

PG_RETURN_VOID();
}

0 comments on commit 9a46609

Please sign in to comment.