Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 05ce7d6

Browse files
author
Neil Conway
committed
Rewrite uuid input and output routines to avoid dependency on the
nonportable "hh" sprintf(3) length modifier. Instead, do the parsing and output by hand. The code to do this isn't ideal, but this is an interim measure anyway: the uuid type should probably use the in-memory struct layout specified by RFC 4122. For now, this patch should hopefully rectify the buildfarm failures for the uuid test. Along the way, re-add pg_cast entries for uuid <-> varchar, which I mistakenly removed earlier, and bump the catversion.
1 parent 068bf65 commit 05ce7d6

File tree

5 files changed

+96
-104
lines changed

5 files changed

+96
-104
lines changed

src/backend/utils/adt/uuid.c

+82-92
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
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
*/
@@ -18,35 +18,16 @@
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 */
3925
struct pg_uuid_t
4026
{
41-
char data[UUID_LEN];
27+
unsigned char data[UUID_LEN];
4228
};
4329

4430
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);
5031
static int uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2);
5132

5233
Datum
@@ -63,96 +44,105 @@ uuid_in(PG_FUNCTION_ARGS)
6344
Datum
6445
uuid_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+
*/
7583
static void
7684
string_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+
goto syntax_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+
goto syntax_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+
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);
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((unsigned char) str_buf[0]) ||
125+
!isxdigit((unsigned char) str_buf[1]))
126+
goto syntax_error;
135127

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+
}
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

151141
Datum
152142
uuid_recv(PG_FUNCTION_ARGS)
153143
{
154144
StringInfo buffer = (StringInfo) PG_GETARG_POINTER(0);
155-
pg_uuid_t *uuid;
145+
pg_uuid_t *uuid;
156146

157147
uuid = (pg_uuid_t *) palloc(UUID_LEN);
158148
memcpy(uuid->data, pq_getmsgbytes(buffer, UUID_LEN), UUID_LEN);
@@ -166,7 +156,7 @@ uuid_send(PG_FUNCTION_ARGS)
166156
StringInfoData buffer;
167157

168158
pq_begintypsend(&buffer);
169-
pq_sendbytes(&buffer, uuid->data, UUID_LEN);
159+
pq_sendbytes(&buffer, (char *) uuid->data, UUID_LEN);
170160
PG_RETURN_BYTEA_P(pq_endtypsend(&buffer));
171161
}
172162

@@ -246,7 +236,7 @@ Datum
246236
uuid_hash(PG_FUNCTION_ARGS)
247237
{
248238
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);
250240
}
251241

252242
/* cast text to uuid */

src/include/catalog/catversion.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.377 2007/01/28 16:16:52 neilc Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.378 2007/01/31 19:33:54 neilc Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 200701281
56+
#define CATALOG_VERSION_NO 200701311
5757

5858
#endif

src/include/catalog/pg_cast.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
1212
*
13-
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.29 2007/01/28 16:16:52 neilc Exp $
13+
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.30 2007/01/31 19:33:54 neilc Exp $
1414
*
1515
* NOTES
1616
* the genbki.sh script reads this file and generates .bki
@@ -400,5 +400,7 @@ DATA(insert ( 1700 1700 1703 i ));
400400
/* casts to and from uuid */
401401
DATA(insert ( 25 2950 2964 a ));
402402
DATA(insert ( 2950 25 2965 a ));
403+
DATA(insert ( 1043 2950 2964 a ));
404+
DATA(insert ( 2950 1043 2965 a ));
403405

404406
#endif /* PG_CAST_H */

src/test/regress/expected/uuid.out

