Skip to content

Commit

Permalink
Support sub-second intervals in hierarchical caggs
Browse files Browse the repository at this point in the history
Internally we use date_part("epoch", interval) and integer division
to determine whether the top cagg's interval is a multiple of
the parent's.
This would lead to loss of precision and incorrect results in the case
of intervals with sub-second components.
Fixed by multiplying by appropriate factors when possible to maintain
precision.

Fixes timescale#5277
  • Loading branch information
konskov committed Feb 10, 2023
1 parent 348796f commit 20bd957
Show file tree
Hide file tree
Showing 6 changed files with 899 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ accidentally triggering the load of a previous DB version.**
* #5214 Fix use of prepared statement in async module
* #5290 Compression can't be enabled on continuous aggregates when segmentby/orderby columns need quotation
* #5239 Fix next_start calculation for fixed schedules
* #5304 Support sub-second intervals in hierarchical caggs

## 2.9.3 (2023-02-03)

Expand Down
10 changes: 10 additions & 0 deletions tsl/src/continuous_aggs/create.c
Original file line number Diff line number Diff line change
Expand Up @@ -1147,9 +1147,19 @@ get_bucket_width(CAggTimebucketInfo bucket_info)
bucket_info.interval->day = bucket_info.interval->month * DAYS_PER_MONTH;
bucket_info.interval->month = 0;
}
int64 MSECS_PER_SEC = 1000;
Datum float_usecs_per_sec = DirectFunctionCall1(i8tod, Int64GetDatum(USECS_PER_SEC));
Datum float_msecs_per_sec = DirectFunctionCall1(i8tod, Int64GetDatum(MSECS_PER_SEC));
Datum epoch = DirectFunctionCall2(interval_part,
PointerGetDatum(cstring_to_text("epoch")),
IntervalPGetDatum(bucket_info.interval));
/* Preserve precision if possible for units less than seconds by converting to usecs or
* msecs */
if (PG_INT64_MAX / USECS_PER_SEC + PG_INT64_MAX % USECS_PER_SEC > DatumGetFloat8(epoch))
epoch = DirectFunctionCall2(float8mul, epoch, float_usecs_per_sec);
else if (PG_INT64_MAX / MSECS_PER_SEC + PG_INT64_MAX % MSECS_PER_SEC >
DatumGetFloat8(epoch))
epoch = DirectFunctionCall2(float8mul, epoch, float_msecs_per_sec);
/* Cast float8 to int8. */
width = DatumGetInt64(DirectFunctionCall1(dtoi8, epoch));
break;
Expand Down
Loading

0 comments on commit 20bd957

Please sign in to comment.