/*-------------------------------------------------------------------------
*
* UUID generation functions using the BSD , E2FS or OSSP UUID library
*
* Copyright ( c ) 2007 - 2025 , PostgreSQL Global Development Group
*
* Portions Copyright ( c ) 2009 Andrew Gierth
*
* contrib / uuid - ossp / uuid - ossp . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include "common/cryptohash.h"
#include "common/sha1.h"
#include "fmgr.h"
#include "port/pg_bswap.h"
#include "utils/builtins.h"
#include "utils/uuid.h"
#include "varatt.h"
/*
* It ' s possible that there ' s more than one uuid . h header file present .
* We expect configure to set the HAVE_ symbol for only the one we want .
*
* BSD includes a uuid_hash ( ) function that conflicts with the one in
* builtins . h ; we # define it out of the way .
*/
#define uuid_hash bsd_uuid_hash
#if defined (HAVE_UUID_H)
#include <uuid.h>
#elif defined (HAVE_OSSP_UUID_H)
#include <ossp/uuid.h>
#elif defined (HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
#else
#error "please use configure's --with-uuid switch to select a UUID library"
#endif
#undef uuid_hash
/* Check our UUID length against OSSP's; better both be 16 */
#if defined (HAVE_UUID_OSSP) && (UUID_LEN != UUID_LEN_BIN)
#error UUID length mismatch
#endif
/* Define some constants like OSSP's, to make the code more readable */
#ifndef HAVE_UUID_OSSP
#define UUID_MAKE_MC 0
#define UUID_MAKE_V1 1
#define UUID_MAKE_V2 2
#define UUID_MAKE_V3 3
#define UUID_MAKE_V4 4
#define UUID_MAKE_V5 5
#endif
/*
* A DCE 1 . 1 compatible source representation of UUIDs , derived from
* the BSD implementation . BSD already has this ; OSSP doesn ' t need it .
*/
#ifdef HAVE_UUID_E2FS
typedef struct
{
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_and_version;
uint8_t clock_seq_hi_and_reserved;
uint8_t clock_seq_low;
uint8_t node[6 ];
} dce_uuid_t;
#else
#define dce_uuid_t uuid_t
#endif
/* If not OSSP, we need some endianness-manipulation macros */
#ifndef HAVE_UUID_OSSP
#define UUID_TO_NETWORK(uu) \
do { \
uu.time_low = pg_hton32(uu.time_low); \
uu.time_mid = pg_hton16(uu.time_mid); \
uu.time_hi_and_version = pg_hton16(uu.time_hi_and_version); \
} while (0 )
#define UUID_TO_LOCAL(uu) \
do { \
uu.time_low = pg_ntoh32(uu.time_low); \
uu.time_mid = pg_ntoh16(uu.time_mid); \
uu.time_hi_and_version = pg_ntoh16(uu.time_hi_and_version); \
} while (0 )
#define UUID_V3_OR_V5(uu, v) \
do { \
uu.time_hi_and_version &= 0 x0FFF; \
uu.time_hi_and_version |= (v << 12 ); \
uu.clock_seq_hi_and_reserved &= 0 x3F; \
uu.clock_seq_hi_and_reserved |= 0 x80; \
} while (0 )
#endif /* !HAVE_UUID_OSSP */
PG_MODULE_MAGIC_EXT(
.name = "uuid-ossp" ,
.version = PG_VERSION
);
PG_FUNCTION_INFO_V1(uuid_nil);
PG_FUNCTION_INFO_V1(uuid_ns_dns);
PG_FUNCTION_INFO_V1(uuid_ns_url);
PG_FUNCTION_INFO_V1(uuid_ns_oid);
PG_FUNCTION_INFO_V1(uuid_ns_x500);
PG_FUNCTION_INFO_V1(uuid_generate_v1);
PG_FUNCTION_INFO_V1(uuid_generate_v1mc);
PG_FUNCTION_INFO_V1(uuid_generate_v3);
PG_FUNCTION_INFO_V1(uuid_generate_v4);
PG_FUNCTION_INFO_V1(uuid_generate_v5);
#ifdef HAVE_UUID_OSSP
static void
pguuid_complain(uuid_rc_t rc)
{
char *err = uuid_error(rc);
if (err != NULL)
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
errmsg("OSSP uuid library failure: %s" , err)));
else
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
errmsg("OSSP uuid library failure: error code %d" , rc)));
}
/*
* We create a uuid_t object just once per session and re - use it for all
* operations in this module . OSSP UUID caches the system MAC address and
* other state in this object . Reusing the object has a number of benefits :
* saving the cycles needed to fetch the system MAC address over and over ,
* reducing the amount of entropy we draw from / dev / urandom , and providing a
* positive guarantee that successive generated V1 - style UUIDs don ' t collide .
* ( On a machine fast enough to generate multiple UUIDs per microsecond ,
* or whatever the system ' s wall - clock resolution is , we ' d otherwise risk
* collisions whenever random initialization of the uuid_t ' s clock sequence
* value chanced to produce duplicates . )
*
* However : when we ' re doing V3 or V5 UUID creation , uuid_make needs two
* uuid_t objects , one holding the namespace UUID and one for the result .
* It ' s unspecified whether it ' s safe to use the same uuid_t for both cases ,
* so let ' s cache a second uuid_t for use as the namespace holder object .
*/
static uuid_t *
get_cached_uuid_t(int which)
{
static uuid_t *cached_uuid[2 ] = {NULL, NULL};
if (cached_uuid[which] == NULL)
{
uuid_rc_t rc;
rc = uuid_create(&cached_uuid[which]);
if (rc != UUID_RC_OK)
{
cached_uuid[which] = NULL;
pguuid_complain(rc);
}
}
return cached_uuid[which];
}
static char *
uuid_to_string(const uuid_t *uuid)
{
char *buf = palloc(UUID_LEN_STR + 1 );
void *ptr = buf;
size_t len = UUID_LEN_STR + 1 ;
uuid_rc_t rc;
rc = uuid_export(uuid, UUID_FMT_STR, &ptr, &len);
if (rc != UUID_RC_OK)
pguuid_complain(rc);
return buf;
}
static void
string_to_uuid(const char *str, uuid_t *uuid)
{
uuid_rc_t rc;
rc = uuid_import(uuid, UUID_FMT_STR, str, UUID_LEN_STR + 1 );
if (rc != UUID_RC_OK)
pguuid_complain(rc);
}
static Datum
special_uuid_value(const char *name)
{
uuid_t *uuid = get_cached_uuid_t(0 );
char *str;
uuid_rc_t rc;
rc = uuid_load(uuid, name);
if (rc != UUID_RC_OK)
pguuid_complain(rc);
str = uuid_to_string(uuid);
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
}
/* len is unused with OSSP, but we want to have the same number of args */
static Datum
uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
{
uuid_t *uuid = get_cached_uuid_t(0 );
char *str;
uuid_rc_t rc;
rc = uuid_make(uuid, mode, ns, name);
if (rc != UUID_RC_OK)
pguuid_complain(rc);
str = uuid_to_string(uuid);
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
}
static Datum
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
{
uuid_t *ns_uuid = get_cached_uuid_t(1 );
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out,
UUIDPGetDatum(ns))),
ns_uuid);
return uuid_generate_internal(mode,
ns_uuid,
text_to_cstring(name),
0 );
}
#else /* !HAVE_UUID_OSSP */
static Datum
uuid_generate_internal(int v, unsigned char *ns, const char *ptr, int len)
{
char strbuf[40 ];
switch (v)
{
case 0 : /* constant-value uuids */
strlcpy(strbuf, ptr, 37 );
break ;
case 1 : /* time/node-based uuids */
{
#ifdef HAVE_UUID_E2FS
uuid_t uu;
uuid_generate_time(uu);
uuid_unparse(uu, strbuf);
/*
* PTR , if set , replaces the trailing characters of the uuid ;
* this is to support v1mc , where a random multicast MAC is
* used instead of the physical one
*/
if (ptr && len <= 36 )
strcpy(strbuf + (36 - len), ptr);
#else /* BSD */
uuid_t uu;
uint32_t status = uuid_s_ok;
char *str = NULL;
uuid_create(&uu, &status);
if (status == uuid_s_ok)
{
uuid_to_string(&uu, &str, &status);
if (status == uuid_s_ok)
{
strlcpy(strbuf, str, 37 );
/*
* In recent NetBSD , uuid_create ( ) has started
* producing v4 instead of v1 UUIDs . Check the
* version field and complain if it ' s not v1 .
*/
if (strbuf[14 ] != '1' )
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
/* translator: %c will be a hex digit */
errmsg("uuid_create() produced a version %c UUID instead of the expected version 1" ,
strbuf[14 ])));
/*
* PTR , if set , replaces the trailing characters of
* the uuid ; this is to support v1mc , where a random
* multicast MAC is used instead of the physical one
*/
if (ptr && len <= 36 )
strcpy(strbuf + (36 - len), ptr);
}
free(str);
}
if (status != uuid_s_ok)
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
errmsg("uuid library failure: %d" ,
(int ) status)));
#endif
break ;
}
case 3 : /* namespace-based MD5 uuids */
case 5 : /* namespace-based SHA1 uuids */
{
dce_uuid_t uu;
#ifdef HAVE_UUID_BSD
uint32_t status = uuid_s_ok;
char *str = NULL;
#endif
if (v == 3 )
{
pg_cryptohash_ctx *ctx = pg_cryptohash_create(PG_MD5);
if (pg_cryptohash_init(ctx) < 0 )
elog(ERROR, "could not initialize %s context: %s" , "MD5" ,
pg_cryptohash_error(ctx));
if (pg_cryptohash_update(ctx, ns, sizeof (uu)) < 0 ||
pg_cryptohash_update(ctx, (unsigned char *) ptr, len) < 0 )
elog(ERROR, "could not update %s context: %s" , "MD5" ,
pg_cryptohash_error(ctx));
/* we assume sizeof MD5 result is 16, same as UUID size */
if (pg_cryptohash_final(ctx, (unsigned char *) &uu,
sizeof (uu)) < 0 )
elog(ERROR, "could not finalize %s context: %s" , "MD5" ,
pg_cryptohash_error(ctx));
pg_cryptohash_free(ctx);
}
else
{
pg_cryptohash_ctx *ctx = pg_cryptohash_create(PG_SHA1);
unsigned char sha1result[SHA1_DIGEST_LENGTH];
if (pg_cryptohash_init(ctx) < 0 )
elog(ERROR, "could not initialize %s context: %s" , "SHA1" ,
pg_cryptohash_error(ctx));
if (pg_cryptohash_update(ctx, ns, sizeof (uu)) < 0 ||
pg_cryptohash_update(ctx, (unsigned char *) ptr, len) < 0 )
elog(ERROR, "could not update %s context: %s" , "SHA1" ,
pg_cryptohash_error(ctx));
if (pg_cryptohash_final(ctx, sha1result, sizeof (sha1result)) < 0 )
elog(ERROR, "could not finalize %s context: %s" , "SHA1" ,
pg_cryptohash_error(ctx));
pg_cryptohash_free(ctx);
memcpy(&uu, sha1result, sizeof (uu));
}
/* the calculated hash is using local order */
UUID_TO_NETWORK(uu);
UUID_V3_OR_V5(uu, v);
#ifdef HAVE_UUID_E2FS
/* uuid_unparse expects local order */
UUID_TO_LOCAL(uu);
uuid_unparse((unsigned char *) &uu, strbuf);
#else /* BSD */
uuid_to_string(&uu, &str, &status);
if (status == uuid_s_ok)
strlcpy(strbuf, str, 37 );
free(str);
if (status != uuid_s_ok)
ereport(ERROR,
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
errmsg("uuid library failure: %d" ,
(int ) status)));
#endif
break ;
}
case 4 : /* random uuid */
default :
{
#ifdef HAVE_UUID_E2FS
uuid_t uu;
uuid_generate_random(uu);
uuid_unparse(uu, strbuf);
#else /* BSD */
snprintf(strbuf, sizeof (strbuf),
"%08lx-%04x-%04x-%04x-%04x%08lx" ,
(unsigned long ) arc4random(),
(unsigned ) (arc4random() & 0 xffff),
(unsigned ) ((arc4random() & 0 xfff) | 0 x4000),
(unsigned ) ((arc4random() & 0 x3fff) | 0 x8000),
(unsigned ) (arc4random() & 0 xffff),
(unsigned long ) arc4random());
#endif
break ;
}
}
return DirectFunctionCall1(uuid_in, CStringGetDatum(strbuf));
}
#endif /* HAVE_UUID_OSSP */
Datum
uuid_nil(PG_FUNCTION_ARGS)
{
#ifdef HAVE_UUID_OSSP
return special_uuid_value("nil" );
#else
return uuid_generate_internal(0 , NULL,
"00000000-0000-0000-0000-000000000000" , 36 );
#endif
}
Datum
uuid_ns_dns(PG_FUNCTION_ARGS)
{
#ifdef HAVE_UUID_OSSP
return special_uuid_value("ns:DNS" );
#else
return uuid_generate_internal(0 , NULL,
"6ba7b810-9dad-11d1-80b4-00c04fd430c8" , 36 );
#endif
}
Datum
uuid_ns_url(PG_FUNCTION_ARGS)
{
#ifdef HAVE_UUID_OSSP
return special_uuid_value("ns:URL" );
#else
return uuid_generate_internal(0 , NULL,
"6ba7b811-9dad-11d1-80b4-00c04fd430c8" , 36 );
#endif
}
Datum
uuid_ns_oid(PG_FUNCTION_ARGS)
{
#ifdef HAVE_UUID_OSSP
return special_uuid_value("ns:OID" );
#else
return uuid_generate_internal(0 , NULL,
"6ba7b812-9dad-11d1-80b4-00c04fd430c8" , 36 );
#endif
}
Datum
uuid_ns_x500(PG_FUNCTION_ARGS)
{
#ifdef HAVE_UUID_OSSP
return special_uuid_value("ns:X500" );
#else
return uuid_generate_internal(0 , NULL,
"6ba7b814-9dad-11d1-80b4-00c04fd430c8" , 36 );
#endif
}
Datum
uuid_generate_v1(PG_FUNCTION_ARGS)
{
return uuid_generate_internal(UUID_MAKE_V1, NULL, NULL, 0 );
}
Datum
uuid_generate_v1mc(PG_FUNCTION_ARGS)
{
#ifdef HAVE_UUID_OSSP
char *buf = NULL;
#elif defined (HAVE_UUID_E2FS)
char strbuf[40 ];
char *buf;
uuid_t uu;
uuid_generate_random(uu);
/* set IEEE802 multicast and local-admin bits */
((dce_uuid_t *) &uu)->node[0 ] |= 0 x03;
uuid_unparse(uu, strbuf);
buf = strbuf + 24 ;
#else /* BSD */
char buf[16 ];
/* set IEEE802 multicast and local-admin bits */
snprintf(buf, sizeof (buf), "-%04x%08lx" ,
(unsigned ) ((arc4random() & 0 xffff) | 0 x0300),
(unsigned long ) arc4random());
#endif
return uuid_generate_internal(UUID_MAKE_V1 | UUID_MAKE_MC, NULL,
buf, 13 );
}
Datum
uuid_generate_v3(PG_FUNCTION_ARGS)
{
pg_uuid_t *ns = PG_GETARG_UUID_P(0 );
text *name = PG_GETARG_TEXT_PP(1 );
#ifdef HAVE_UUID_OSSP
return uuid_generate_v35_internal(UUID_MAKE_V3, ns, name);
#else
return uuid_generate_internal(UUID_MAKE_V3, (unsigned char *) ns,
VARDATA_ANY(name), VARSIZE_ANY_EXHDR(name));
#endif
}
Datum
uuid_generate_v4(PG_FUNCTION_ARGS)
{
return uuid_generate_internal(UUID_MAKE_V4, NULL, NULL, 0 );
}
Datum
uuid_generate_v5(PG_FUNCTION_ARGS)
{
pg_uuid_t *ns = PG_GETARG_UUID_P(0 );
text *name = PG_GETARG_TEXT_PP(1 );
#ifdef HAVE_UUID_OSSP
return uuid_generate_v35_internal(UUID_MAKE_V5, ns, name);
#else
return uuid_generate_internal(UUID_MAKE_V5, (unsigned char *) ns,
VARDATA_ANY(name), VARSIZE_ANY_EXHDR(name));
#endif
}
Messung V0.5 in Prozent C=94 H=93 G=93
¤ Dauer der Verarbeitung: 0.47 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland