Add a new builtin type, "uuid". This implements a UUID type, similar to

that defined in RFC 4122. This patch includes the basic implementation,
plus regression tests. Documentation and perhaps some additional
functionality will come later. Catversion bumped.

Patch from Gevik Babakhani; review from Peter, Tom, and myself.
This commit is contained in:
Neil Conway 2007-01-28 16:16:54 +00:00
parent a8e0b66061
commit a534068e0e
17 changed files with 621 additions and 16 deletions

View File

@ -1,7 +1,7 @@
#
# Makefile for utils/adt
#
# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.62 2007/01/20 17:16:13 petere Exp $
# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.63 2007/01/28 16:16:52 neilc Exp $
#
subdir = src/backend/utils/adt
@ -25,7 +25,8 @@ OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
network.o mac.o inet_net_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o xml.o
ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o xml.o \
uuid.o
like.o: like.c like_match.c

View File

@ -0,0 +1,279 @@
/*-------------------------------------------------------------------------
*
* uuid.c
* Functions for the built-in type "uuid".
*
* Copyright (c) 2007, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.1 2007/01/28 16:16:52 neilc Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/hash.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/uuid.h"
/* Accepted GUID formats */
/* UUID_FMT1 is the default output format */
#define UUID_FMT1 "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
#define UUID_FMT2 "{%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}"
#define UUID_FMT3 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
/* UUIDs are accepted in any of the following textual input formats. */
#define UUID_CHK_FMT1 "00000000-0000-0000-0000-000000000000"
#define UUID_CHK_FMT2 "{00000000-0000-0000-0000-000000000000}"
#define UUID_CHK_FMT3 "00000000000000000000000000000000"
#define PRINT_SIZE 40
/* uuid size in bytes */
#define UUID_LEN 16
/* The uuid_t type is declared as struct uuid_t in uuid.h */
struct uuid_t
{
char data[UUID_LEN];
};
static void uuid_data_from_string(const char *source, unsigned char *data);
static void string_from_uuid_data(const char *fmt, const char *data, char *uuid_str);
static bool parse_uuid_string(const char *fmt, const char *chk_fmt,
const char *source, unsigned char *data);
static bool is_valid_format(const char *source, const char *fmt);
static int32 uuid_internal_cmp(uuid_t *arg1, uuid_t *arg2);
Datum
uuid_in(PG_FUNCTION_ARGS)
{
char *uuid_str = PG_GETARG_CSTRING(0);
uuid_t *uuid;
uint8 data[UUID_LEN];
uuid_data_from_string(uuid_str, data);
uuid = (uuid_t *) palloc(sizeof(uuid_t));
memcpy(uuid->data, data, UUID_LEN);
PG_RETURN_UUID_P(uuid);
}
Datum
uuid_out(PG_FUNCTION_ARGS)
{
uuid_t *uuid = (uuid_t *) PG_GETARG_POINTER(0);
char *uuid_str;
uuid_str = (char *) palloc(PRINT_SIZE);
string_from_uuid_data(UUID_FMT1, uuid->data, uuid_str);
PG_RETURN_CSTRING(uuid_str);
}
/* string to uuid convertor by various format types */
static void
uuid_data_from_string(const char *source, unsigned char *data)
{
if (!parse_uuid_string(UUID_FMT1, UUID_CHK_FMT1, source, data) &&
!parse_uuid_string(UUID_FMT2, UUID_CHK_FMT2, source, data) &&
!parse_uuid_string(UUID_FMT3, UUID_CHK_FMT3, source, data))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for uuid: \"%s\"",
source)));
}
}
/* check the validity of a uuid string by a given format */
static bool
is_valid_format(const char *source, const char *fmt)
{
int i;
int fmtlen = strlen(fmt);
/* check length first */
if (fmtlen != strlen(source))
return false;
for (i = 0; i < fmtlen; i++)
{
int fc;
int sc;
bool valid_chr;
fc = fmt[i];
sc = source[i];
/* false if format chr is { or - and source is not */
if (fc != '0' && fc != sc)
return false;
/* check for valid char in source */
valid_chr = (sc >= '0' && sc <= '9') ||
(sc >= 'a' && sc <= 'f' ) ||
(sc >= 'A' && sc <= 'F' );
if (fc == '0' && !valid_chr)
return false;
}
return true;
}
/* parse the uuid string to a format and return true if okay */
static bool
parse_uuid_string(const char *fmt, const char *chk_fmt,
const char *source, unsigned char *data)
{
int result = sscanf(source, fmt,
&data[0], &data[1], &data[2], &data[3], &data[4],
&data[5], &data[6], &data[7], &data[8], &data[9],
&data[10], &data[11], &data[12], &data[13],
&data[14], &data[15]);
return (result == 16) && is_valid_format(source, chk_fmt);
}
/* create a string representation of the uuid */
static void
string_from_uuid_data(const char *fmt, const char *data, char *uuid_str)
{
snprintf(uuid_str, PRINT_SIZE, fmt,
data[0], data[1], data[2], data[3], data[4],
data[5], data[6], data[7], data[8], data[9],
data[10], data[11], data[12], data[13],
data[14], data[15]);
}
Datum
uuid_recv(PG_FUNCTION_ARGS)
{
StringInfo buffer = (StringInfo) PG_GETARG_POINTER(0);
uuid_t *uuid;
uuid = (uuid_t *) palloc(UUID_LEN);
memcpy(uuid->data, pq_getmsgbytes(buffer, UUID_LEN), UUID_LEN);
PG_RETURN_POINTER(uuid);
}
Datum
uuid_send(PG_FUNCTION_ARGS)
{
uuid_t *uuid = PG_GETARG_UUID_P(0);
StringInfoData buffer;
pq_begintypsend(&buffer);
pq_sendbytes(&buffer, uuid->data, UUID_LEN);
PG_RETURN_BYTEA_P(pq_endtypsend(&buffer));
}
/* internal uuid compare function */
static int32
uuid_internal_cmp(uuid_t *arg1, uuid_t *arg2)
{
return memcmp(arg1->data, arg2->data, UUID_LEN);
}
Datum
uuid_lt(PG_FUNCTION_ARGS)
{
uuid_t *arg1 = PG_GETARG_UUID_P(0);
uuid_t *arg2 = PG_GETARG_UUID_P(1);
PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) < 0);
}
Datum
uuid_le(PG_FUNCTION_ARGS)
{
uuid_t *arg1 = PG_GETARG_UUID_P(0);
uuid_t *arg2 = PG_GETARG_UUID_P(1);
PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) <= 0);
}
Datum
uuid_eq(PG_FUNCTION_ARGS)
{
uuid_t *arg1 = PG_GETARG_UUID_P(0);
uuid_t *arg2 = PG_GETARG_UUID_P(1);
PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) == 0);
}
Datum
uuid_ge(PG_FUNCTION_ARGS)
{
uuid_t *arg1 = PG_GETARG_UUID_P(0);
uuid_t *arg2 = PG_GETARG_UUID_P(1);
PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) >= 0);
}
Datum
uuid_gt(PG_FUNCTION_ARGS)
{
uuid_t *arg1 = PG_GETARG_UUID_P(0);
uuid_t *arg2 = PG_GETARG_UUID_P(1);
PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) > 0);
}
Datum
uuid_ne(PG_FUNCTION_ARGS)
{
uuid_t *arg1 = PG_GETARG_UUID_P(0);
uuid_t *arg2 = PG_GETARG_UUID_P(1);
PG_RETURN_BOOL(uuid_internal_cmp(arg1, arg2) != 0);
}
/* handler for btree index operator */
Datum
uuid_cmp(PG_FUNCTION_ARGS)
{
uuid_t *arg1 = PG_GETARG_UUID_P(0);
uuid_t *arg2 = PG_GETARG_UUID_P(1);
PG_RETURN_INT32(uuid_internal_cmp(arg1, arg2));
}
/* hash index support */
Datum
uuid_hash(PG_FUNCTION_ARGS)
{
uuid_t *key = PG_GETARG_UUID_P(0);
return hash_any((unsigned char *) key, sizeof(uuid_t));
}
/* cast text to uuid */
Datum
text_uuid(PG_FUNCTION_ARGS)
{
text *input = PG_GETARG_TEXT_P(0);
int length;
char *str;
Datum result;
length = VARSIZE(input) - VARHDRSZ;
str = palloc(length + 1);
memcpy(str, VARDATA(input), length);
*(str + length) = '\0';
result = DirectFunctionCall1(uuid_in, CStringGetDatum(str));
pfree(str);
PG_RETURN_DATUM(result);
}
/* cast uuid to text */
Datum
uuid_text(PG_FUNCTION_ARGS)
{
uuid_t *uuid = PG_GETARG_UUID_P(0);
Datum uuid_str = DirectFunctionCall1(uuid_out, UUIDPGetDatum(uuid));
PG_RETURN_DATUM(DirectFunctionCall1(textin, uuid_str));
}

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.376 2007/01/22 01:35:21 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.377 2007/01/28 16:16:52 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200701211
#define CATALOG_VERSION_NO 200701281
#endif

