0001-UUDv7-fix-offset-computations-in-dates-after-2262.patch
application/octet-stream
Filename: 0001-UUDv7-fix-offset-computations-in-dates-after-2262.patch
Type: application/octet-stream
Part: 0
Message:
Re: UUID v7
Patch
Format: format-patch
Series: patch 0001
Subject: UUDv7: fix offset computations in dates after 2262
| File | + | − |
|---|---|---|
| src/backend/utils/adt/uuid.c | 14 | 12 |
From 8b52d0942f657c35e238bd95bd2d95aa5c4a5b2e Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Fri, 31 Jan 2025 12:03:16 +0500
Subject: [PATCH] UUDv7: fix offset computations in dates after 2262
We used nanosecond representation of offsetted time values which
cannot be stored in 64-bit integer for dates significantly after
beginning of UNIX epoch. To prevent overflow we separate millisecond
part from nanoseconds, thus allowing us to store both parts in 64-bit
integers.
---
src/backend/utils/adt/uuid.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c
index 4f8402ef925..3349c2674c8 100644
--- a/src/backend/utils/adt/uuid.c
+++ b/src/backend/utils/adt/uuid.c
@@ -68,7 +68,7 @@ static int uuid_fast_cmp(Datum x, Datum y, SortSupport ssup);
static bool uuid_abbrev_abort(int memtupcount, SortSupport ssup);
static Datum uuid_abbrev_convert(Datum original, SortSupport ssup);
static inline void uuid_set_version(pg_uuid_t *uuid, unsigned char version);
-static inline int64 get_real_time_ns_ascending();
+static inline uint64 get_real_time_ns_ascending();
Datum
uuid_in(PG_FUNCTION_ARGS)
@@ -476,11 +476,11 @@ gen_random_uuid(PG_FUNCTION_ARGS)
* The returned timestamp is ensured to be at least SUBMS_MINIMAL_STEP greater
* than the previous returned timestamp (on this backend).
*/
-static inline int64
+static inline uint64
get_real_time_ns_ascending()
{
- static int64 previous_ns = 0;
- int64 ns;
+ static uint64 previous_ns = 0;
+ uint64 ns;
/* Get the current real timestamp */
@@ -527,13 +527,13 @@ get_real_time_ns_ascending()
* used for time-dependent bits of UUID.
*/
static pg_uuid_t *
-generate_uuidv7(int64 ns)
+generate_uuidv7(uint64 ms, uint64 ns_in_ms)
{
pg_uuid_t *uuid = palloc(UUID_LEN);
int64 unix_ts_ms;
int32 increased_clock_precision;
- unix_ts_ms = ns / NS_PER_MS;
+ unix_ts_ms = ms;
/* Fill in time part */
uuid->data[0] = (unsigned char) (unix_ts_ms >> 40);
@@ -547,7 +547,7 @@ generate_uuidv7(int64 ns)
* sub-millisecond timestamp fraction (SUBMS_BITS bits, not
* SUBMS_MINIMAL_STEP_BITS)
*/
- increased_clock_precision = ((ns % NS_PER_MS) * (1 << SUBMS_BITS)) / NS_PER_MS;
+ increased_clock_precision = ((ns_in_ms) * (1 << SUBMS_BITS)) / NS_PER_MS;
/* Fill the increased clock precision to "rand_a" bits */
uuid->data[6] = (unsigned char) (increased_clock_precision >> 8);
@@ -586,7 +586,8 @@ generate_uuidv7(int64 ns)
Datum
uuidv7(PG_FUNCTION_ARGS)
{
- pg_uuid_t *uuid = generate_uuidv7(get_real_time_ns_ascending());
+ uint64 ns = get_real_time_ns_ascending();
+ pg_uuid_t *uuid = generate_uuidv7(ns / NS_PER_MS, ns % NS_PER_MS);
PG_RETURN_UUID_P(uuid);
}
@@ -600,7 +601,9 @@ uuidv7_interval(PG_FUNCTION_ARGS)
Interval *shift = PG_GETARG_INTERVAL_P(0);
TimestampTz ts;
pg_uuid_t *uuid;
- int64 ns = get_real_time_ns_ascending();
+ /* 64 bits is enough for real time, but not for a time range of UUID */
+ uint64 ns = get_real_time_ns_ascending();
+ uint64 us;
/*
* Shift the current timestamp by the given interval. To calculate time
@@ -621,11 +624,10 @@ uuidv7_interval(PG_FUNCTION_ARGS)
/*
* Convert a TimestampTz value back to an UNIX epoch and back nanoseconds.
*/
- ns = (ts + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY * USECS_PER_SEC)
- * NS_PER_US + ns % NS_PER_US;
+ us = (ts + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY * USECS_PER_SEC);
/* Generate an UUIDv7 */
- uuid = generate_uuidv7(ns);
+ uuid = generate_uuidv7(us / 1000, (us % 1000) * 1000 + ns % NS_PER_US);
PG_RETURN_UUID_P(uuid);
}
--
2.42.0