diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 13:44:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 13:44:03 +0000 |
commit | 293913568e6a7a86fd1479e1cff8e2ecb58d6568 (patch) | |
tree | fc3b469a3ec5ab71b36ea97cc7aaddb838423a0c /contrib/uuid-ossp | |
parent | Initial commit. (diff) | |
download | postgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.tar.xz postgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.zip |
Adding upstream version 16.2.upstream/16.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/uuid-ossp')
-rw-r--r-- | contrib/uuid-ossp/.gitignore | 4 | ||||
-rw-r--r-- | contrib/uuid-ossp/Makefile | 25 | ||||
-rw-r--r-- | contrib/uuid-ossp/expected/uuid_ossp.out | 139 | ||||
-rw-r--r-- | contrib/uuid-ossp/meson.build | 41 | ||||
-rw-r--r-- | contrib/uuid-ossp/sql/uuid_ossp.sql | 75 | ||||
-rw-r--r-- | contrib/uuid-ossp/uuid-ossp--1.0--1.1.sql | 15 | ||||
-rw-r--r-- | contrib/uuid-ossp/uuid-ossp--1.1.sql | 54 | ||||
-rw-r--r-- | contrib/uuid-ossp/uuid-ossp.c | 552 | ||||
-rw-r--r-- | contrib/uuid-ossp/uuid-ossp.control | 6 |
9 files changed, 911 insertions, 0 deletions
diff --git a/contrib/uuid-ossp/.gitignore b/contrib/uuid-ossp/.gitignore new file mode 100644 index 0000000..5dcb3ff --- /dev/null +++ b/contrib/uuid-ossp/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/uuid-ossp/Makefile b/contrib/uuid-ossp/Makefile new file mode 100644 index 0000000..e126ce1 --- /dev/null +++ b/contrib/uuid-ossp/Makefile @@ -0,0 +1,25 @@ +# contrib/uuid-ossp/Makefile + +MODULE_big = uuid-ossp +OBJS = \ + $(WIN32RES) \ + uuid-ossp.o + +EXTENSION = uuid-ossp +DATA = uuid-ossp--1.1.sql uuid-ossp--1.0--1.1.sql +PGFILEDESC = "uuid-ossp - UUID generation" + +REGRESS = uuid_ossp + +SHLIB_LINK += $(UUID_LIBS) + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/uuid-ossp +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/uuid-ossp/expected/uuid_ossp.out b/contrib/uuid-ossp/expected/uuid_ossp.out new file mode 100644 index 0000000..409c885 --- /dev/null +++ b/contrib/uuid-ossp/expected/uuid_ossp.out @@ -0,0 +1,139 @@ +CREATE EXTENSION "uuid-ossp"; +SELECT uuid_nil(); + uuid_nil +-------------------------------------- + 00000000-0000-0000-0000-000000000000 +(1 row) + +SELECT uuid_ns_dns(); + uuid_ns_dns +-------------------------------------- + 6ba7b810-9dad-11d1-80b4-00c04fd430c8 +(1 row) + +SELECT uuid_ns_url(); + uuid_ns_url +-------------------------------------- + 6ba7b811-9dad-11d1-80b4-00c04fd430c8 +(1 row) + +SELECT uuid_ns_oid(); + uuid_ns_oid +-------------------------------------- + 6ba7b812-9dad-11d1-80b4-00c04fd430c8 +(1 row) + +SELECT uuid_ns_x500(); + uuid_ns_x500 +-------------------------------------- + 6ba7b814-9dad-11d1-80b4-00c04fd430c8 +(1 row) + +-- some quick and dirty field extraction functions +-- this is actually timestamp concatenated with clock sequence, per RFC 4122 +CREATE FUNCTION uuid_timestamp_bits(uuid) RETURNS varbit AS +$$ SELECT ('x' || substr($1::text, 15, 4) || substr($1::text, 10, 4) || + substr($1::text, 1, 8) || substr($1::text, 20, 4))::bit(80) + & x'0FFFFFFFFFFFFFFF3FFF' $$ +LANGUAGE SQL STRICT IMMUTABLE; +CREATE FUNCTION uuid_version_bits(uuid) RETURNS varbit AS +$$ SELECT ('x' || substr($1::text, 15, 2))::bit(8) & '11110000' $$ +LANGUAGE SQL STRICT IMMUTABLE; +CREATE FUNCTION uuid_reserved_bits(uuid) RETURNS varbit AS +$$ SELECT ('x' || substr($1::text, 20, 2))::bit(8) & '11000000' $$ +LANGUAGE SQL STRICT IMMUTABLE; +CREATE FUNCTION uuid_multicast_bit(uuid) RETURNS bool AS +$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000001') != '00000000' $$ +LANGUAGE SQL STRICT IMMUTABLE; +CREATE FUNCTION uuid_local_admin_bit(uuid) RETURNS bool AS +$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000010') != '00000000' $$ +LANGUAGE SQL STRICT IMMUTABLE; +CREATE FUNCTION uuid_node(uuid) RETURNS text AS +$$ SELECT substr($1::text, 25) $$ +LANGUAGE SQL STRICT IMMUTABLE; +-- Ideally, the multicast bit would never be set in V1 output, but the +-- UUID library may fall back to MC if it can't get the system MAC address. +-- Also, the local-admin bit might be set (if so, we're probably inside a VM). +-- So we can't test either bit here. +SELECT uuid_version_bits(uuid_generate_v1()), + uuid_reserved_bits(uuid_generate_v1()); + uuid_version_bits | uuid_reserved_bits +-------------------+-------------------- + 00010000 | 10000000 +(1 row) + +-- Although RFC 4122 only requires the multicast bit to be set in V1MC style +-- UUIDs, our implementation always sets the local-admin bit as well. +SELECT uuid_version_bits(uuid_generate_v1mc()), + uuid_reserved_bits(uuid_generate_v1mc()), + uuid_multicast_bit(uuid_generate_v1mc()), + uuid_local_admin_bit(uuid_generate_v1mc()); + uuid_version_bits | uuid_reserved_bits | uuid_multicast_bit | uuid_local_admin_bit +-------------------+--------------------+--------------------+---------------------- + 00010000 | 10000000 | t | t +(1 row) + +-- timestamp+clock sequence should be monotonic increasing in v1 +SELECT uuid_timestamp_bits(uuid_generate_v1()) < uuid_timestamp_bits(uuid_generate_v1()); + ?column? +---------- + t +(1 row) + +SELECT uuid_timestamp_bits(uuid_generate_v1mc()) < uuid_timestamp_bits(uuid_generate_v1mc()); + ?column? +---------- + t +(1 row) + +-- Ideally, the node value is stable in V1 addresses, but OSSP UUID +-- falls back to V1MC behavior if it can't get the system MAC address. +SELECT CASE WHEN uuid_multicast_bit(uuid_generate_v1()) AND + uuid_local_admin_bit(uuid_generate_v1()) THEN + true -- punt, no test + ELSE + uuid_node(uuid_generate_v1()) = uuid_node(uuid_generate_v1()) + END; + case +------ + t +(1 row) + +-- In any case, V1MC node addresses should be random. +SELECT uuid_node(uuid_generate_v1()) <> uuid_node(uuid_generate_v1mc()); + ?column? +---------- + t +(1 row) + +SELECT uuid_node(uuid_generate_v1mc()) <> uuid_node(uuid_generate_v1mc()); + ?column? +---------- + t +(1 row) + +SELECT uuid_generate_v3(uuid_ns_dns(), 'www.widgets.com'); + uuid_generate_v3 +-------------------------------------- + 3d813cbb-47fb-32ba-91df-831e1593ac29 +(1 row) + +SELECT uuid_generate_v5(uuid_ns_dns(), 'www.widgets.com'); + uuid_generate_v5 +-------------------------------------- + 21f7f8de-8051-5b89-8680-0195ef798b6a +(1 row) + +SELECT uuid_version_bits(uuid_generate_v4()), + uuid_reserved_bits(uuid_generate_v4()); + uuid_version_bits | uuid_reserved_bits +-------------------+-------------------- + 01000000 | 10000000 +(1 row) + +SELECT uuid_generate_v4() <> uuid_generate_v4(); + ?column? +---------- + t +(1 row) + diff --git a/contrib/uuid-ossp/meson.build b/contrib/uuid-ossp/meson.build new file mode 100644 index 0000000..b9fe603 --- /dev/null +++ b/contrib/uuid-ossp/meson.build @@ -0,0 +1,41 @@ +# Copyright (c) 2022-2023, PostgreSQL Global Development Group + +if not uuid.found() + subdir_done() +endif + +uuid_ossp_sources = files( + 'uuid-ossp.c', +) + +if host_system == 'windows' + uuid_ossp_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'uuid-ossp', + '--FILEDESC', 'uuid-ossp - UUID generation',]) +endif + +uuid_ossp = shared_module('uuid-ossp', + uuid_ossp_sources, + kwargs: contrib_mod_args + { + 'dependencies': [uuid, contrib_mod_args['dependencies']], + }, +) +contrib_targets += uuid_ossp + +install_data( + 'uuid-ossp--1.0--1.1.sql', + 'uuid-ossp--1.1.sql', + 'uuid-ossp.control', + kwargs: contrib_data_args, +) + +tests += { + 'name': 'uuid-ossp', + 'sd': meson.current_source_dir(), + 'bd': meson.current_build_dir(), + 'regress': { + 'sql': [ + 'uuid_ossp', + ], + }, +} diff --git a/contrib/uuid-ossp/sql/uuid_ossp.sql b/contrib/uuid-ossp/sql/uuid_ossp.sql new file mode 100644 index 0000000..b4237df --- /dev/null +++ b/contrib/uuid-ossp/sql/uuid_ossp.sql @@ -0,0 +1,75 @@ +CREATE EXTENSION "uuid-ossp"; + +SELECT uuid_nil(); +SELECT uuid_ns_dns(); +SELECT uuid_ns_url(); +SELECT uuid_ns_oid(); +SELECT uuid_ns_x500(); + +-- some quick and dirty field extraction functions + +-- this is actually timestamp concatenated with clock sequence, per RFC 4122 +CREATE FUNCTION uuid_timestamp_bits(uuid) RETURNS varbit AS +$$ SELECT ('x' || substr($1::text, 15, 4) || substr($1::text, 10, 4) || + substr($1::text, 1, 8) || substr($1::text, 20, 4))::bit(80) + & x'0FFFFFFFFFFFFFFF3FFF' $$ +LANGUAGE SQL STRICT IMMUTABLE; + +CREATE FUNCTION uuid_version_bits(uuid) RETURNS varbit AS +$$ SELECT ('x' || substr($1::text, 15, 2))::bit(8) & '11110000' $$ +LANGUAGE SQL STRICT IMMUTABLE; + +CREATE FUNCTION uuid_reserved_bits(uuid) RETURNS varbit AS +$$ SELECT ('x' || substr($1::text, 20, 2))::bit(8) & '11000000' $$ +LANGUAGE SQL STRICT IMMUTABLE; + +CREATE FUNCTION uuid_multicast_bit(uuid) RETURNS bool AS +$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000001') != '00000000' $$ +LANGUAGE SQL STRICT IMMUTABLE; + +CREATE FUNCTION uuid_local_admin_bit(uuid) RETURNS bool AS +$$ SELECT (('x' || substr($1::text, 25, 2))::bit(8) & '00000010') != '00000000' $$ +LANGUAGE SQL STRICT IMMUTABLE; + +CREATE FUNCTION uuid_node(uuid) RETURNS text AS +$$ SELECT substr($1::text, 25) $$ +LANGUAGE SQL STRICT IMMUTABLE; + +-- Ideally, the multicast bit would never be set in V1 output, but the +-- UUID library may fall back to MC if it can't get the system MAC address. +-- Also, the local-admin bit might be set (if so, we're probably inside a VM). +-- So we can't test either bit here. +SELECT uuid_version_bits(uuid_generate_v1()), + uuid_reserved_bits(uuid_generate_v1()); + +-- Although RFC 4122 only requires the multicast bit to be set in V1MC style +-- UUIDs, our implementation always sets the local-admin bit as well. +SELECT uuid_version_bits(uuid_generate_v1mc()), + uuid_reserved_bits(uuid_generate_v1mc()), + uuid_multicast_bit(uuid_generate_v1mc()), + uuid_local_admin_bit(uuid_generate_v1mc()); + +-- timestamp+clock sequence should be monotonic increasing in v1 +SELECT uuid_timestamp_bits(uuid_generate_v1()) < uuid_timestamp_bits(uuid_generate_v1()); +SELECT uuid_timestamp_bits(uuid_generate_v1mc()) < uuid_timestamp_bits(uuid_generate_v1mc()); + +-- Ideally, the node value is stable in V1 addresses, but OSSP UUID +-- falls back to V1MC behavior if it can't get the system MAC address. +SELECT CASE WHEN uuid_multicast_bit(uuid_generate_v1()) AND + uuid_local_admin_bit(uuid_generate_v1()) THEN + true -- punt, no test + ELSE + uuid_node(uuid_generate_v1()) = uuid_node(uuid_generate_v1()) + END; + +-- In any case, V1MC node addresses should be random. +SELECT uuid_node(uuid_generate_v1()) <> uuid_node(uuid_generate_v1mc()); +SELECT uuid_node(uuid_generate_v1mc()) <> uuid_node(uuid_generate_v1mc()); + +SELECT uuid_generate_v3(uuid_ns_dns(), 'www.widgets.com'); +SELECT uuid_generate_v5(uuid_ns_dns(), 'www.widgets.com'); + +SELECT uuid_version_bits(uuid_generate_v4()), + uuid_reserved_bits(uuid_generate_v4()); + +SELECT uuid_generate_v4() <> uuid_generate_v4(); diff --git a/contrib/uuid-ossp/uuid-ossp--1.0--1.1.sql b/contrib/uuid-ossp/uuid-ossp--1.0--1.1.sql new file mode 100644 index 0000000..d6b82e6 --- /dev/null +++ b/contrib/uuid-ossp/uuid-ossp--1.0--1.1.sql @@ -0,0 +1,15 @@ +/* contrib/uuid-ossp/uuid-ossp--1.0--1.1.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION uuid-ossp UPDATE TO '1.1'" to load this file. \quit + +ALTER FUNCTION uuid_nil() PARALLEL SAFE; +ALTER FUNCTION uuid_ns_dns() PARALLEL SAFE; +ALTER FUNCTION uuid_ns_url() PARALLEL SAFE; +ALTER FUNCTION uuid_ns_oid() PARALLEL SAFE; +ALTER FUNCTION uuid_ns_x500() PARALLEL SAFE; +ALTER FUNCTION uuid_generate_v1() PARALLEL SAFE; +ALTER FUNCTION uuid_generate_v1mc() PARALLEL SAFE; +ALTER FUNCTION uuid_generate_v3(uuid, text) PARALLEL SAFE; +ALTER FUNCTION uuid_generate_v4() PARALLEL SAFE; +ALTER FUNCTION uuid_generate_v5(uuid, text) PARALLEL SAFE; diff --git a/contrib/uuid-ossp/uuid-ossp--1.1.sql b/contrib/uuid-ossp/uuid-ossp--1.1.sql new file mode 100644 index 0000000..c9cefd7 --- /dev/null +++ b/contrib/uuid-ossp/uuid-ossp--1.1.sql @@ -0,0 +1,54 @@ +/* contrib/uuid-ossp/uuid-ossp--1.1.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use '''CREATE EXTENSION "uuid-ossp"''' to load this file. \quit + +CREATE FUNCTION uuid_nil() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_nil' +IMMUTABLE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_ns_dns() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_ns_dns' +IMMUTABLE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_ns_url() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_ns_url' +IMMUTABLE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_ns_oid() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_ns_oid' +IMMUTABLE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_ns_x500() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_ns_x500' +IMMUTABLE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_generate_v1() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_generate_v1' +VOLATILE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_generate_v1mc() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_generate_v1mc' +VOLATILE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_generate_v3(namespace uuid, name text) +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_generate_v3' +IMMUTABLE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_generate_v4() +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_generate_v4' +VOLATILE STRICT LANGUAGE C PARALLEL SAFE; + +CREATE FUNCTION uuid_generate_v5(namespace uuid, name text) +RETURNS uuid +AS 'MODULE_PATHNAME', 'uuid_generate_v5' +IMMUTABLE STRICT LANGUAGE C PARALLEL SAFE; diff --git a/contrib/uuid-ossp/uuid-ossp.c b/contrib/uuid-ossp/uuid-ossp.c new file mode 100644 index 0000000..6399baf --- /dev/null +++ b/contrib/uuid-ossp/uuid-ossp.c @@ -0,0 +1,552 @@ +/*------------------------------------------------------------------------- + * + * UUID generation functions using the BSD, E2FS or OSSP UUID library + * + * Copyright (c) 2007-2023, PostgreSQL Global Development Group + * + * Portions Copyright (c) 2009 Andrew Gierth + * + * contrib/uuid-ossp/uuid-ossp.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "common/cryptohash.h" +#include "common/sha1.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 &= 0x0FFF; \ + uu.time_hi_and_version |= (v << 12); \ + uu.clock_seq_hi_and_reserved &= 0x3F; \ + uu.clock_seq_hi_and_reserved |= 0x80; \ +} while(0) + +#endif /* !HAVE_UUID_OSSP */ + +PG_MODULE_MAGIC; + +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() & 0xffff), + (unsigned) ((arc4random() & 0xfff) | 0x4000), + (unsigned) ((arc4random() & 0x3fff) | 0x8000), + (unsigned) (arc4random() & 0xffff), + (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] |= 0x03; + + 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() & 0xffff) | 0x0300), + (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 +} diff --git a/contrib/uuid-ossp/uuid-ossp.control b/contrib/uuid-ossp/uuid-ossp.control new file mode 100644 index 0000000..142a99e --- /dev/null +++ b/contrib/uuid-ossp/uuid-ossp.control @@ -0,0 +1,6 @@ +# uuid-ossp extension +comment = 'generate universally unique identifiers (UUIDs)' +default_version = '1.1' +module_pathname = '$libdir/uuid-ossp' +relocatable = true +trusted = true |