View File

@ -29,7 +29,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.77 2007/01/05 22:19:52 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.78 2007/01/28 16:16:52 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -487,6 +487,16 @@ DATA(insert ( 397 2277 2277 3 f 1070 403 ));
DATA(insert ( 397 2277 2277 4 f 1075 403 ));
DATA(insert ( 397 2277 2277 5 f 1073 403 ));
/*
* btree uuid_ops
*/
DATA(insert ( 2968 2950 2950 1 f 2974 403 ));
DATA(insert ( 2968 2950 2950 2 f 2976 403 ));
DATA(insert ( 2968 2950 2950 3 f 2972 403 ));
DATA(insert ( 2968 2950 2950 4 f 2977 403 ));
DATA(insert ( 2968 2950 2950 5 f 2975 403 ));
/*
* hash index _ops
*/
@ -548,6 +558,9 @@ DATA(insert ( 2231 1042 1042 1 f 2328 405 ));
DATA(insert ( 2232 19 19 1 f 2334 405 ));
/* aclitem_ops */
DATA(insert ( 2235 1033 1033 1 f 974 405 ));
/* uuid_ops */
DATA(insert ( 2969 2950 2950 1 f 2972 405 ));
/*
* gist box_ops

View File

@ -22,7 +22,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.62 2007/01/05 22:19:52 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.63 2007/01/28 16:16:52 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -127,6 +127,7 @@ DATA(insert ( 2099 790 790 1 377 ));
DATA(insert ( 2233 703 703 1 380 ));
DATA(insert ( 2234 704 704 1 381 ));
DATA(insert ( 2789 27 27 1 2794 ));
DATA(insert ( 2968 2950 2950 1 2960 ));
/* hash */
@ -160,6 +161,7 @@ DATA(insert ( 2229 25 25 1 456 ));
DATA(insert ( 2231 1042 1042 1 456 ));
DATA(insert ( 2232 19 19 1 455 ));
DATA(insert ( 2235 1033 1033 1 329 ));
DATA(insert ( 2969 2950 2950 1 2963 ));
/* gist */

