Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 794f10f

Browse files
committed
Add some UUID support functions
Add uuid_extract_timestamp() and uuid_extract_version(). Author: Andrey Borodin Reviewed-by: Sergey Prokhorenko, Kirk Wolak, Przemysław Sztoch Reviewed-by: Nikolay Samokhvalov, Jelte Fennema-Nio, Aleksander Alekseev Reviewed-by: Peter Eisentraut, Chris Travers, Lukas Fittl Discussion: https://postgr.es/m/CAAhFRxitJv%3DyoGnXUgeLB_O%2BM7J2BJAmb5jqAT9gZ3bij3uLDA%40mail.gmail.com
1 parent d56cb42 commit 794f10f

File tree

7 files changed

+157
-1
lines changed

7 files changed

+157
-1
lines changed

doc/src/sgml/func.sgml

+30
Original file line numberDiff line numberDiff line change
@@ -14127,6 +14127,14 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
1412714127
<primary>gen_random_uuid</primary>
1412814128
</indexterm>
1412914129

14130+
<indexterm>
14131+
<primary>uuid_extract_timestamp</primary>
14132+
</indexterm>
14133+
14134+
<indexterm>
14135+
<primary>uuid_extract_version</primary>
14136+
</indexterm>
14137+
1413014138
<para>
1413114139
<productname>PostgreSQL</productname> includes one function to generate a UUID:
1413214140
<synopsis>
@@ -14141,6 +14149,28 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
1414114149
implement other standard algorithms for generating UUIDs.
1414214150
</para>
1414314151

14152+
<para>
14153+
There are also functions to extract data from UUIDs:
14154+
<synopsis>
14155+
<function>uuid_extract_timestamp</function> (uuid) <returnvalue>timestamp with time zone</returnvalue>
14156+
</synopsis>
14157+
This function extracts a <type>timestamp with time zone</type> from UUID
14158+
version 1. For other versions, this function returns null. Note that the
14159+
extracted timestamp is not necessarily exactly equal to the time the UUID
14160+
was generated; this depends on the implementation that generated the UUID.
14161+
</para>
14162+
14163+
<para>
14164+
<synopsis>
14165+
<function>uuid_extract_version</function> (uuid) <returnvalue>smallint</returnvalue>
14166+
</synopsis>
14167+
This function extracts the version from a UUID of the variant described by
14168+
<ulink url="https://tools.ietf.org/html/rfc4122">RFC 4122</ulink>. For
14169+
other variants, this function returns null. For example, for a UUID
14170+
generated by <function>gen_random_uuid</function>, this function will
14171+
return 4.
14172+
</para>
14173+
1414414174
<para>
1414514175
<productname>PostgreSQL</productname> also provides the usual comparison
1414614176
operators shown in <xref linkend="functions-comparison-op-table"/> for

src/backend/utils/adt/uuid.c

+64
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "utils/fmgrprotos.h"
2121
#include "utils/guc.h"
2222
#include "utils/sortsupport.h"
23+
#include "utils/timestamp.h"
2324
#include "utils/uuid.h"
2425

2526
/* sortsupport for uuid */
@@ -425,3 +426,66 @@ gen_random_uuid(PG_FUNCTION_ARGS)
425426

426427
PG_RETURN_UUID_P(uuid);
427428
}
429+
430+
#define UUIDV1_EPOCH_JDATE 2299161 /* == date2j(1582,10,15) */
431+
432+
/*
433+
* Extract timestamp from UUID.
434+
*
435+
* Returns null if not RFC 4122 variant or not a version that has a timestamp.
436+
*/
437+
Datum
438+
uuid_extract_timestamp(PG_FUNCTION_ARGS)
439+
{
440+
pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
441+
int version;
442+
uint64 tms;
443+
TimestampTz ts;
444+
445+
/* check if RFC 4122 variant */
446+
if ((uuid->data[8] & 0xc0) != 0x80)
447+
PG_RETURN_NULL();
448+
449+
version = uuid->data[6] >> 4;
450+
451+
if (version == 1)
452+
{
453+
tms = ((uint64) uuid->data[0] << 24)
454+
+ ((uint64) uuid->data[1] << 16)
455+
+ ((uint64) uuid->data[2] << 8)
456+
+ ((uint64) uuid->data[3])
457+
+ ((uint64) uuid->data[4] << 40)
458+
+ ((uint64) uuid->data[5] << 32)
459+
+ (((uint64) uuid->data[6] & 0xf) << 56)
460+
+ ((uint64) uuid->data[7] << 48);
461+
462+
/* convert 100-ns intervals to us, then adjust */
463+
ts = (TimestampTz) (tms / 10) -
464+
((uint64) POSTGRES_EPOCH_JDATE - UUIDV1_EPOCH_JDATE) * SECS_PER_DAY * USECS_PER_SEC;
465+
466+
PG_RETURN_TIMESTAMPTZ(ts);
467+
}
468+
469+
/* not a timestamp-containing UUID version */
470+
PG_RETURN_NULL();
471+
}
472+
473+
/*
474+
* Extract UUID version.
475+
*
476+
* Returns null if not RFC 4122 variant.
477+
*/
478+
Datum
479+
uuid_extract_version(PG_FUNCTION_ARGS)
480+
{
481+
pg_uuid_t *uuid = PG_GETARG_UUID_P(0);
482+
uint16 version;
483+
484+
/* check if RFC 4122 variant */
485+
if ((uuid->data[8] & 0xc0) != 0x80)
486+
PG_RETURN_NULL();
487+
488+
version = uuid->data[6] >> 4;
489+
490+
PG_RETURN_UINT16(version);
491+
}

