Header And Logo

PostgreSQL
| The world's most advanced open source database.

uuid.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * uuid.c
00004  *    Functions for the built-in type "uuid".
00005  *
00006  * Copyright (c) 2007-2013, PostgreSQL Global Development Group
00007  *
00008  * IDENTIFICATION
00009  *    src/backend/utils/adt/uuid.c
00010  *
00011  *-------------------------------------------------------------------------
00012  */
00013 
00014 #include "postgres.h"
00015 
00016 #include "access/hash.h"
00017 #include "libpq/pqformat.h"
00018 #include "utils/builtins.h"
00019 #include "utils/uuid.h"
00020 
00021 /* uuid size in bytes */
00022 #define UUID_LEN 16
00023 
00024 /* pg_uuid_t is declared to be struct pg_uuid_t in uuid.h */
00025 struct pg_uuid_t
00026 {
00027     unsigned char data[UUID_LEN];
00028 };
00029 
00030 static void string_to_uuid(const char *source, pg_uuid_t *uuid);
00031 static int  uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2);
00032 
00033 Datum
00034 uuid_in(PG_FUNCTION_ARGS)
00035 {
00036     char       *uuid_str = PG_GETARG_CSTRING(0);
00037     pg_uuid_t  *uuid;
00038 
00039     uuid = (pg_uuid_t *) palloc(sizeof(*uuid));
00040     string_to_uuid(uuid_str, uuid);
00041     PG_RETURN_UUID_P(uuid);
00042 }
00043 
00044 Datum
00045 uuid_out(PG_FUNCTION_ARGS)
00046 {
00047     pg_uuid_t  *uuid = PG_GETARG_UUID_P(0);
00048     static const char hex_chars[] = "0123456789abcdef";
00049     StringInfoData buf;
00050     int         i;
00051 
00052     initStringInfo(&buf);
00053     for (i = 0; i < UUID_LEN; i++)
00054     {
00055         int         hi;
00056         int         lo;
00057 
00058         /*
00059          * We print uuid values as a string of 8, 4, 4, 4, and then 12
00060          * hexadecimal characters, with each group is separated by a hyphen
00061          * ("-"). Therefore, add the hyphens at the appropriate places here.
00062          */
00063         if (i == 4 || i == 6 || i == 8 || i == 10)
00064             appendStringInfoChar(&buf, '-');
00065 
00066         hi = uuid->data[i] >> 4;
00067         lo = uuid->data[i] & 0x0F;
00068 
00069         appendStringInfoChar(&buf, hex_chars[hi]);
00070         appendStringInfoChar(&buf, hex_chars[lo]);
00071     }
00072 
00073     PG_RETURN_CSTRING(buf.data);
00074 }
00075 
00076 /*
00077  * We allow UUIDs as a series of 32 hexadecimal digits with an optional dash
00078  * after each group of 4 hexadecimal digits, and optionally surrounded by {}.
00079  * (The canonical format 8x-4x-4x-4x-12x, where "nx" means n hexadecimal
00080  * digits, is the only one used for output.)
00081  */
00082 static void
00083 string_to_uuid(const char *source, pg_uuid_t *uuid)
00084 {
00085     const char *src = source;
00086     bool        braces = false;
00087     int         i;
00088 
00089     if (src[0] == '{')
00090     {
00091         src++;
00092         braces = true;
00093     }
00094 
00095     for (i = 0; i < UUID_LEN; i++)
00096     {
00097         char        str_buf[3];
00098 
00099         if (src[0] == '\0' || src[1] == '\0')
00100             goto syntax_error;
00101         memcpy(str_buf, src, 2);
00102         if (!isxdigit((unsigned char) str_buf[0]) ||
00103             !isxdigit((unsigned char) str_buf[1]))
00104             goto syntax_error;
00105 
00106         str_buf[2] = '\0';
00107         uuid->data[i] = (unsigned char) strtoul(str_buf, NULL, 16);
00108         src += 2;
00109         if (src[0] == '-' && (i % 2) == 1 && i < UUID_LEN - 1)
00110             src++;
00111     }
00112 
00113     if (braces)
00114     {
00115         if (*src != '}')
00116             goto syntax_error;
00117         src++;
00118     }
00119 
00120     if (*src != '\0')
00121         goto syntax_error;
00122 
00123     return;
00124 
00125 syntax_error:
00126     ereport(ERROR,
00127             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00128              errmsg("invalid input syntax for uuid: \"%s\"",
00129                     source)));
00130 }
00131 
00132 Datum
00133 uuid_recv(PG_FUNCTION_ARGS)
00134 {
00135     StringInfo  buffer = (StringInfo) PG_GETARG_POINTER(0);
00136     pg_uuid_t  *uuid;
00137 
00138     uuid = (pg_uuid_t *) palloc(UUID_LEN);
00139     memcpy(uuid->data, pq_getmsgbytes(buffer, UUID_LEN), UUID_LEN);
00140     PG_RETURN_POINTER(uuid);
00141 }
00142 
00143 Datum
00144 uuid_send(PG_FUNCTION_ARGS)
00145 {
00146     pg_uuid_t  *uuid = PG_GETARG_UUID_P(0);
00147     StringInfoData buffer;
00148 
00149     pq_begintypsend(&buffer);
00150     pq_sendbytes(&buffer, (char *) uuid->data, UUID_LEN);
00151     PG_RETURN_BYTEA_P(pq_endtypsend(&buffer));
00152 }
00153 
00154 /* internal uuid compare function */
00155 static int
00156 uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
00157 {
00158     return memcmp(arg1->data, arg2->data, UUID_LEN);
00159 }
00160 
00161 Datum
00162 uuid_lt(PG_FUNCTION_ARGS)
00163 {
00164     pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
00165     pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);
00166 
00167     PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) < 0);
00168 }
00169 
00170 Datum
00171 uuid_le(PG_FUNCTION_ARGS)
00172 {
00173     pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
00174     pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);
00175 
00176     PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) <= 0);
00177 }
00178 
00179 Datum
00180 uuid_eq(PG_FUNCTION_ARGS)
00181 {
00182     pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
00183     pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);
00184 
00185     PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) == 0);
00186 }
00187 
00188 Datum
00189 uuid_ge(PG_FUNCTION_ARGS)
00190 {
00191     pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
00192     pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);
00193 
00194     PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) >= 0);
00195 }
00196 
00197 Datum
00198 uuid_gt(PG_FUNCTION_ARGS)
00199 {
00200     pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
00201     pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);
00202 
00203     PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) > 0);
00204 }
00205 
00206 Datum
00207 uuid_ne(PG_FUNCTION_ARGS)
00208 {
00209     pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
00210     pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);
00211 
00212     PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) != 0);
00213 }
00214 
00215 /* handler for btree index operator */
00216 Datum
00217 uuid_cmp(PG_FUNCTION_ARGS)
00218 {
00219     pg_uuid_t  *arg1 = PG_GETARG_UUID_P(0);
00220     pg_uuid_t  *arg2 = PG_GETARG_UUID_P(1);
00221 
00222     PG_RETURN_INT32(uuid_internal_cmp(arg1, arg2));
00223 }
00224 
00225 /* hash index support */
00226 Datum
00227 uuid_hash(PG_FUNCTION_ARGS)
00228 {
00229     pg_uuid_t  *key = PG_GETARG_UUID_P(0);
00230 
00231     return hash_any(key->data, UUID_LEN);
00232 }