Commit 5925e554 authored by Peter Eisentraut's avatar Peter Eisentraut

Add gen_random_uuid function

This adds a built-in function to generate UUIDs.

PostgreSQL hasn't had a built-in function to generate a UUID yet,
relying on external modules such as uuid-ossp and pgcrypto to provide
one.  Now that we have a strong random number generator built-in, we
can easily provide a version 4 (random) UUID generation function.

This patch takes the existing function gen_random_uuid() from pgcrypto
and makes it a built-in function.  The pgcrypto implementation now
internally redirects to the built-in one.
Reviewed-by: default avatarFabien COELHO <coelho@cri.ensmp.fr>
Discussion: https://www.postgresql.org/message-id/6a65610c-46fc-2323-6b78-e8086340a325@2ndquadrant.com
parent 565f3390
...@@ -446,20 +446,8 @@ PG_FUNCTION_INFO_V1(pg_random_uuid); ...@@ -446,20 +446,8 @@ PG_FUNCTION_INFO_V1(pg_random_uuid);
Datum Datum
pg_random_uuid(PG_FUNCTION_ARGS) pg_random_uuid(PG_FUNCTION_ARGS)
{ {
uint8 *buf = (uint8 *) palloc(UUID_LEN); /* redirect to built-in function */
return gen_random_uuid(fcinfo);
/* Generate random bits. */
if (!pg_strong_random(buf, UUID_LEN))
px_THROW_ERROR(PXE_NO_RANDOM);
/*
* Set magic numbers for a "version 4" (pseudorandom) UUID, see
* http://tools.ietf.org/html/rfc4122#section-4.4
*/
buf[6] = (buf[6] & 0x0f) | 0x40; /* "version" field */
buf[8] = (buf[8] & 0x3f) | 0x80; /* "variant" field */
PG_RETURN_UUID_P((pg_uuid_t *) buf);
} }
static void * static void *
......
...@@ -4195,16 +4195,8 @@ a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11 ...@@ -4195,16 +4195,8 @@ a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
</para> </para>
<para> <para>
<productname>PostgreSQL</productname> provides storage and comparison See <xref linkend="functions-uuid"/> for how to generate a UUID in
functions for UUIDs, but the core database does not include any <productname>PostgreSQL</productname>.
function for generating UUIDs, because no single algorithm is well
suited for every application. The <xref
linkend="uuid-ossp"/> module
provides functions that implement several standard algorithms.
The <xref linkend="pgcrypto"/> module also provides a generation
function for random UUIDs.
Alternatively, UUIDs could be generated by client applications or
other libraries invoked through a server-side function.
</para> </para>
</sect1> </sect1>
......
...@@ -10267,6 +10267,32 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple ...@@ -10267,6 +10267,32 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
</sect1> </sect1>
<sect1 id="functions-uuid">
<title>UUID Functions</title>
<indexterm zone="datatype-uuid">
<primary>UUID</primary>
<secondary>generating</secondary>
</indexterm>
<indexterm>
<primary>gen_random_uuid</primary>
</indexterm>
<para>
<productname>PostgreSQL</productname> includes one function to generate a UUID:
<synopsis>
gen_random_uuid() returns uuid
</synopsis>
This function returns a version 4 (random) UUID. This is the most commonly
used type of UUID and is appropriate for most applications.
</para>
<para>
The <xref linkend="uuid-ossp"/> module provides additional functions that
implement other standard algorithms for generating UUIDs.
</para>
</sect1>
<sect1 id="functions-xml"> <sect1 id="functions-xml">
......
...@@ -1132,7 +1132,8 @@ gen_random_bytes(count integer) returns bytea ...@@ -1132,7 +1132,8 @@ gen_random_bytes(count integer) returns bytea
gen_random_uuid() returns uuid gen_random_uuid() returns uuid
</synopsis> </synopsis>
<para> <para>
Returns a version 4 (random) UUID. Returns a version 4 (random) UUID. (Obsolete, this function is now also
included in core <productname>PostgreSQL</productname>.)
</para> </para>
</sect2> </sect2>
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
The <filename>uuid-ossp</filename> module provides functions to generate universally The <filename>uuid-ossp</filename> module provides functions to generate universally
unique identifiers (UUIDs) using one of several standard algorithms. There unique identifiers (UUIDs) using one of several standard algorithms. There
are also functions to produce certain special UUID constants. are also functions to produce certain special UUID constants.
This module is only necessary for special requirements beyond what is
available in core <productname>PostgreSQL</productname>. See <xref
linkend="functions-uuid"/> for built-in ways to generate UUIDs.
</para> </para>
<sect2> <sect2>
...@@ -181,14 +184,6 @@ SELECT uuid_generate_v3(uuid_ns_url(), 'http://www.postgresql.org'); ...@@ -181,14 +184,6 @@ SELECT uuid_generate_v3(uuid_ns_url(), 'http://www.postgresql.org');
More than one of these libraries might be available on a particular More than one of these libraries might be available on a particular
machine, so <filename>configure</filename> does not automatically choose one. machine, so <filename>configure</filename> does not automatically choose one.
</para> </para>
<note>
<para>
If you only need randomly-generated (version 4) UUIDs,
consider using the <function>gen_random_uuid()</function> function
from the <xref linkend="pgcrypto"/> module instead.
</para>
</note>
</sect2> </sect2>
<sect2> <sect2>
......
...@@ -416,3 +416,23 @@ uuid_hash_extended(PG_FUNCTION_ARGS) ...@@ -416,3 +416,23 @@ uuid_hash_extended(PG_FUNCTION_ARGS)
return hash_any_extended(key->data, UUID_LEN, PG_GETARG_INT64(1)); return hash_any_extended(key->data, UUID_LEN, PG_GETARG_INT64(1));
} }
Datum
gen_random_uuid(PG_FUNCTION_ARGS)
{
pg_uuid_t *uuid = palloc(UUID_LEN);
if (!pg_strong_random(uuid, UUID_LEN))
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("could not generate random values")));
/*
* Set magic numbers for a "version 4" (pseudorandom) UUID, see
* http://tools.ietf.org/html/rfc4122#section-4.4
*/
uuid->data[6] = (uuid->data[6] & 0x0f) | 0x40; /* time_hi_and_version */
uuid->data[8] = (uuid->data[8] & 0x3f) | 0x80; /* clock_seq_hi_and_reserved */
PG_RETURN_UUID_P(uuid);
}
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201907141 #define CATALOG_VERSION_NO 201907142
#endif #endif
...@@ -8376,6 +8376,9 @@ ...@@ -8376,6 +8376,9 @@
{ oid => '3412', descr => 'hash', { oid => '3412', descr => 'hash',
proname => 'uuid_hash_extended', prorettype => 'int8', proname => 'uuid_hash_extended', prorettype => 'int8',
proargtypes => 'uuid int8', prosrc => 'uuid_hash_extended' }, proargtypes => 'uuid int8', prosrc => 'uuid_hash_extended' },
{ oid => '3432', descr => 'generate random UUID',
proname => 'gen_random_uuid', proleakproof => 't', prorettype => 'uuid',
proargtypes => '', prosrc => 'gen_random_uuid' },
# pg_lsn # pg_lsn
{ oid => '3229', descr => 'I/O', { oid => '3229', descr => 'I/O',
......
...@@ -742,6 +742,7 @@ sha224(bytea) ...@@ -742,6 +742,7 @@ sha224(bytea)
sha256(bytea) sha256(bytea)
sha384(bytea) sha384(bytea)
sha512(bytea) sha512(bytea)
gen_random_uuid()
starts_with(text,text) starts_with(text,text)
macaddr8_eq(macaddr8,macaddr8) macaddr8_eq(macaddr8,macaddr8)
macaddr8_lt(macaddr8,macaddr8) macaddr8_lt(macaddr8,macaddr8)
......
...@@ -145,5 +145,15 @@ SELECT COUNT(*) FROM guid1 g1 LEFT JOIN guid2 g2 ON g1.guid_field = g2.guid_fiel ...@@ -145,5 +145,15 @@ SELECT COUNT(*) FROM guid1 g1 LEFT JOIN guid2 g2 ON g1.guid_field = g2.guid_fiel
1 1
(1 row) (1 row)
-- generation test
TRUNCATE guid1;
INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid());
INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid());
SELECT count(DISTINCT guid_field) FROM guid1;
count
-------
2
(1 row)
-- clean up -- clean up
DROP TABLE guid1, guid2 CASCADE; DROP TABLE guid1, guid2 CASCADE;
...@@ -75,5 +75,11 @@ INSERT INTO guid2(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e'); ...@@ -75,5 +75,11 @@ INSERT INTO guid2(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e');
SELECT COUNT(*) FROM guid1 g1 INNER JOIN guid2 g2 ON g1.guid_field = g2.guid_field; SELECT COUNT(*) FROM guid1 g1 INNER JOIN guid2 g2 ON g1.guid_field = g2.guid_field;
SELECT COUNT(*) FROM guid1 g1 LEFT JOIN guid2 g2 ON g1.guid_field = g2.guid_field WHERE g2.guid_field IS NULL; SELECT COUNT(*) FROM guid1 g1 LEFT JOIN guid2 g2 ON g1.guid_field = g2.guid_field WHERE g2.guid_field IS NULL;
-- generation test
TRUNCATE guid1;
INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid());
INSERT INTO guid1 (guid_field) VALUES (gen_random_uuid());
SELECT count(DISTINCT guid_field) FROM guid1;
-- clean up -- clean up
DROP TABLE guid1, guid2 CASCADE; DROP TABLE guid1, guid2 CASCADE;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment