postgres.git / summary / log / commit / refs
commit 3f2fdd150eb04fe1da60e2a99f4ba2dd2be6443b
Author: Masahiko Sawada <msawada@postgresql.org>
Date: Tue Aug 04 20:41:02 2026 +0000
Add comments to uuid_extract_timestamp().
The timestamp-reassembly expressions in uuid_extract_timestamp() are
chains of shifted octets whose shift counts encode the field layout of
each UUID version, which is not otherwise recoverable from the code.
This commit documents, for UUIDv1, UUIDv6, and UUIDv7 alike, which
octets carry which part of the timestamp and where each part lands in
the reassembled value, citing the RFC section that defines it.
Author: Tristan Partin <tristan@partin.io>
Reviewed-by: MiĆosz Bieniek <bieniek.milosz@proton.me>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Discussion: https://postgr.es/m/DJHJW50YWKIT.XIOT4NOZRQ03@partin.io
src/backend/utils/adt/uuid.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c
index c0133c0b3e1..246225a8735 100644
--- a/src/backend/utils/adt/uuid.c
+++ b/src/backend/utils/adt/uuid.c
@@ -775,6 +775,19 @@ uuid_extract_timestamp(PG_FUNCTION_ARGS)
if (version == 1)
{
+ /*----------
+ * UUIDv1 splits the 60-bit Gregorian timestamp into three fields that
+ * are *not* stored most-significant-first (see RFC 9562 Sec. 5.1):
+ *
+ * time_low (bits 0-31) octets 0-3, the least significant 32 bits
+ * time_mid (bits 32-47) octets 4-5, the middle 16 bits
+ * time_high (bits 48-59) octet 6 low nibble + octet 7, the most
+ * significant 12 bits (octet 6 high nibble
+ * holds the version and is masked off)
+ *
+ * Reassemble the timestamp by shifting each field back to its place.
+ *----------
+ */
tms = ((uint64) uuid->data[0] << 24)
+ ((uint64) uuid->data[1] << 16)
+ ((uint64) uuid->data[2] << 8)
@@ -792,6 +805,25 @@ uuid_extract_timestamp(PG_FUNCTION_ARGS)
if (version == 6)
{
+ /*----------
+ * UUIDv6 is a field-compatible reordering of UUIDv1 that stores the
+ * 60-bit Gregorian timestamp most-significant-first (see RFC 9562
+ * Sec. 5.6):
+ *
+ * time_high (bits 28-59) octets 0-3, the most significant 32 bits
+ * time_mid (bits 12-27) octets 4-5, the middle 16 bits
+ * time_low (bits 0-11) octet 6 low nibble + octet 7, the least
+ * significant 12 bits (octet 6 high nibble
+ * holds the version and is masked off)
+ *
+ * Note that the 12-bit field is the least significant one here,
+ * while in UUIDv1 it is the most significant. The version nibble
+ * therefore sits below time_high and time_mid rather than above
+ * them, and compacting the timestamp squeezes it out: each of
+ * octets 0-5 ends up 4 bits lower than a plain big-endian read
+ * would put it, hence the 52/44/36/28/20/12 shift counts below.
+ *----------
+ */
tms = ((uint64) uuid->data[0] << 52)
+ ((uint64) uuid->data[1] << 44)
+ ((uint64) uuid->data[2] << 36)
@@ -809,6 +841,12 @@ uuid_extract_timestamp(PG_FUNCTION_ARGS)
if (version == 7)
{
+ /*
+ * UUIDv7 stores a 48-bit Unix timestamp in milliseconds (unix_ts_ms)
+ * most-significant-first in octets 0-5 (see RFC 9562 Sec. 5.7). There
+ * is no version nibble inside this field, so the bytes reassemble at
+ * clean 8-bit boundaries.
+ */
tms = (uuid->data[5])
+ (((uint64) uuid->data[4]) << 8)
+ (((uint64) uuid->data[3]) << 16)
[parent: 451871b740d7]