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
+ goto syntax_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
+ goto syntax_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
+ 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 );
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 ((unsigned char ) str_buf [0 ]) ||
125
+ !isxdigit ((unsigned char ) str_buf [1 ]))
126
+ goto syntax_error ;
135
127
136
- return (result == 16 ) && is_valid_format (source , chk_fmt );
137
- }
128
+ str_buf [2 ] = '\0' ;
129
+ uuid -> data [i ] = (unsigned char ) 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 */
0 commit comments