postgresql/contrib/uuid-ossp/uuid-ossp.c
Tom Lane 220db7ccd8 Simplify and standardize conversions between TEXT datums and ordinary C
strings.  This patch introduces four support functions cstring_to_text,
cstring_to_text_with_len, text_to_cstring, and text_to_cstring_buffer, and
two macros CStringGetTextDatum and TextDatumGetCString.  A number of
existing macros that provided variants on these themes were removed.

Most of the places that need to make such conversions now require just one
function or macro call, in place of the multiple notational layers that used
to be needed.  There are no longer any direct calls of textout or textin,
and we got most of the places that were using handmade conversions via
memcpy (there may be a few still lurking, though).

This commit doesn't make any serious effort to eliminate transient memory
leaks caused by detoasting toasted text objects before they reach
text_to_cstring.  We changed PG_GETARG_TEXT_P to PG_GETARG_TEXT_PP in a few
places where it was easy, but much more could be done.

Brendan Jurd and Tom Lane
2008-03-25 22:42:46 +00:00

252 lines
4.9 KiB
C

/*-------------------------------------------------------------------------
*
* UUID generation functions using the OSSP UUID library
*
* Copyright (c) 2007-2008 PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/contrib/uuid-ossp/uuid-ossp.c,v 1.8 2008/03/25 22:42:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#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.
*/
#ifdef HAVE_OSSP_UUID_H
#include <ossp/uuid.h>
#else
#ifdef HAVE_UUID_H
#include <uuid.h>
#else
#error OSSP uuid.h not found
#endif
#endif
/* better both be 16 */
#if (UUID_LEN != UUID_LEN_BIN)
#error UUID length mismatch
#endif
PG_MODULE_MAGIC;
Datum uuid_nil(PG_FUNCTION_ARGS);
Datum uuid_ns_dns(PG_FUNCTION_ARGS);
Datum uuid_ns_url(PG_FUNCTION_ARGS);
Datum uuid_ns_oid(PG_FUNCTION_ARGS);
Datum uuid_ns_x500(PG_FUNCTION_ARGS);
Datum uuid_generate_v1(PG_FUNCTION_ARGS);
Datum uuid_generate_v1mc(PG_FUNCTION_ARGS);
Datum uuid_generate_v3(PG_FUNCTION_ARGS);
Datum uuid_generate_v4(PG_FUNCTION_ARGS);
Datum uuid_generate_v5(PG_FUNCTION_ARGS);
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);
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)));
}
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;
char *str;
uuid_rc_t rc;
rc = uuid_create(&uuid);
if (rc != UUID_RC_OK)
pguuid_complain(rc);
rc = uuid_load(uuid, 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));
}
Datum
uuid_nil(PG_FUNCTION_ARGS)
{
return special_uuid_value("nil");
}
Datum
uuid_ns_dns(PG_FUNCTION_ARGS)
{
return special_uuid_value("ns:DNS");
}
Datum
uuid_ns_url(PG_FUNCTION_ARGS)
{
return special_uuid_value("ns:URL");
}
Datum
uuid_ns_oid(PG_FUNCTION_ARGS)
{
return special_uuid_value("ns:OID");
}
Datum
uuid_ns_x500(PG_FUNCTION_ARGS)
{
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));
}
Datum
uuid_generate_v1(PG_FUNCTION_ARGS)
{
return uuid_generate_internal(UUID_MAKE_V1, NULL, NULL);
}
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);
return result;
}
Datum
uuid_generate_v3(PG_FUNCTION_ARGS)
{
pg_uuid_t *ns = PG_GETARG_UUID_P(0);
text *name = PG_GETARG_TEXT_P(1);
return uuid_generate_v35_internal(UUID_MAKE_V3, ns, name);
}
Datum
uuid_generate_v4(PG_FUNCTION_ARGS)
{
return uuid_generate_internal(UUID_MAKE_V4, NULL, NULL);
}
Datum
uuid_generate_v5(PG_FUNCTION_ARGS)
{
pg_uuid_t *ns = PG_GETARG_UUID_P(0);
text *name = PG_GETARG_TEXT_P(1);
return uuid_generate_v35_internal(UUID_MAKE_V5, ns, name);
}