66 * Copyright (c) 2007, PostgreSQL Global Development Group
77 *
88 * 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 $
1010 *
1111 *-------------------------------------------------------------------------
1212 */
1818#include "utils/builtins.h"
1919#include "utils/uuid.h"
2020
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-
3521/* uuid size in bytes */
3622#define UUID_LEN 16
3723
3824/* pg_uuid_t is declared to be struct pg_uuid_t in uuid.h */
3925struct pg_uuid_t
4026{
41- char data [UUID_LEN ];
27+ unsigned char data [UUID_LEN ];
4228};
4329
4430static 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 );
5031static int uuid_internal_cmp (const pg_uuid_t * arg1 ,const pg_uuid_t * arg2 );
5132
5233Datum
@@ -63,96 +44,105 @@ uuid_in(PG_FUNCTION_ARGS)
6344Datum
6445uuid_out (PG_FUNCTION_ARGS )
6546{
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 ;
6851
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 );
7275}
7376
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+ */
7583static void
7684string_to_uuid (const char * source ,pg_uuid_t * uuid )
7785{
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
8197{
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 ;
8899
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 ;
95104
96- /* check length first */
97- if (fmtlen != strlen (source ))
98- return false;
105+ str ++ ;/* skip the first character */
106+ }
99107
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 );
120117}
121118
122- return true;
123- }
119+ for (i = 0 ;i < UUID_LEN ;i ++ )
120+ {
121+ char str_buf [3 ];
124122
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 ;
135127
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+ }
138131
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 )));
149139}
150140
151141Datum
152142uuid_recv (PG_FUNCTION_ARGS )
153143{
154144StringInfo buffer = (StringInfo )PG_GETARG_POINTER (0 );
155- pg_uuid_t * uuid ;
145+ pg_uuid_t * uuid ;
156146
157147uuid = (pg_uuid_t * )palloc (UUID_LEN );
158148memcpy (uuid -> data ,pq_getmsgbytes (buffer ,UUID_LEN ),UUID_LEN );
@@ -166,7 +156,7 @@ uuid_send(PG_FUNCTION_ARGS)
166156StringInfoData buffer ;
167157
168158pq_begintypsend (& buffer );
169- pq_sendbytes (& buffer ,uuid -> data ,UUID_LEN );
159+ pq_sendbytes (& buffer ,( char * ) uuid -> data ,UUID_LEN );
170160PG_RETURN_BYTEA_P (pq_endtypsend (& buffer ));
171161}
172162
@@ -246,7 +236,7 @@ Datum
246236uuid_hash (PG_FUNCTION_ARGS )
247237{
248238pg_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 );
250240}
251241
252242/* cast text to uuid */