View File

@ -10,7 +10,7 @@
*
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.28 2007/01/05 22:19:52 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.29 2007/01/28 16:16:52 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -397,4 +397,8 @@ DATA(insert ( 1560 1560 1685 i ));
DATA(insert ( 1562 1562 1687 i ));
DATA(insert ( 1700 1700 1703 i ));
/* casts to and from uuid */
DATA(insert ( 25 2950 2964 a ));
DATA(insert ( 2950 25 2965 a ));
#endif /* PG_CAST_H */

View File

@ -28,7 +28,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.73 2007/01/05 22:19:52 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.74 2007/01/28 16:16:52 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -200,5 +200,7 @@ DATA(insert ( 2742 _timestamp_ops PGNSP PGUID 2745 1115 t 1114 ));
DATA(insert ( 2742 _money_ops PGNSP PGUID 2745 791 t 790 ));
DATA(insert ( 2742 _reltime_ops PGNSP PGUID 2745 1024 t 703 ));
DATA(insert ( 2742 _tinterval_ops PGNSP PGUID 2745 1025 t 704 ));
DATA(insert ( 403 uuid_ops PGNSP PGUID 2968 2950 t 0 ));
DATA(insert ( 405 uuid_ops PGNSP PGUID 2969 2950 t 0 ));
#endif /* PG_OPCLASS_H */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.148 2007/01/05 22:19:53 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.149 2007/01/28 16:16:52 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -895,6 +895,14 @@ DATA(insert OID = 2875 ( "@" PGNSP PGUID b f f 601 628 16 0 0 on_sl - - )
DATA(insert OID = 2876 ( "@" PGNSP PGUID b f f 601 603 16 0 0 on_sb - - ));
DATA(insert OID = 2877 ( "~" PGNSP PGUID b f f 1034 1033 16 0 0 aclcontains - - ));
/* uuid operators */
DATA(insert OID = 2972 ( "=" PGNSP PGUID b t t 2950 2950 16 2972 2973 uuid_eq eqsel eqjoinsel ));
DATA(insert OID = 2973 ( "<>" PGNSP PGUID b f f 2950 2950 16 2973 2972 uuid_ne neqsel neqjoinsel ));
DATA(insert OID = 2974 ( "<" PGNSP PGUID b f f 2950 2950 16 2975 2977 uuid_lt scalarltsel scalarltjoinsel ));
DATA(insert OID = 2975 ( ">" PGNSP PGUID b f f 2950 2950 16 2974 2976 uuid_gt scalargtsel scalargtjoinsel ));
DATA(insert OID = 2976 ( "<=" PGNSP PGUID b f f 2950 2950 16 2977 2975 uuid_le scalarltsel scalarltjoinsel ));
DATA(insert OID = 2977 ( ">=" PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel ));
/*
* function prototypes

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_opfamily.h,v 1.2 2007/01/05 22:19:53 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_opfamily.h,v 1.3 2007/01/28 16:16:52 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -134,5 +134,8 @@ DATA(insert OID = 2593 ( 783 box_ops PGNSP PGUID ));
DATA(insert OID = 2594 ( 783 poly_ops PGNSP PGUID ));
DATA(insert OID = 2595 ( 783 circle_ops PGNSP PGUID ));
DATA(insert OID = 2745 ( 2742 array_ops PGNSP PGUID ));
DATA(insert OID = 2968 ( 403 uuid_ops PGNSP PGUID ));
DATA(insert OID = 2969 ( 405 uuid_ops PGNSP PGUID ));
#endif /* PG_OPFAMILY_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.440 2007/01/22 01:35:22 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.441 2007/01/28 16:16:52 neilc Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -4046,6 +4046,35 @@ DESCR("aggregate transition function");
DATA(insert OID = 2901 ( xmlagg PGNSP PGUID 12 1 0 t f f f i 1 142 "142" _null_ _null_ _null_ aggregate_dummy - _null_ ));
DESCR("concatenate XML values");
/* uuid */
DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 f f t f i 1 2950 "2275" _null_ _null_ _null_ uuid_in - _null_ ));
DESCR("I/O");
DATA(insert OID = 2953 ( uuid_out PGNSP PGUID 12 1 0 f f t f i 1 2275 "2950" _null_ _null_ _null_ uuid_out - _null_ ));
DESCR("I/O");
DATA(insert OID = 2954 ( uuid_lt PGNSP PGUID 12 1 0 f f t f i 2 16 "2950 2950" _null_ _null_ _null_ uuid_lt - _null_ ));
DESCR("less-than");
DATA(insert OID = 2955 ( uuid_le PGNSP PGUID 12 1 0 f f t f i 2 16 "2950 2950" _null_ _null_ _null_ uuid_le - _null_ ));
DESCR("less-than-or-equal");
DATA(insert OID = 2956 ( uuid_eq PGNSP PGUID 12 1 0 f f t f i 2 16 "2950 2950" _null_ _null_ _null_ uuid_eq - _null_ ));
DESCR("equal");
DATA(insert OID = 2957 ( uuid_ge PGNSP PGUID 12 1 0 f f t f i 2 16 "2950 2950" _null_ _null_ _null_ uuid_ge - _null_ ));
DESCR("greater-than-or-equal");
DATA(insert OID = 2958 ( uuid_gt PGNSP PGUID 12 1 0 f f t f i 2 16 "2950 2950" _null_ _null_ _null_ uuid_gt - _null_ ));
DESCR("greater-than");
DATA(insert OID = 2959 ( uuid_ne PGNSP PGUID 12 1 0 f f t f i 2 16 "2950 2950" _null_ _null_ _null_ uuid_ne - _null_ ));
DESCR("not-equal");
DATA(insert OID = 2960 ( uuid_cmp PGNSP PGUID 12 1 0 f f t f i 2 23 "2950 2950" _null_ _null_ _null_ uuid_cmp - _null_ ));
DESCR("btree less-equal-greater");
DATA(insert OID = 2961 ( uuid_recv PGNSP PGUID 12 1 0 f f t f i 1 2950 "2281" _null_ _null_ _null_ uuid_recv - _null_ ));
DESCR("I/O");
DATA(insert OID = 2962 ( uuid_send PGNSP PGUID 12 1 0 f f t f i 1 17 "2950" _null_ _null_ _null_ uuid_send - _null_ ));
DESCR("I/O");
DATA(insert OID = 2963 ( uuid_hash PGNSP PGUID 12 1 0 f f t f i 1 23 "2950" _null_ _null_ _null_ uuid_hash - _null_ ));
DESCR("hash");
DATA(insert OID = 2964 ( uuid PGNSP PGUID 12 1 0 f f t f i 1 2950 "25" _null_ _null_ _null_ text_uuid - _null_ ));
DESCR("convert text to uuid");
DATA(insert OID = 2965 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "2950" _null_ _null_ _null_ uuid_text - _null_ ));
DESCR("convert uuid to text");
/*
* Symbolic values for provolatile column: these indicate whether the result

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.179 2007/01/05 22:19:53 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.180 2007/01/28 16:16:54 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -561,6 +561,11 @@ DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p t \054 0 0 opaque_in opaque
DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 _null_ _null_ ));
#define ANYELEMENTOID 2283
/* uuid */
DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b t \054 0 0 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 _null_ _null_ ));
DESCR("UUID datatype");
DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b t \054 0 2950 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
/*
* prototypes for functions in pg_type.c
*/

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.286 2007/01/16 21:41:14 neilc Exp $
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.287 2007/01/28 16:16:54 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -926,4 +926,20 @@ extern Datum pg_prepared_statement(PG_FUNCTION_ARGS);
/* utils/mmgr/portalmem.c */
extern Datum pg_cursor(PG_FUNCTION_ARGS);
/* uuid.c */
extern Datum uuid_in(PG_FUNCTION_ARGS);
extern Datum uuid_out(PG_FUNCTION_ARGS);
extern Datum uuid_send(PG_FUNCTION_ARGS);
extern Datum uuid_recv(PG_FUNCTION_ARGS);
extern Datum uuid_lt(PG_FUNCTION_ARGS);
extern Datum uuid_le(PG_FUNCTION_ARGS);
extern Datum uuid_eq(PG_FUNCTION_ARGS);
extern Datum uuid_ge(PG_FUNCTION_ARGS);
extern Datum uuid_gt(PG_FUNCTION_ARGS);
extern Datum uuid_ne(PG_FUNCTION_ARGS);
extern Datum uuid_cmp(PG_FUNCTION_ARGS);
extern Datum uuid_hash(PG_FUNCTION_ARGS);
extern Datum text_uuid(PG_FUNCTION_ARGS);
extern Datum uuid_text(PG_FUNCTION_ARGS);
#endif /* BUILTINS_H */

