0001-Fix-uuidv7-with-pre-epoch-interval-silently-producin.patch
application/octet-stream
Filename: 0001-Fix-uuidv7-with-pre-epoch-interval-silently-producin.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0001
Subject: Fix uuidv7() with pre-epoch interval silently producing misordered UUID
| File | + | − |
|---|---|---|
| src/backend/utils/adt/uuid.c | 11 | 0 |
| src/test/regress/expected/uuid.out | 4 | 0 |
| src/test/regress/sql/uuid.sql | 3 | 0 |
From 22c0770e6e41c7914f3df80baaff846b6c9f589a Mon Sep 17 00:00:00 2001
From: Baji Shaik <baji.pgdev@gmail.com>
Date: Fri, 12 Jun 2026 17:30:04 -0500
Subject: [PATCH 1/3] Fix uuidv7() with pre-epoch interval silently producing
misordered UUID
uuidv7(interval) with a negative interval large enough to shift the
timestamp before the Unix epoch (1970-01-01) silently produces a UUID
whose encoded timestamp wraps around via unsigned integer overflow.
Fix by rejecting timestamps before the Unix epoch with a clear error.
This aligns with RFC 9562 Section 6.2.
---
src/backend/utils/adt/uuid.c | 11 +++++++++++
src/test/regress/expected/uuid.out | 4 ++++
src/test/regress/sql/uuid.sql | 3 +++
3 files changed, 18 insertions(+)
diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c
index 6ee3752ac78..c44858b6391 100644
--- a/src/backend/utils/adt/uuid.c
+++ b/src/backend/utils/adt/uuid.c
@@ -690,6 +690,17 @@ uuidv7_interval(PG_FUNCTION_ARGS)
/* Convert a TimestampTz value back to an UNIX epoch timestamp */
us = ts + (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY * USECS_PER_SEC;
+ /*
+ * UUID version 7 does not support timestamps before the Unix epoch.
+ * A negative value here would wrap when cast to uint64, producing a UUID
+ * with a bogus far-future timestamp that breaks sort ordering.
+ */
+ if (us < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range for UUID version 7"),
+ errdetail("UUID version 7 does not support timestamps before the Unix epoch.")));
+
/* Generate an UUIDv7 */
uuid = generate_uuidv7(us / US_PER_MS, (us % US_PER_MS) * NS_PER_US + ns % NS_PER_US);
diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out
index 9c5dda9e9ab..ea3c1adf412 100644
--- a/src/test/regress/expected/uuid.out
+++ b/src/test/regress/expected/uuid.out
@@ -318,6 +318,10 @@ SELECT uuid_extract_timestamp('11111111-1111-1111-1111-111111111111'); -- null
(1 row)
+-- uuidv7(interval) rejects timestamps before the Unix epoch
+SELECT uuidv7('-1000 years'::interval);
+ERROR: timestamp out of range for UUID version 7
+DETAIL: UUID version 7 does not support timestamps before the Unix epoch.
-- casts
SELECT '5b35380a-7143-4912-9b55-f322699c6770'::uuid::bytea;
bytea
diff --git a/src/test/regress/sql/uuid.sql b/src/test/regress/sql/uuid.sql
index 8cc2ad40614..15442f5f9e7 100644
--- a/src/test/regress/sql/uuid.sql
+++ b/src/test/regress/sql/uuid.sql
@@ -155,6 +155,9 @@ SELECT uuid_extract_timestamp('017F22E2-79B0-7CC3-98C4-DC0C0C07398F') = 'Tuesday
SELECT uuid_extract_timestamp(gen_random_uuid()); -- null
SELECT uuid_extract_timestamp('11111111-1111-1111-1111-111111111111'); -- null
+-- uuidv7(interval) rejects timestamps before the Unix epoch
+SELECT uuidv7('-1000 years'::interval);
+
-- casts
SELECT '5b35380a-7143-4912-9b55-f322699c6770'::uuid::bytea;
SELECT '\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid;
--
2.50.1 (Apple Git-155)