summaryrefslogtreecommitdiffstats
path: root/contrib/uuid-ossp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/uuid-ossp/.gitignore4
-rw-r--r--contrib/uuid-ossp/Makefile25
-rw-r--r--contrib/uuid-ossp/expected/uuid_ossp.out139
-rw-r--r--contrib/uuid-ossp/sql/uuid_ossp.sql75
-rw-r--r--contrib/uuid-ossp/uuid-ossp--1.0--1.1.sql15
-rw-r--r--contrib/uuid-ossp/uuid-ossp--1.1.sql54
-rw-r--r--contrib/uuid-ossp/uuid-ossp.c553
-rw-r--r--contrib/uuid-ossp/uuid-ossp.control6
8 files changed, 871 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/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..456a438
--- /dev/null
+++ b/contrib/uuid-ossp/uuid-ossp.c
@@ -0,0 +1,553 @@
+/*-------------------------------------------------------------------------
+ *
+ * UUID generation functions using the BSD, E2FS or OSSP UUID library
+ *
+ * Copyright (c) 2007-2022, 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"
+
+/*
+ * 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);
+ }
+ if (str)
+ 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);
+
+ if (str)
+ 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