27
src/include/utils/uuid.h Normal file
View File

@ -0,0 +1,27 @@
/*-------------------------------------------------------------------------
*
* uuid.h
* Header file for the "uuid" data type.
*
* Copyright (c) 2007, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/utils/uuid.h,v 1.1 2007/01/28 16:16:54 neilc Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef UUID_H
#define UUID_H
/* guid size in bytes */
#define UUID_LEN 16
/* opaque struct; defined in uuid.c */
typedef struct uuid_t uuid_t;
/* fmgr interface macros */
#define UUIDPGetDatum(X) PointerGetDatum(X)
#define PG_RETURN_UUID_P(X) return UUIDPGetDatum(X)
#define DatumGetUUIDP(X) ((uuid_t *) DatumGetPointer(X))
#define PG_GETARG_UUID_P(X) DatumGetUUIDP(PG_GETARG_DATUM(X))
#endif /* UUID_H */

View File

@ -0,0 +1,136 @@
-- regression test for the uuid datatype
-- creating test tables
CREATE TABLE guid1
(
guid_field UUID,
text_field TEXT DEFAULT(now())
);
CREATE TABLE guid2
(
guid_field UUID,
text_field TEXT DEFAULT(now())
);
-- inserting invalid data tests
-- too long
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111F');
ERROR: invalid input syntax for uuid: "11111111-1111-1111-1111-111111111111F"
-- too short
INSERT INTO guid1(guid_field) VALUES('{11111111-1111-1111-1111-11111111111}');
ERROR: invalid input syntax for uuid: "{11111111-1111-1111-1111-11111111111}"
-- valid data but invalid format
INSERT INTO guid1(guid_field) VALUES('111-11111-1111-1111-1111-111111111111');
ERROR: invalid input syntax for uuid: "111-11111-1111-1111-1111-111111111111"
INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222 ');
ERROR: invalid input syntax for uuid: "{22222222-2222-2222-2222-222222222222 "
-- invalid data
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-G111-111111111111');
ERROR: invalid input syntax for uuid: "11111111-1111-1111-G111-111111111111"
INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111');
ERROR: invalid input syntax for uuid: "11+11111-1111-1111-1111-111111111111"
--inserting three input formats
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
INSERT INTO guid1(guid_field) VALUES('33333333333333333333333333333333');
-- retrieving the inserted data
SELECT guid_field FROM guid1;
guid_field
--------------------------------------
11111111-1111-1111-1111-111111111111
22222222-2222-2222-2222-222222222222
33333333-3333-3333-3333-333333333333
(3 rows)
-- ordering test
SELECT guid_field FROM guid1 ORDER BY guid_field ASC;
guid_field
--------------------------------------
11111111-1111-1111-1111-111111111111
22222222-2222-2222-2222-222222222222
33333333-3333-3333-3333-333333333333
(3 rows)
SELECT guid_field FROM guid1 ORDER BY guid_field DESC;
guid_field
--------------------------------------
33333333-3333-3333-3333-333333333333
22222222-2222-2222-2222-222222222222
11111111-1111-1111-1111-111111111111
(3 rows)
-- = operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field = '33333333-3333-3333-3333-333333333333';
count
-------
1
(1 row)
-- <> operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field <> '11111111111111111111111111111111';
count
-------
2
(1 row)
-- < operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field < '22222222-2222-2222-2222-222222222222';
count
-------
1
(1 row)
-- <= operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field <= '22222222-2222-2222-2222-222222222222';
count
-------
2
(1 row)
-- > operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field > '22222222-2222-2222-2222-222222222222';
count
-------
1
(1 row)
-- >= operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field >= '22222222-2222-2222-2222-222222222222';
count
-------
2
(1 row)
-- btree and hash index creation test
CREATE INDEX guid1_btree ON guid1 USING BTREE (guid_field);
CREATE INDEX guid1_hash ON guid1 USING HASH (guid_field);
-- unique index test
CREATE UNIQUE INDEX guid1_unique_BTREE ON guid1 USING BTREE (guid_field);
-- should fail
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
ERROR: duplicate key violates unique constraint "guid1_unique_btree"
-- check to see whether the new indexes are actually there
SELECT count(*) FROM pg_class WHERE relkind='i' AND relname LIKE 'guid%';
count
-------
3
(1 row)
-- populating the test tables with additional records
INSERT INTO guid1(guid_field) VALUES('44444444-4444-4444-4444-444444444444');
INSERT INTO guid2(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
INSERT INTO guid2(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
INSERT INTO guid2(guid_field) VALUES('33333333333333333333333333333333');
-- join test
SELECT COUNT(*) FROM guid1 g1 INNER JOIN guid2 g2 ON g1.guid_field = g2.guid_field;
count
-------
3
(1 row)
SELECT COUNT(*) FROM guid1 g1 LEFT JOIN guid2 g2 ON g1.guid_field = g2.guid_field WHERE g2.guid_field IS NULL;
count
-------
1
(1 row)
-- clean up
DROP TABLE guid1, guid2 CASCADE;

View File

@ -1,8 +1,8 @@
# ----------
# The first group of parallel test
# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.37 2007/01/20 17:15:43 neilc Exp $
# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.38 2007/01/28 16:16:54 neilc Exp $
# ----------
test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric
test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid
# Depends on things setup during char, varchar and text
test: strings

View File

@ -1,4 +1,4 @@
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.35 2007/01/20 17:15:43 neilc Exp $
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.36 2007/01/28 16:16:54 neilc Exp $
# This should probably be in an order similar to parallel_schedule.
test: boolean
test: char
@ -13,6 +13,7 @@ test: float4
test: float8
test: bit
test: numeric
test: uuid
test: strings
test: numerology
test: point

View File

@ -0,0 +1,79 @@
-- regression test for the uuid datatype
-- creating test tables
CREATE TABLE guid1
(
guid_field UUID,
text_field TEXT DEFAULT(now())
);
CREATE TABLE guid2
(
guid_field UUID,
text_field TEXT DEFAULT(now())
);
-- inserting invalid data tests
-- too long
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111F');
-- too short
INSERT INTO guid1(guid_field) VALUES('{11111111-1111-1111-1111-11111111111}');
-- valid data but invalid format
INSERT INTO guid1(guid_field) VALUES('111-11111-1111-1111-1111-111111111111');
INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222 ');
-- invalid data
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-G111-111111111111');
INSERT INTO guid1(guid_field) VALUES('11+11111-1111-1111-1111-111111111111');
--inserting three input formats
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
INSERT INTO guid1(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
INSERT INTO guid1(guid_field) VALUES('33333333333333333333333333333333');
-- retrieving the inserted data
SELECT guid_field FROM guid1;
-- ordering test
SELECT guid_field FROM guid1 ORDER BY guid_field ASC;
SELECT guid_field FROM guid1 ORDER BY guid_field DESC;
-- = operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field = '33333333-3333-3333-3333-333333333333';
-- <> operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field <> '11111111111111111111111111111111';
-- < operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field < '22222222-2222-2222-2222-222222222222';
-- <= operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field <= '22222222-2222-2222-2222-222222222222';
-- > operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field > '22222222-2222-2222-2222-222222222222';
-- >= operator test
SELECT COUNT(*) FROM guid1 WHERE guid_field >= '22222222-2222-2222-2222-222222222222';
-- btree and hash index creation test
CREATE INDEX guid1_btree ON guid1 USING BTREE (guid_field);
CREATE INDEX guid1_hash ON guid1 USING HASH (guid_field);
-- unique index test
CREATE UNIQUE INDEX guid1_unique_BTREE ON guid1 USING BTREE (guid_field);
-- should fail
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
-- check to see whether the new indexes are actually there
SELECT count(*) FROM pg_class WHERE relkind='i' AND relname LIKE 'guid%';
-- populating the test tables with additional records
INSERT INTO guid1(guid_field) VALUES('44444444-4444-4444-4444-444444444444');
INSERT INTO guid2(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
INSERT INTO guid2(guid_field) VALUES('{22222222-2222-2222-2222-222222222222}');
INSERT INTO guid2(guid_field) VALUES('33333333333333333333333333333333');
-- join test
SELECT COUNT(*) FROM guid1 g1 INNER JOIN guid2 g2 ON g1.guid_field = g2.guid_field;
SELECT COUNT(*) FROM guid1 g1 LEFT JOIN guid2 g2 ON g1.guid_field = g2.guid_field WHERE g2.guid_field IS NULL;
-- clean up
DROP TABLE guid1, guid2 CASCADE;