src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/* yyyymmddN */
60-
#define CATALOG_VERSION_NO 202403181
60+
#define CATALOG_VERSION_NO 202403191
6161

6262
#endif

src/include/catalog/pg_proc.dat

+7
Original file line numberDiff line numberDiff line change
@@ -9170,6 +9170,13 @@
91709170
{ oid => '3432', descr => 'generate random UUID',
91719171
proname => 'gen_random_uuid', proleakproof => 't', provolatile => 'v',
91729172
prorettype => 'uuid', proargtypes => '', prosrc => 'gen_random_uuid' },
9173+
{ oid => '9897', descr => 'extract timestamp from UUID',
9174+
proname => 'uuid_extract_timestamp', proleakproof => 't',
9175+
prorettype => 'timestamptz', proargtypes => 'uuid',
9176+
prosrc => 'uuid_extract_timestamp' },
9177+
{ oid => '9898', descr => 'extract version from RFC 4122 UUID',
9178+
proname => 'uuid_extract_version', proleakproof => 't', prorettype => 'int2',
9179+
proargtypes => 'uuid', prosrc => 'uuid_extract_version' },
91739180

91749181
# pg_lsn
91759182
{ oid => '3229', descr => 'I/O',

src/test/regress/expected/opr_sanity.out

+2
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,8 @@ xid8ge(xid8,xid8)
872872
xid8eq(xid8,xid8)
873873
xid8ne(xid8,xid8)
874874
xid8cmp(xid8,xid8)
875+
uuid_extract_timestamp(uuid)
876+
uuid_extract_version(uuid)
875877
-- restore normal output mode
876878
\a\t
877879
-- List of functions used by libpq's fe-lobj.c

src/test/regress/expected/uuid.out

+39
Original file line numberDiff line numberDiff line change
@@ -168,5 +168,44 @@ SELECT count(DISTINCT guid_field) FROM guid1;
168168
2
169169
(1 row)
170170

171+
-- extract functions
172+
-- version
173+
SELECT uuid_extract_version('11111111-1111-5111-8111-111111111111'); -- 5
174+
uuid_extract_version
175+
----------------------
176+
5
177+
(1 row)
178+
179+
SELECT uuid_extract_version(gen_random_uuid()); -- 4
180+
uuid_extract_version
181+
----------------------
182+
4
183+
(1 row)
184+
185+
SELECT uuid_extract_version('11111111-1111-1111-1111-111111111111'); -- null
186+
uuid_extract_version
187+
----------------------
188+
189+
(1 row)
190+
191+
-- timestamp
192+
SELECT uuid_extract_timestamp('C232AB00-9414-11EC-B3C8-9F6BDECED846') = 'Tuesday, February 22, 2022 2:22:22.00 PM GMT+05:00'; -- RFC 4122bis test vector
193+
?column?
194+
----------
195+
t
196+
(1 row)
197+
198+
SELECT uuid_extract_timestamp(gen_random_uuid()); -- null
199+
uuid_extract_timestamp
200+
------------------------
201+
202+
(1 row)
203+
204+
SELECT uuid_extract_timestamp('11111111-1111-1111-1111-111111111111'); -- null
205+
uuid_extract_timestamp
206+
------------------------
207+
208+
(1 row)
209+
171210
-- clean up
172211
DROP TABLE guid1, guid2 CASCADE;

src/test/regress/sql/uuid.sql

+14
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,19 @@ INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid());
8585
INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid());
8686
SELECT count(DISTINCT guid_field) FROM guid1;
8787

88+
89+
-- extract functions
90+
91+
-- version
92+
SELECT uuid_extract_version('11111111-1111-5111-8111-111111111111'); -- 5
93+
SELECT uuid_extract_version(gen_random_uuid()); -- 4
94+
SELECT uuid_extract_version('11111111-1111-1111-1111-111111111111'); -- null
95+
96+
-- timestamp
97+
SELECT uuid_extract_timestamp('C232AB00-9414-11EC-B3C8-9F6BDECED846') = 'Tuesday, February 22, 2022 2:22:22.00 PM GMT+05:00'; -- RFC 4122bis test vector
98+
SELECT uuid_extract_timestamp(gen_random_uuid()); -- null
99+
SELECT uuid_extract_timestamp('11111111-1111-1111-1111-111111111111'); -- null
100+
101+
88102
-- clean up
89103
DROP TABLE guid1, guid2 CASCADE;

0 commit comments

Comments
 (0)