6
6
* Copyright (c) 2007, PostgreSQL Global Development Group
7
7
*
8
8
* IDENTIFICATION
9
- * $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.2 2007/01/28 20:25:38 neilc Exp $
9
+ * $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.3 2007/01/31 19:33:54 neilc Exp $
10
10
*
11
11
*-------------------------------------------------------------------------
12
12
*/
18
18
#include "utils/builtins.h"
19
19
#include "utils/uuid.h"
20
20
21
- /* Accepted GUID formats */
22
-
23
- /* UUID_FMT1 is the default output format */
24
- #define UUID_FMT1 "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
25
- #define UUID_FMT2 "{%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}"
26
- #define UUID_FMT3 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
27
-
28
- /* UUIDs are accepted in any of the following textual input formats. */
29
- #define UUID_CHK_FMT1 "00000000-0000-0000-0000-000000000000"
30
- #define UUID_CHK_FMT2 "{00000000-0000-0000-0000-000000000000}"
31
- #define UUID_CHK_FMT3 "00000000000000000000000000000000"
32
-
33
- #define PRINT_SIZE 40
34
-
35
21
/* uuid size in bytes */
36
22
#define UUID_LEN 16
37
23
38
24
/* pg_uuid_t is declared to be struct pg_uuid_t in uuid.h */
39
25
struct pg_uuid_t
40
26
{
41
- char data [UUID_LEN ];
27
+ unsigned char data [UUID_LEN ];
42
28
};
43
29
44
30
static void string_to_uuid (const char * source ,pg_uuid_t * uuid );
45
- static void uuid_to_string (const char * fmt ,const pg_uuid_t * uuid ,
46
- char * uuid_str );
47
- static bool parse_uuid_string (const char * fmt ,const char * chk_fmt ,
48
- const char * source ,char * data );
49
- static bool is_valid_format (const char * source ,const char * fmt );
50
31
static int uuid_internal_cmp (const pg_uuid_t * arg1 ,const pg_uuid_t * arg2 );
51
32
52
33
Datum
@@ -63,96 +44,105 @@ uuid_in(PG_FUNCTION_ARGS)
63
44
Datum
64
45
uuid_out (PG_FUNCTION_ARGS )
65
46
{
66
- pg_uuid_t * uuid = PG_GETARG_UUID_P (0 );
67
- char * uuid_str ;
47
+ pg_uuid_t * uuid = PG_GETARG_UUID_P (0 );
48
+ static const char hex_chars []= "0123456789abcdef" ;
49
+ StringInfoData buf ;
50
+ int i ;
68
51
69
- uuid_str = (char * )palloc (PRINT_SIZE );
70
- uuid_to_string (UUID_FMT1 ,uuid ,uuid_str );
71
- PG_RETURN_CSTRING (uuid_str );
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 );
72
75
}
73
76
74
- /* string to uuid convertor by various format types */
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
+ */
75
83
static void
76
84
string_to_uuid (const char * source ,pg_uuid_t * uuid )
77
85
{
78
- if (!parse_uuid_string (UUID_FMT1 ,UUID_CHK_FMT1 ,source ,uuid -> data )&&
79
- !parse_uuid_string (UUID_FMT2 ,UUID_CHK_FMT2 ,source ,uuid -> data )&&
80
- !parse_uuid_string (UUID_FMT3 ,UUID_CHK_FMT3 ,source ,uuid -> data ))
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
+ gotosyntax_error ;
93
+
94
+ if (src_len == 32 )
95
+ memcpy (hex_buf ,source ,src_len );
96
+ else
81
97
{
82
- ereport (ERROR ,
83
- (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
84
- errmsg ("invalid input syntax for uuid: \"%s\"" ,
85
- source )));
86
- }
87
- }
98
+ const char * str = source ;
88
99
89
- /* check the validity of a uuid string by a given format */
90
- static bool
91
- is_valid_format (const char * source ,const char * fmt )
92
- {
93
- int i ;
94
- int fmtlen = strlen (fmt );
100
+ if (src_len == 38 )
101
+ {
102
+ if (str [0 ]!= '{' || str [37 ]!= '}' )
103
+ gotosyntax_error ;
95
104
96
- /* check length first */
97
- if (fmtlen != strlen (source ))
98
- return false;
105
+ str ++ ;/* skip the first character */
106
+ }
99
107
100
- for (i = 0 ;i < fmtlen ;i ++ )
101
- {
102
- int fc ;
103
- int sc ;
104
- bool valid_chr ;
105
-
106
- fc = fmt [i ];
107
- sc = source [i ];
108
-
109
- /* false if format chr is { or - and source is not */
110
- if (fc != '0' && fc != sc )
111
- return false;
112
-
113
- /* check for valid char in source */
114
- valid_chr = (sc >='0' && sc <='9' )||
115
- (sc >='a' && sc <='f' )||
116
- (sc >='A' && sc <='F' );
117
-
118
- if (fc == '0' && !valid_chr )
119
- return false;
108
+ if (str [8 ]!= '-' || str [13 ]!= '-' ||
109
+ str [18 ]!= '-' || str [23 ]!= '-' )
110
+ gotosyntax_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 );
120
117
}
121
118
122
- return true;
123
- }
119
+ for (i = 0 ;i < UUID_LEN ;i ++ )
120
+ {
121
+ char str_buf [3 ];
124
122
125
- /* parse the uuid string to a format and return true if okay */
126
- static bool
127
- parse_uuid_string (const char * fmt ,const char * chk_fmt ,
128
- const char * source ,char * data )
129
- {
130
- int result = sscanf (source ,fmt ,
131
- & data [0 ],& data [1 ],& data [2 ],& data [3 ],& data [4 ],
132
- & data [5 ],& data [6 ],& data [7 ],& data [8 ],& data [9 ],
133
- & data [10 ],& data [11 ],& data [12 ],& data [13 ],
134
- & data [14 ],& data [15 ]);
123
+ memcpy (str_buf ,& hex_buf [i * 2 ],2 );
124
+ if (!isxdigit ((unsignedchar )str_buf [0 ])||
125
+ !isxdigit ((unsignedchar )str_buf [1 ]))
126
+ gotosyntax_error ;
135
127
136
- return (result == 16 )&& is_valid_format (source ,chk_fmt );
137
- }
128
+ str_buf [2 ]= '\0' ;
129
+ uuid -> data [i ]= (unsignedchar )strtoul (str_buf ,NULL ,16 );
130
+ }
138
131
139
- /* create a string representation of the uuid */
140
- static void
141
- uuid_to_string (const char * fmt ,const pg_uuid_t * uuid ,char * uuid_str )
142
- {
143
- const char * data = uuid -> data ;
144
- snprintf (uuid_str ,PRINT_SIZE ,fmt ,
145
- data [0 ],data [1 ],data [2 ],data [3 ],data [4 ],
146
- data [5 ],data [6 ],data [7 ],data [8 ],data [9 ],
147
- data [10 ],data [11 ],data [12 ],data [13 ],
148
- data [14 ],data [15 ]);
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 )));
149
139
}
150
140
151
141
Datum
152
142
uuid_recv (PG_FUNCTION_ARGS )
153
143
{
154
144
StringInfo buffer = (StringInfo )PG_GETARG_POINTER (0 );
155
- pg_uuid_t * uuid ;
145
+ pg_uuid_t * uuid ;
156
146
157
147
uuid = (pg_uuid_t * )palloc (UUID_LEN );
158
148
memcpy (uuid -> data ,pq_getmsgbytes (buffer ,UUID_LEN ),UUID_LEN );
@@ -166,7 +156,7 @@ uuid_send(PG_FUNCTION_ARGS)
166
156
StringInfoData buffer ;
167
157
168
158
pq_begintypsend (& buffer );
169
- pq_sendbytes (& buffer ,uuid -> data ,UUID_LEN );
159
+ pq_sendbytes (& buffer ,( char * ) uuid -> data ,UUID_LEN );
170
160
PG_RETURN_BYTEA_P (pq_endtypsend (& buffer ));
171
161
}
172
162
@@ -246,7 +236,7 @@ Datum
246
236
uuid_hash (PG_FUNCTION_ARGS )
247
237
{
248
238
pg_uuid_t * key = PG_GETARG_UUID_P (0 );
249
- return hash_any (( unsigned char * ) key , sizeof ( pg_uuid_t ) );
239
+ return hash_any (key -> data , UUID_LEN );
250
240
}
251
241
252
242
/* cast text to uuid */