]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/uuid.c
24b05f34266fa01e78cf7454eff0122df50694f0
[postgresql] / src / backend / utils / adt / uuid.c
1 /*-------------------------------------------------------------------------
2  *
3  * uuid.c
4  *        Functions for the built-in type "uuid".
5  *
6  * Copyright (c) 2007, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *        $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.4 2007/06/05 21:31:06 tgl Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13
14 #include "postgres.h"
15
16 #include "access/hash.h"
17 #include "libpq/pqformat.h"
18 #include "utils/builtins.h"
19 #include "utils/uuid.h"
20
21 /* uuid size in bytes */
22 #define UUID_LEN 16
23
24 /* pg_uuid_t is declared to be struct pg_uuid_t in uuid.h */
25 struct pg_uuid_t
26 {
27     unsigned char  data[UUID_LEN];
28 };
29
30 static void string_to_uuid(const char *source, pg_uuid_t *uuid);
31 static int uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2);
32
33 Datum
34 uuid_in(PG_FUNCTION_ARGS)
35 {
36         char            *uuid_str = PG_GETARG_CSTRING(0);
37         pg_uuid_t       *uuid;
38
39         uuid = (pg_uuid_t *) palloc(sizeof(*uuid));
40         string_to_uuid(uuid_str, uuid);
41         PG_RETURN_UUID_P(uuid);
42 }
43
44 Datum
45 uuid_out(PG_FUNCTION_ARGS)
46 {
47         pg_uuid_t                       *uuid = PG_GETARG_UUID_P(0);
48         static const char hex_chars[] = "0123456789abcdef";
49         StringInfoData           buf;
50         int                              i;
51
52         initStringInfo(&buf);
53         for (i = 0; i < UUID_LEN; i++)
54         {
55                 int hi;
56                 int lo;
57
58                 /*
59                  * We print uuid values as a string of 8, 4, 4, 4, and then 12
60                  * hexadecimal characters, with each group is separated by a
61                  * hyphen ("-"). Therefore, add the hyphens at the appropriate
62                  * places here.
63                  */
64                 if (i == 4 || i == 6 || i == 8 || i == 10)
65                         appendStringInfoChar(&buf, '-');
66
67                 hi = uuid->data[i] >> 4;
68                 lo = uuid->data[i] & 0x0F;
69
70                 appendStringInfoChar(&buf, hex_chars[hi]);
71                 appendStringInfoChar(&buf, hex_chars[lo]);
72         }
73
74         PG_RETURN_CSTRING(buf.data);
75 }
76
77 /*
78  * We allow UUIDs in three input formats: 8x-4x-4x-4x-12x,
79  * {8x-4x-4x-4x-12x}, and 32x, where "nx" means n hexadecimal digits
80  * (only the first format is used for output). We convert the first
81  * two formats into the latter format before further processing.
82  */
83 static void
84 string_to_uuid(const char *source, pg_uuid_t *uuid)
85 {
86         char            hex_buf[32];    /* not NUL terminated */
87         int             i;
88         int             src_len;
89
90         src_len = strlen(source);
91         if (src_len != 32 && src_len != 36 && src_len != 38)
92                 goto syntax_error;
93
94         if (src_len == 32)
95                 memcpy(hex_buf, source, src_len);
96         else
97         {
98                 const char *str = source;
99
100                 if (src_len == 38)
101                 {
102                         if (str[0] != '{' || str[37] != '}')
103                                 goto syntax_error;
104
105                         str++;  /* skip the first character */
106                 }
107
108                 if (str[8] != '-' || str[13] != '-' ||
109                         str[18] != '-' || str[23] != '-')
110                         goto syntax_error;
111
112                 memcpy(hex_buf, str, 8);
113                 memcpy(hex_buf + 8, str + 9, 4);
114                 memcpy(hex_buf + 12, str + 14, 4);
115                 memcpy(hex_buf + 16, str + 19, 4);
116                 memcpy(hex_buf + 20, str + 24, 12);
117         }
118
119         for (i = 0; i < UUID_LEN; i++)
120         {
121                 char str_buf[3];
122
123                 memcpy(str_buf, &hex_buf[i * 2], 2);
124                 if (!isxdigit((unsigned char) str_buf[0]) ||
125                         !isxdigit((unsigned char) str_buf[1]))
126                         goto syntax_error;
127
128                 str_buf[2] = '\0';
129                 uuid->data[i] = (unsigned char) strtoul(str_buf, NULL, 16);
130         }
131
132         return;
133
134 syntax_error:
135                 ereport(ERROR,
136                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
137                                  errmsg("invalid input syntax for uuid: \"%s\"",
138                                                 source)));
139 }
140
141 Datum
142 uuid_recv(PG_FUNCTION_ARGS)
143 {
144         StringInfo       buffer = (StringInfo) PG_GETARG_POINTER(0);
145         pg_uuid_t       *uuid;
146
147         uuid = (pg_uuid_t *) palloc(UUID_LEN);
148         memcpy(uuid->data, pq_getmsgbytes(buffer, UUID_LEN), UUID_LEN);
149         PG_RETURN_POINTER(uuid);
150 }
151
152 Datum
153 uuid_send(PG_FUNCTION_ARGS)
154 {
155         pg_uuid_t                               *uuid = PG_GETARG_UUID_P(0);
156         StringInfoData           buffer;
157
158         pq_begintypsend(&buffer);
159         pq_sendbytes(&buffer, (char *) uuid->data, UUID_LEN);
160         PG_RETURN_BYTEA_P(pq_endtypsend(&buffer));
161 }
162
163 /* internal uuid compare function */
164 static int
165 uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
166 {
167         return memcmp(arg1->data, arg2->data, UUID_LEN);
168 }
169
170 Datum
171 uuid_lt(PG_FUNCTION_ARGS)
172 {
173         pg_uuid_t       *arg1 = PG_GETARG_UUID_P(0);
174         pg_uuid_t       *arg2 = PG_GETARG_UUID_P(1);
175
176         PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) < 0);
177 }
178
179 Datum
180 uuid_le(PG_FUNCTION_ARGS)
181 {
182         pg_uuid_t       *arg1 = PG_GETARG_UUID_P(0);
183         pg_uuid_t       *arg2 = PG_GETARG_UUID_P(1);
184
185         PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) <= 0);
186 }
187
188 Datum
189 uuid_eq(PG_FUNCTION_ARGS)
190 {
191         pg_uuid_t       *arg1 = PG_GETARG_UUID_P(0);
192         pg_uuid_t       *arg2 = PG_GETARG_UUID_P(1);
193
194         PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) == 0);
195 }
196
197 Datum
198 uuid_ge(PG_FUNCTION_ARGS)
199 {
200         pg_uuid_t       *arg1 = PG_GETARG_UUID_P(0);
201         pg_uuid_t       *arg2 = PG_GETARG_UUID_P(1);
202
203         PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) >= 0);
204 }
205
206 Datum
207 uuid_gt(PG_FUNCTION_ARGS)
208 {
209         pg_uuid_t       *arg1 = PG_GETARG_UUID_P(0);
210         pg_uuid_t       *arg2 = PG_GETARG_UUID_P(1);
211
212         PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) > 0);
213 }
214
215 Datum
216 uuid_ne(PG_FUNCTION_ARGS)
217 {
218         pg_uuid_t       *arg1 = PG_GETARG_UUID_P(0);
219         pg_uuid_t       *arg2 = PG_GETARG_UUID_P(1);
220
221         PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) != 0);
222 }
223
224 /* handler for btree index operator */
225 Datum
226 uuid_cmp(PG_FUNCTION_ARGS)
227 {
228         pg_uuid_t       *arg1 = PG_GETARG_UUID_P(0);
229         pg_uuid_t       *arg2 = PG_GETARG_UUID_P(1);
230
231         PG_RETURN_INT32(uuid_internal_cmp(arg1, arg2));
232 }
233
234 /* hash index support */
235 Datum
236 uuid_hash(PG_FUNCTION_ARGS)
237 {
238         pg_uuid_t       *key = PG_GETARG_UUID_P(0);
239         return hash_any(key->data, UUID_LEN);
240 }