diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 3017c674040..d8d91678e86 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4439,6 +4439,17 @@ a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11 Output is always in the standard form. + + It is possible to cast uuid values to and from type + bytea. This is useful for using functions such as + encode() and decode() + with UUID values. For example: + +encode('1ea3d64c-bc40-4cc3-84bb-6b11ee31e5c2'::uuid::bytea, 'base64') +decode('HqPWTLxATMOEu2sR7jHlwg==', 'base64')::uuid + + + See for how to generate a UUID in PostgreSQL. diff --git a/src/backend/utils/adt/bytea.c b/src/backend/utils/adt/bytea.c index fd7662d41ee..39ed04ddae8 100644 --- a/src/backend/utils/adt/bytea.c +++ b/src/backend/utils/adt/bytea.c @@ -28,6 +28,7 @@ #include "utils/guc.h" #include "utils/memutils.h" #include "utils/sortsupport.h" +#include "utils/uuid.h" #include "varatt.h" /* GUC variable */ @@ -1340,3 +1341,29 @@ int8_bytea(PG_FUNCTION_ARGS) { return int8send(fcinfo); } + +/* Cast bytea -> uuid */ +Datum +bytea_uuid(PG_FUNCTION_ARGS) +{ + bytea *v = PG_GETARG_BYTEA_PP(0); + int len = VARSIZE_ANY_EXHDR(v); + pg_uuid_t *uuid; + + if (len != UUID_LEN) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid input length for type %s", "uuid"), + errdetail("Expected %d bytes, got %d.", UUID_LEN, len))); + + uuid = palloc_object(pg_uuid_t); + memcpy(uuid->data, VARDATA_ANY(v), UUID_LEN); + PG_RETURN_UUID_P(uuid); +} + +/* Cast uuid -> bytea; can just use uuid_send() */ +Datum +uuid_bytea(PG_FUNCTION_ARGS) +{ + return uuid_send(fcinfo); +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 55a8fbbd509..fd8472cb5a5 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202603171 +#define CATALOG_VERSION_NO 202603191 #endif diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat index 9b1cfb1b590..a7b6d812c5a 100644 --- a/src/include/catalog/pg_cast.dat +++ b/src/include/catalog/pg_cast.dat @@ -362,6 +362,12 @@ { castsource => 'bytea', casttarget => 'int8', castfunc => 'int8(bytea)', castcontext => 'e', castmethod => 'f' }, +# Allow explicit coercions between bytea and uuid type +{ castsource => 'bytea', casttarget => 'uuid', castfunc => 'uuid(bytea)', + castcontext => 'e', castmethod => 'f' }, +{ castsource => 'uuid', casttarget => 'bytea', castfunc => 'bytea(uuid)', + castcontext => 'e', castmethod => 'f' }, + # Allow explicit coercions between int4 and "char" { castsource => 'char', casttarget => 'int4', castfunc => 'int4(char)', castcontext => 'e', castmethod => 'f' }, diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index fc8d82665b8..84e7adde0e5 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -1208,6 +1208,13 @@ proname => 'int8', prorettype => 'int8', proargtypes => 'bytea', prosrc => 'bytea_int8' }, +{ oid => '9880', descr => 'convert uuid to bytea', + proname => 'bytea', prorettype => 'bytea', proargtypes => 'uuid', + prosrc => 'uuid_bytea' }, +{ oid => '9881', descr => 'convert bytea to uuid', + proname => 'uuid', prorettype => 'uuid', proargtypes => 'bytea', + prosrc => 'bytea_uuid' }, + { oid => '449', descr => 'hash', proname => 'hashint2', prorettype => 'int4', proargtypes => 'int2', prosrc => 'hashint2' }, diff --git a/src/test/regress/expected/uuid.out b/src/test/regress/expected/uuid.out index 95392003b86..d157ef7d0b3 100644 --- a/src/test/regress/expected/uuid.out +++ b/src/test/regress/expected/uuid.out @@ -305,5 +305,27 @@ SELECT uuid_extract_timestamp('11111111-1111-1111-1111-111111111111'); -- null (1 row) +-- casts +SELECT '5b35380a-7143-4912-9b55-f322699c6770'::uuid::bytea; + bytea +------------------------------------ + \x5b35380a714349129b55f322699c6770 +(1 row) + +SELECT '\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid; + uuid +-------------------------------------- + 019a2f85-9ced-7225-b99d-9c55044a2563 +(1 row) + +SELECT '\x1234567890abcdef'::bytea::uuid; -- error +ERROR: invalid input length for type uuid +DETAIL: Expected 16 bytes, got 8. +SELECT v = v::bytea::uuid as matched FROM gen_random_uuid() v; + matched +--------- + t +(1 row) + -- clean up DROP TABLE guid1, guid2, guid3 CASCADE; diff --git a/src/test/regress/sql/uuid.sql b/src/test/regress/sql/uuid.sql index 465153a0341..f512f4dea1d 100644 --- a/src/test/regress/sql/uuid.sql +++ b/src/test/regress/sql/uuid.sql @@ -146,6 +146,11 @@ SELECT uuid_extract_timestamp('017F22E2-79B0-7CC3-98C4-DC0C0C07398F') = 'Tuesday SELECT uuid_extract_timestamp(gen_random_uuid()); -- null SELECT uuid_extract_timestamp('11111111-1111-1111-1111-111111111111'); -- null +-- casts +SELECT '5b35380a-7143-4912-9b55-f322699c6770'::uuid::bytea; +SELECT '\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid; +SELECT '\x1234567890abcdef'::bytea::uuid; -- error +SELECT v = v::bytea::uuid as matched FROM gen_random_uuid() v; -- clean up DROP TABLE guid1, guid2, guid3 CASCADE;