+6-6
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ ERROR: invalid input syntax for uuid: "11+11111-1111-1111-1111-111111111111"
3030
--inserting three input formats
3131
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
3232
INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
33-
INSERT INTO guid1(guid_field) VALUES('33333333333333333333333333333333');
33+
INSERT INTO guid1(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e');
3434
-- retrieving the inserted data
3535
SELECT guid_field FROM guid1;
3636
guid_field
3737
--------------------------------------
3838
11111111-1111-1111-1111-111111111111
3939
22222222-2222-2222-2222-222222222222
40-
33333333-3333-3333-3333-333333333333
40+
3f3e3c3b-3a30-3938-3736-353433a2313e
4141
(3 rows)
4242

4343
-- ordering test
@@ -46,19 +46,19 @@ SELECT guid_field FROM guid1 ORDER BY guid_field ASC;
4646
--------------------------------------
4747
11111111-1111-1111-1111-111111111111
4848
22222222-2222-2222-2222-222222222222
49-
33333333-3333-3333-3333-333333333333
49+
3f3e3c3b-3a30-3938-3736-353433a2313e
5050
(3 rows)
5151

5252
SELECT guid_field FROM guid1 ORDER BY guid_field DESC;
5353
guid_field
5454
--------------------------------------
55-
33333333-3333-3333-3333-333333333333
55+
3f3e3c3b-3a30-3938-3736-353433a2313e
5656
22222222-2222-2222-2222-222222222222
5757
11111111-1111-1111-1111-111111111111
5858
(3 rows)
5959

6060
-- = operator test
61-
SELECT COUNT(*) FROM guid1 WHERE guid_field = '33333333-3333-3333-3333-333333333333';
61+
SELECT COUNT(*) FROM guid1 WHERE guid_field = '3f3e3c3b-3a30-3938-3736-353433a2313e';
6262
count
6363
-------
6464
1
@@ -118,7 +118,7 @@ SELECT count(*) FROM pg_class WHERE relkind='i' AND relname LIKE 'guid%';
118118
INSERT INTO guid1(guid_field) VALUES('44444444-4444-4444-4444-444444444444');
119119
INSERT INTO guid2(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
120120
INSERT INTO guid2(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
121-
INSERT INTO guid2(guid_field) VALUES('33333333333333333333333333333333');
121+
INSERT INTO guid2(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e');
122122
-- join test
123123
SELECT COUNT(*) FROM guid1 g1 INNER JOIN guid2 g2 ON g1.guid_field = g2.guid_field;
124124
count

src/test/regress/sql/uuid.sql

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111');
2626
--inserting three input formats
2727
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
2828
INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
29-
INSERT INTO guid1(guid_field) VALUES('33333333333333333333333333333333');
29+
INSERT INTO guid1(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e');
3030

3131
-- retrieving the inserted data
3232
SELECT guid_field FROM guid1;
@@ -36,7 +36,7 @@ SELECT guid_field FROM guid1 ORDER BY guid_field ASC;
3636
SELECT guid_field FROM guid1 ORDER BY guid_field DESC;
3737

3838
-- = operator test
39-
SELECT COUNT(*) FROM guid1 WHERE guid_field = '33333333-3333-3333-3333-333333333333';
39+
SELECT COUNT(*) FROM guid1 WHERE guid_field = '3f3e3c3b-3a30-3938-3736-353433a2313e';
4040

4141
-- <> operator test
4242
SELECT COUNT(*) FROM guid1 WHERE guid_field <> '11111111111111111111111111111111';
@@ -69,7 +69,7 @@ SELECT count(*) FROM pg_class WHERE relkind='i' AND relname LIKE 'guid%';
6969
INSERT INTO guid1(guid_field) VALUES('44444444-4444-4444-4444-444444444444');
7070
INSERT INTO guid2(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
7171
INSERT INTO guid2(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
72-
INSERT INTO guid2(guid_field) VALUES('33333333333333333333333333333333');
72+
INSERT INTO guid2(guid_field) VALUES('3f3e3c3b3a3039383736353433a2313e');
7373

7474
-- join test
7575
SELECT COUNT(*) FROM guid1 g1 INNER JOIN guid2 g2 ON g1.guid_field = g2.guid_field;

0 commit comments

Comments
 (0)