]> granicus.if.org Git - postgresql/commitdiff
Add a new builtin type, "uuid". This implements a UUID type, similar to
authorNeil Conway <neilc@samurai.com>
Sun, 28 Jan 2007 16:16:54 +0000 (16:16 +0000)
committerNeil Conway <neilc@samurai.com>
Sun, 28 Jan 2007 16:16:54 +0000 (16:16 +0000)
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.

17 files changed:
src/backend/utils/adt/Makefile
src/backend/utils/adt/uuid.c [new file with mode: 0644]
src/include/catalog/catversion.h
src/include/catalog/pg_amop.h
src/include/catalog/pg_amproc.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_opclass.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_opfamily.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_type.h
src/include/utils/builtins.h
src/include/utils/uuid.h [new file with mode: 0644]
src/test/regress/expected/uuid.out [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/uuid.sql [new file with mode: 0644]

index 238fb8e862feee81f74a675fdd55f40c9119c4ae..ad3b848607b9a768e1e209e5baaa67fa34e4e6f4 100644 (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
 
diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c
new file mode 100644 (file)
index 0000000..124d430
--- /dev/null
@@ -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));
+}
index ccf5f90357e8f72d3db9fbb08b348962d5bf8b62..89dfefe30fb511830fc1e6ef53a9cd2ae85eef7a 100644 (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
index 7137c6e1c34bd93eb795997816068e25137f4104..01e47df7d9cb31e23c6760b09b7d855d327e3004 100644 (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
index bc77f54a384d7e8014e39d174d46119d9b36242e..64db6483417048af085a32c644f64aeb7705725b 100644 (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 */
index 2c5a2e9e9c59cf549571599e82ab859d9ca6f32e..a66b8c5b2e61c9ebc9e321ed3e82bda3bfd6c367 100644 (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 */
index 21c7d54ae8eec150b4c1191d5eee53103b2ccf15..148f02db2a99d32d8febdd0d02dbf669e152eaba 100644 (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 */
index 26a15f7139e648cb50d1ca4cbd18be8b2b59a91a..6411da05c3a63390c46879f8a9fb1478f51f28ed 100644 (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
index 1f91e58f3fb4b614b8d5db34773d565402cae1d4..63d1b2776431edec4a8aa656dd402a3e6dae8fdf 100644 (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 */
index c0c9a3cfd05754d769e21c7abf71e0b0604ec91f..eaee34109626fed34d5486437c45f9c545e90e97 100644 (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
index ebaa13049efc3e712029f2084a37ccc549a5c282..89849c25fcbf10355b0650af89b1e7ac03a5a9ac 100644 (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
  */
index 3368e2c024fb8d8739c6244c2e29057ed29d0e92..aee4095654c639156e36ed831c08a22440ab5c4d 100644 (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 */
diff --git a/src/include/utils/uuid.h b/src/include/utils/uuid.h
new file mode 100644 (file)
index 0000000..12cb00a
--- /dev/null
@@ -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 */
diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out
new file mode 100644 (file)
index 0000000..9f714ad
--- /dev/null
@@ -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;
index c2e53fb5c351473088d3b65c8f48ecb6c75e3693..efc1f1fef6e2cfa7fba2a3ec36bff1f5e30f2d87 100644 (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
index 4c1c63c62e08c9e3fafa19419934a1093ebfa04e..75e8b83138b33e7003964d188573c17debd942bd 100644 (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
diff --git a/src/test/regress/sql/uuid.sql b/src/test/regress/sql/uuid.sql
new file mode 100644 (file)
index 0000000..93153da
--- /dev/null
@@ -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;