diff options
Diffstat (limited to 'src/backend/utils/adt/uuid.c')
-rw-r--r-- | src/backend/utils/adt/uuid.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c new file mode 100644 index 00000000000..124d430dbfa --- /dev/null +++ b/src/backend/utils/adt/uuid.c @@ -0,0 +1,279 @@ +/*------------------------------------------------------------------------- + * + * uuid.c + * Functions for the built-in type "uuid". + * + * Copyright (c) 2007, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.1 2007/01/28 16:16:52 neilc Exp $ + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/hash.h" +#include "libpq/pqformat.h" +#include "utils/builtins.h" +#include "utils/uuid.h" + +/* Accepted GUID formats */ + +/* UUID_FMT1 is the default output format */ +#define UUID_FMT1 "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" +#define UUID_FMT2 "{%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}" +#define UUID_FMT3 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +/* UUIDs are accepted in any of the following textual input formats. */ +#define UUID_CHK_FMT1 "00000000-0000-0000-0000-000000000000" +#define UUID_CHK_FMT2 "{00000000-0000-0000-0000-000000000000}" +#define UUID_CHK_FMT3 "00000000000000000000000000000000" + +#define PRINT_SIZE 40 + +/* uuid size in bytes */ +#define UUID_LEN 16 + +/* The uuid_t type is declared as struct uuid_t in uuid.h */ +struct uuid_t +{ + char data[UUID_LEN]; +}; + +static void uuid_data_from_string(const char *source, unsigned char *data); +static void string_from_uuid_data(const char *fmt, const char *data, char *uuid_str); +static bool parse_uuid_string(const char *fmt, const char *chk_fmt, + const char *source, unsigned char *data); +static bool is_valid_format(const char *source, const char *fmt); +static int32 uuid_internal_cmp(uuid_t *arg1, uuid_t *arg2); + +Datum +uuid_in(PG_FUNCTION_ARGS) +{ + char *uuid_str = PG_GETARG_CSTRING(0); + uuid_t *uuid; + uint8 data[UUID_LEN]; + + uuid_data_from_string(uuid_str, data); + uuid = (uuid_t *) palloc(sizeof(uuid_t)); + memcpy(uuid->data, data, UUID_LEN); + PG_RETURN_UUID_P(uuid); +} + +Datum +uuid_out(PG_FUNCTION_ARGS) +{ + uuid_t *uuid = (uuid_t *) PG_GETARG_POINTER(0); + char *uuid_str; + + uuid_str = (char *) palloc(PRINT_SIZE); + string_from_uuid_data(UUID_FMT1, uuid->data, uuid_str); + PG_RETURN_CSTRING(uuid_str); +} + +/* string to uuid convertor by various format types */ +static void +uuid_data_from_string(const char *source, unsigned char *data) +{ + if (!parse_uuid_string(UUID_FMT1, UUID_CHK_FMT1, source, data) && + !parse_uuid_string(UUID_FMT2, UUID_CHK_FMT2, source, data) && + !parse_uuid_string(UUID_FMT3, UUID_CHK_FMT3, source, data)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for uuid: \"%s\"", + source))); + } +} + +/* check the validity of a uuid string by a given format */ +static bool +is_valid_format(const char *source, const char *fmt) +{ + int i; + int fmtlen = strlen(fmt); + + /* check length first */ + if (fmtlen != strlen(source)) + return false; + + for (i = 0; i < fmtlen; i++) + { + int fc; + int sc; + bool valid_chr; + + fc = fmt[i]; + sc = source[i]; + + /* false if format chr is { or - and source is not */ + if (fc != '0' && fc != sc) + return false; + + /* check for valid char in source */ + valid_chr = (sc >= '0' && sc <= '9') || + (sc >= 'a' && sc <= 'f' ) || + (sc >= 'A' && sc <= 'F' ); + + if (fc == '0' && !valid_chr) + return false; + } + + return true; +} + +/* parse the uuid string to a format and return true if okay */ +static bool +parse_uuid_string(const char *fmt, const char *chk_fmt, + const char *source, unsigned char *data) +{ + int result = sscanf(source, fmt, + &data[0], &data[1], &data[2], &data[3], &data[4], + &data[5], &data[6], &data[7], &data[8], &data[9], + &data[10], &data[11], &data[12], &data[13], + &data[14], &data[15]); + + return (result == 16) && is_valid_format(source, chk_fmt); +} + +/* create a string representation of the uuid */ +static void +string_from_uuid_data(const char *fmt, const char *data, char *uuid_str) +{ + snprintf(uuid_str, PRINT_SIZE, fmt, + data[0], data[1], data[2], data[3], data[4], + data[5], data[6], data[7], data[8], data[9], + data[10], data[11], data[12], data[13], + data[14], data[15]); +} + +Datum +uuid_recv(PG_FUNCTION_ARGS) +{ + StringInfo buffer = (StringInfo) PG_GETARG_POINTER(0); + uuid_t *uuid; + + uuid = (uuid_t *) palloc(UUID_LEN); + memcpy(uuid->data, pq_getmsgbytes(buffer, UUID_LEN), UUID_LEN); + PG_RETURN_POINTER(uuid); +} + +Datum +uuid_send(PG_FUNCTION_ARGS) +{ + uuid_t *uuid = PG_GETARG_UUID_P(0); + StringInfoData buffer; + + pq_begintypsend(&buffer); + pq_sendbytes(&buffer, uuid->data, UUID_LEN); + PG_RETURN_BYTEA_P(pq_endtypsend(&buffer)); +} + +/* internal uuid compare function */ +static int32 +uuid_internal_cmp(uuid_t *arg1, uuid_t *arg2) +{ + return memcmp(arg1->data, arg2->data, UUID_LEN); +} + +Datum +uuid_lt(PG_FUNCTION_ARGS) +{ + uuid_t *arg1 = PG_GETARG_UUID_P(0); + uuid_t *arg2 = PG_GETARG_UUID_P(1); + + PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) < 0); +} + +Datum +uuid_le(PG_FUNCTION_ARGS) +{ + uuid_t *arg1 = PG_GETARG_UUID_P(0); + uuid_t *arg2 = PG_GETARG_UUID_P(1); + + PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) <= 0); +} + +Datum +uuid_eq(PG_FUNCTION_ARGS) +{ + uuid_t *arg1 = PG_GETARG_UUID_P(0); + uuid_t *arg2 = PG_GETARG_UUID_P(1); + + PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) == 0); +} + +Datum +uuid_ge(PG_FUNCTION_ARGS) +{ + uuid_t *arg1 = PG_GETARG_UUID_P(0); + uuid_t *arg2 = PG_GETARG_UUID_P(1); + + PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) >= 0); +} + +Datum +uuid_gt(PG_FUNCTION_ARGS) +{ + uuid_t *arg1 = PG_GETARG_UUID_P(0); + uuid_t *arg2 = PG_GETARG_UUID_P(1); + + PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) > 0); +} + +Datum +uuid_ne(PG_FUNCTION_ARGS) +{ + uuid_t *arg1 = PG_GETARG_UUID_P(0); + uuid_t *arg2 = PG_GETARG_UUID_P(1); + + PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) != 0); +} + +/* handler for btree index operator */ +Datum +uuid_cmp(PG_FUNCTION_ARGS) +{ + uuid_t *arg1 = PG_GETARG_UUID_P(0); + uuid_t *arg2 = PG_GETARG_UUID_P(1); + + PG_RETURN_INT32(uuid_internal_cmp(arg1, arg2)); +} + +/* hash index support */ +Datum +uuid_hash(PG_FUNCTION_ARGS) +{ + uuid_t *key = PG_GETARG_UUID_P(0); + return hash_any((unsigned char *) key, sizeof(uuid_t)); +} + +/* cast text to uuid */ +Datum +text_uuid(PG_FUNCTION_ARGS) +{ + text *input = PG_GETARG_TEXT_P(0); + int length; + char *str; + Datum result; + + length = VARSIZE(input) - VARHDRSZ; + str = palloc(length + 1); + memcpy(str, VARDATA(input), length); + *(str + length) = '\0'; + + result = DirectFunctionCall1(uuid_in, CStringGetDatum(str)); + pfree(str); + PG_RETURN_DATUM(result); +} + +/* cast uuid to text */ +Datum +uuid_text(PG_FUNCTION_ARGS) +{ + uuid_t *uuid = PG_GETARG_UUID_P(0); + Datum uuid_str = DirectFunctionCall1(uuid_out, UUIDPGetDatum(uuid)); + + PG_RETURN_DATUM(DirectFunctionCall1(textin, uuid_str)); +} |