diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 238fb8e862..ad3b848607 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -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 index 0000000000..124d430dbf --- /dev/null +++ b/src/backend/utils/adt/uuid.c @@ -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)); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index ccf5f90357..89dfefe30f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 7137c6e1c3..01e47df7d9 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -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 diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index bc77f54a38..64db648341 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -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 */ diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 2c5a2e9e9c..a66b8c5b2e 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -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 */ diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 21c7d54ae8..148f02db2a 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -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 */ diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 26a15f7139..6411da05c3 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -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 diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h index 1f91e58f3f..63d1b27764 100644 --- a/src/include/catalog/pg_opfamily.h +++ b/src/include/catalog/pg_opfamily.h @@ -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 */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index c0c9a3cfd0..eaee341096 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -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 diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index ebaa13049e..89849c25fc 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -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 */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 3368e2c024..aee4095654 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -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 index 0000000000..12cb00a0b7 --- /dev/null +++ b/src/include/utils/uuid.h @@ -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 index 0000000000..9f714ad2e1 --- /dev/null +++ b/src/test/regress/expected/uuid.out @@ -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; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index c2e53fb5c3..efc1f1fef6 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -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 diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 4c1c63c62e..75e8b83138 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -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 index 0000000000..93153da9d7 --- /dev/null +++ b/src/test/regress/sql/uuid.sql @@ -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;