Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions  Download package

uuid.c

/*-------------------------------------------------------------------------
 *
 * uuid.c
 *      Functions for the built-in type "uuid".
 *
 * Copyright (c) 2007-2009, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *      $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.11 2009/06/11 14:49:04 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/hash.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/uuid.h"

/* uuid size in bytes */
#define UUID_LEN 16

/* pg_uuid_t is declared to be struct pg_uuid_t in uuid.h */
struct pg_uuid_t
{
      unsigned char data[UUID_LEN];
};

static void string_to_uuid(const char *source, pg_uuid_t *uuid);
static int  uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2);

Datum
uuid_in(PG_FUNCTION_ARGS)
{
      char     *uuid_str = PG_GETARG_CSTRING(0);
      pg_uuid_t  *uuid;

      uuid = (pg_uuid_t *) palloc(sizeof(*uuid));
      string_to_uuid(uuid_str, uuid);
      PG_RETURN_UUID_P(uuid);
}

Datum
uuid_out(PG_FUNCTION_ARGS)
{
      pg_uuid_t  *uuid = PG_GETARG_UUID_P(0);
      static const char hex_chars[] = "0123456789abcdef";
      StringInfoData buf;
      int               i;

      initStringInfo(&buf);
      for (i = 0; i < UUID_LEN; i++)
      {
            int               hi;
            int               lo;

            /*
             * We print uuid values as a string of 8, 4, 4, 4, and then 12
             * hexadecimal characters, with each group is separated by a hyphen
             * ("-"). Therefore, add the hyphens at the appropriate places here.
             */
            if (i == 4 || i == 6 || i == 8 || i == 10)
                  appendStringInfoChar(&buf, '-');

            hi = uuid->data[i] >> 4;
            lo = uuid->data[i] & 0x0F;

            appendStringInfoChar(&buf, hex_chars[hi]);
            appendStringInfoChar(&buf, hex_chars[lo]);
      }

      PG_RETURN_CSTRING(buf.data);
}

/*
 * We allow UUIDs as a series of 32 hexadecimal digits with an optional dash
 * after each group of 4 hexadecimal digits, and optionally surrounded by {}.
 * (The canonical format 8x-4x-4x-4x-12x, where "nx" means n hexadecimal
 * digits, is the only one used for output.)
 */
static void
string_to_uuid(const char *source, pg_uuid_t *uuid)
{
      const char *src = source;
      bool        braces = false;
      int               i;

      if (src[0] == '{')
      {
            src++;
            braces = true;
      }

      for (i = 0; i < UUID_LEN; i++)
      {
            char        str_buf[3];

            if (src[0] == '\0' || src[1] == '\0')
                  goto syntax_error;
            memcpy(str_buf, src, 2);
            if (!isxdigit((unsigned char) str_buf[0]) ||
                  !isxdigit((unsigned char) str_buf[1]))
                  goto syntax_error;

            str_buf[2] = '\0';
            uuid->data[i] = (unsigned char) strtoul(str_buf, NULL, 16);
            src += 2;
            if (src[0] == '-' && (i % 2) == 1 && i < UUID_LEN - 1)
                  src++;
      }

      if (braces)
      {
            if (*src != '}')
                  goto syntax_error;
            src++;
      }

      if (*src != '\0')
            goto syntax_error;

      return;

syntax_error:
      ereport(ERROR,
                  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                   errmsg("invalid input syntax for uuid: \"%s\"",
                              source)));
}

Datum
uuid_recv(PG_FUNCTION_ARGS)
{
      StringInfo  buffer = (StringInfo) PG_GETARG_POINTER(0);
      pg_uuid_t  *uuid;

      uuid = (pg_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)
{
      pg_uuid_t  *uuid = PG_GETARG_UUID_P(0);
      StringInfoData buffer;

      pq_begintypsend(&buffer);
      pq_sendbytes(&buffer, (char *) uuid->data, UUID_LEN);
      PG_RETURN_BYTEA_P(pq_endtypsend(&buffer));
}

/* internal uuid compare function */
static int
uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
{
      return memcmp(arg1->data, arg2->data, UUID_LEN);
}

Datum
uuid_lt(PG_FUNCTION_ARGS)
{
      pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
      pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);

      PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) < 0);
}

Datum
uuid_le(PG_FUNCTION_ARGS)
{
      pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
      pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);

      PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) <= 0);
}

Datum
uuid_eq(PG_FUNCTION_ARGS)
{
      pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
      pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);

      PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) == 0);
}

Datum
uuid_ge(PG_FUNCTION_ARGS)
{
      pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
      pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);

      PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) >= 0);
}

Datum
uuid_gt(PG_FUNCTION_ARGS)
{
      pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
      pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);

      PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) > 0);
}

Datum
uuid_ne(PG_FUNCTION_ARGS)
{
      pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
      pg_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)
{
      pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
      pg_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)
{
      pg_uuid_t  *key = PG_GETARG_UUID_P(0);

      return hash_any(key->data, UUID_LEN);
}

Generated by  Doxygen 1.6.0   Back to index