diff options
Diffstat (limited to 'contrib')
| -rw-r--r-- | contrib/Makefile | 2 | ||||
| -rw-r--r-- | contrib/uuid-ossp/.gitignore | 6 | ||||
| -rw-r--r-- | contrib/uuid-ossp/Makefile | 16 | ||||
| -rw-r--r-- | contrib/uuid-ossp/expected/uuid_ossp.out | 91 | ||||
| -rw-r--r-- | contrib/uuid-ossp/sql/uuid_ossp.sql | 22 | ||||
| -rw-r--r-- | contrib/uuid-ossp/uuid-ossp.c | 401 |
6 files changed, 474 insertions, 64 deletions
diff --git a/contrib/Makefile b/contrib/Makefile index 8dc40f7de00..b37d0dd2c31 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -64,7 +64,7 @@ else ALWAYS_SUBDIRS += sslinfo endif -ifeq ($(with_ossp_uuid),yes) +ifneq ($(with_uuid),no) SUBDIRS += uuid-ossp else ALWAYS_SUBDIRS += uuid-ossp diff --git a/contrib/uuid-ossp/.gitignore b/contrib/uuid-ossp/.gitignore new file mode 100644 index 00000000000..6c989c78729 --- /dev/null +++ b/contrib/uuid-ossp/.gitignore @@ -0,0 +1,6 @@ +/md5.c +/sha1.c +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/uuid-ossp/Makefile b/contrib/uuid-ossp/Makefile index 9b2d2e3ff93..335cc7ef50a 100644 --- a/contrib/uuid-ossp/Makefile +++ b/contrib/uuid-ossp/Makefile @@ -1,12 +1,21 @@ # contrib/uuid-ossp/Makefile MODULE_big = uuid-ossp -OBJS = uuid-ossp.o +OBJS = uuid-ossp.o $(UUID_EXTRA_OBJS) EXTENSION = uuid-ossp DATA = uuid-ossp--1.0.sql uuid-ossp--unpackaged--1.0.sql -SHLIB_LINK += $(OSSP_UUID_LIBS) +REGRESS = uuid_ossp + +SHLIB_LINK += $(UUID_LIBS) + +# We copy some needed files verbatim from pgcrypto +pgcrypto_src = $(top_srcdir)/contrib/pgcrypto + +PG_CPPFLAGS = -I$(pgcrypto_src) + +EXTRA_CLEAN = md5.c sha1.c ifdef USE_PGXS PG_CONFIG = pg_config @@ -18,3 +27,6 @@ top_builddir = ../.. include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif + +md5.c sha1.c: % : $(pgcrypto_src)/% + rm -f $@ && $(LN_S) $< . diff --git a/contrib/uuid-ossp/expected/uuid_ossp.out b/contrib/uuid-ossp/expected/uuid_ossp.out new file mode 100644 index 00000000000..986843c8976 --- /dev/null +++ b/contrib/uuid-ossp/expected/uuid_ossp.out @@ -0,0 +1,91 @@ +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) + +SELECT uuid_generate_v1() < uuid_generate_v1(); + ?column? +---------- + t +(1 row) + +SELECT uuid_generate_v1() < uuid_generate_v1mc(); + ?column? +---------- + t +(1 row) + +SELECT substr(uuid_generate_v1()::text, 25) = substr(uuid_generate_v1()::text, 25); + ?column? +---------- + t +(1 row) + +SELECT substr(uuid_generate_v1()::text, 25) <> substr(uuid_generate_v1mc()::text, 25); + ?column? +---------- + t +(1 row) + +SELECT substr(uuid_generate_v1mc()::text, 25) <> substr(uuid_generate_v1mc()::text, 25); + ?column? +---------- + t +(1 row) + +SELECT ('x' || substr(uuid_generate_v1mc()::text, 25, 2))::bit(8) & '00000011'; + ?column? +---------- + 00000011 +(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_generate_v4()::text ~ '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'; + ?column? +---------- + t +(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 00000000000..29fba21b3f7 --- /dev/null +++ b/contrib/uuid-ossp/sql/uuid_ossp.sql @@ -0,0 +1,22 @@ +CREATE EXTENSION "uuid-ossp"; + +SELECT uuid_nil(); +SELECT uuid_ns_dns(); +SELECT uuid_ns_url(); +SELECT uuid_ns_oid(); +SELECT uuid_ns_x500(); + +SELECT uuid_generate_v1() < uuid_generate_v1(); +SELECT uuid_generate_v1() < uuid_generate_v1mc(); + +SELECT substr(uuid_generate_v1()::text, 25) = substr(uuid_generate_v1()::text, 25); +SELECT substr(uuid_generate_v1()::text, 25) <> substr(uuid_generate_v1mc()::text, 25); +SELECT substr(uuid_generate_v1mc()::text, 25) <> substr(uuid_generate_v1mc()::text, 25); + +SELECT ('x' || substr(uuid_generate_v1mc()::text, 25, 2))::bit(8) & '00000011'; + +SELECT uuid_generate_v3(uuid_ns_dns(), 'www.widgets.com'); +SELECT uuid_generate_v5(uuid_ns_dns(), 'www.widgets.com'); + +SELECT uuid_generate_v4()::text ~ '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'; +SELECT uuid_generate_v4() <> uuid_generate_v4(); diff --git a/contrib/uuid-ossp/uuid-ossp.c b/contrib/uuid-ossp/uuid-ossp.c index 8f99084df34..f8c33d2b469 100644 --- a/contrib/uuid-ossp/uuid-ossp.c +++ b/contrib/uuid-ossp/uuid-ossp.c @@ -1,40 +1,113 @@ /*------------------------------------------------------------------------- * - * UUID generation functions using the OSSP UUID library + * UUID generation functions using the BSD, E2FS or OSSP UUID library * * Copyright (c) 2007-2014, PostgreSQL Global Development Group * + * Portions Copyright (c) 2009 Andrew Gierth + * * contrib/uuid-ossp/uuid-ossp.c * *------------------------------------------------------------------------- */ #include "postgres.h" + #include "fmgr.h" #include "utils/builtins.h" #include "utils/uuid.h" /* - * There's some confusion over the location of the uuid.h header file. - * On Debian, it's installed as ossp/uuid.h, while on Fedora, or if you - * install ossp-uuid from a tarball, it's installed as uuid.h. Don't know - * what other systems do. + * 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. */ -#ifdef HAVE_OSSP_UUID_H -#include <ossp/uuid.h> -#else +#define uuid_hash bsd_uuid_hash + #ifdef HAVE_UUID_H #include <uuid.h> -#else -#error OSSP uuid.h not found #endif +#ifdef HAVE_OSSP_UUID_H +#include <ossp/uuid.h> #endif +#ifdef HAVE_UUID_UUID_H +#include <uuid/uuid.h> +#endif + +#undef uuid_hash -/* better both be 16 */ -#if (UUID_LEN != UUID_LEN_BIN) +/* + * Some BSD variants offer md5 and sha1 implementations but Linux does not, + * so we use a copy of the ones from pgcrypto. Not needed with OSSP, though. + */ +#ifndef HAVE_UUID_OSSP +#include "md5.h" +#include "sha1.h" +#endif + + +/* 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 = htonl(uu.time_low); \ + uu.time_mid = htons(uu.time_mid); \ + uu.time_hi_and_version = htons(uu.time_hi_and_version); \ +} while (0) + +#define UUID_TO_LOCAL(uu) \ +do { \ + uu.time_low = ntohl(uu.time_low); \ + uu.time_mid = ntohs(uu.time_mid); \ + uu.time_hi_and_version = ntohs(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; @@ -51,6 +124,8 @@ 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) { @@ -114,100 +189,294 @@ special_uuid_value(const char *name) 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; + char *str; + uuid_rc_t rc; + + rc = uuid_create(&uuid); + if (rc != UUID_RC_OK) + pguuid_complain(rc); + rc = uuid_make(uuid, mode, ns, name); + if (rc != UUID_RC_OK) + pguuid_complain(rc); + str = uuid_to_string(uuid); + rc = uuid_destroy(uuid); + if (rc != UUID_RC_OK) + pguuid_complain(rc); + + return DirectFunctionCall1(uuid_in, CStringGetDatum(str)); +} + + +static Datum +uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name) +{ + uuid_t *ns_uuid; + Datum result; + uuid_rc_t rc; + + rc = uuid_create(&ns_uuid); + if (rc != UUID_RC_OK) + pguuid_complain(rc); + string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))), + ns_uuid); + + result = uuid_generate_internal(mode, + ns_uuid, + text_to_cstring(name), + 0); + + rc = uuid_destroy(ns_uuid); + if (rc != UUID_RC_OK) + pguuid_complain(rc); + + return result; +} + +#else /* !HAVE_UUID_OSSP */ + +static Datum +uuid_generate_internal(int v, unsigned char *ns, 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); + + /* + * 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) + { + MD5_CTX ctx; + + MD5Init(&ctx); + MD5Update(&ctx, ns, sizeof(uu)); + MD5Update(&ctx, (unsigned char *) ptr, len); + MD5Final((unsigned char *) &uu, &ctx); + } + else + { + SHA1_CTX ctx; + + SHA1Init(&ctx); + SHA1Update(&ctx, ns, sizeof(uu)); + SHA1Update(&ctx, (unsigned char *) ptr, len); + SHA1Final((unsigned char *) &uu, &ctx); + } + + /* 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"); -} - - -static Datum -uuid_generate_internal(int mode, const uuid_t *ns, const char *name) -{ - uuid_t *uuid; - char *str; - uuid_rc_t rc; - - rc = uuid_create(&uuid); - if (rc != UUID_RC_OK) - pguuid_complain(rc); - rc = uuid_make(uuid, mode, ns, name); - if (rc != UUID_RC_OK) - pguuid_complain(rc); - str = uuid_to_string(uuid); - rc = uuid_destroy(uuid); - if (rc != UUID_RC_OK) - pguuid_complain(rc); - - return DirectFunctionCall1(uuid_in, CStringGetDatum(str)); +#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); + return uuid_generate_internal(UUID_MAKE_V1, NULL, NULL, 0); } Datum uuid_generate_v1mc(PG_FUNCTION_ARGS) { - return uuid_generate_internal(UUID_MAKE_V1 | UUID_MAKE_MC, NULL, NULL); -} - - -static Datum -uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name) -{ - uuid_t *ns_uuid; - Datum result; - uuid_rc_t rc; - - rc = uuid_create(&ns_uuid); - if (rc != UUID_RC_OK) - pguuid_complain(rc); - string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))), - ns_uuid); - - result = uuid_generate_internal(mode, - ns_uuid, - text_to_cstring(name)); - - rc = uuid_destroy(ns_uuid); - if (rc != UUID_RC_OK) - pguuid_complain(rc); +#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 result; + return uuid_generate_internal(UUID_MAKE_V1 | UUID_MAKE_MC, NULL, + buf, 13); } @@ -217,14 +486,19 @@ uuid_generate_v3(PG_FUNCTION_ARGS) pg_uuid_t *ns = PG_GETARG_UUID_P(0); text *name = PG_GETARG_TEXT_P(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(name), VARSIZE(name) - VARHDRSZ); +#endif } Datum uuid_generate_v4(PG_FUNCTION_ARGS) { - return uuid_generate_internal(UUID_MAKE_V4, NULL, NULL); + return uuid_generate_internal(UUID_MAKE_V4, NULL, NULL, 0); } @@ -234,5 +508,10 @@ uuid_generate_v5(PG_FUNCTION_ARGS) pg_uuid_t *ns = PG_GETARG_UUID_P(0); text *name = PG_GETARG_TEXT_P(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(name), VARSIZE(name) - VARHDRSZ); +#endif } |
