Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1vE59G-004RWp-BR for pgsql-hackers@arkaria.postgresql.org; Wed, 29 Oct 2025 12:19:31 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1vE59F-000nDu-97 for pgsql-hackers@arkaria.postgresql.org; Wed, 29 Oct 2025 12:19:28 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1vE59E-000nDl-P5 for pgsql-hackers@lists.postgresql.org; Wed, 29 Oct 2025 12:19:28 +0000 Received: from forwardcorp1d.mail.yandex.net ([2a02:6b8:c41:1300:1:45:d181:df01]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vE59B-004smt-0x for pgsql-hackers@postgresql.org; Wed, 29 Oct 2025 12:19:27 +0000 Received: from mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net [IPv6:2a02:6b8:c42:65a0:0:640:e1de:0]) by forwardcorp1d.mail.yandex.net (Yandex) with ESMTPS id DA76F81052; Wed, 29 Oct 2025 15:19:22 +0300 (MSK) Received: from smtpclient.apple (unknown [2a02:6bf:8080:65e::1:37]) by mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (smtpcorp/Yandex) with ESMTPSA id JJd4R20F0Cg0-iGZALnk0; Wed, 29 Oct 2025 15:19:21 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1761740362; bh=ZGhEXEAbNML3Eb6fRC4kVZ/Zfhg1UWwCR1MC2z5GpjI=; h=References:To:Cc:In-Reply-To:Date:From:Message-Id:Subject; b=a/qj3E1Bd7NieW/bFSBFMIU8FEUY8xJZt1xEscs5qBhYr7WnoyxBS9TgbwfBWAsqp CKOJeffMFtm8paaUOrtYMblRkOYvc0t09jSXhtmCtSDjAqikVyLOlkeeIKdW25xFJ1 qHAXrJ0yZMHQTz5KmAqoo9zWBl+Mmwgf0Gfyr9js= Authentication-Results: mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net; dkim=pass header.i=@yandex-team.ru From: Andrey Borodin Message-Id: <9CB824CC-70DC-4165-AC6A-9664F47209EE@yandex-team.ru> Content-Type: multipart/mixed; boundary="Apple-Mail=_034AAE3C-C436-4EBE-AC6E-F3C41A989FC1" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.700.81\)) Subject: Re: Add uuid_to_base32hex() and base32hex_to_uuid() built-in functions Date: Wed, 29 Oct 2025 16:19:08 +0400 In-Reply-To: Cc: =?utf-8?Q?Dagfinn_Ilmari_Manns=C3=A5ker?= , Jelte Fennema-Nio , Sergey Prokhorenko , pgsql-hackers To: Masahiko Sawada References: <1791665551.452444.1761209220211.ref@mail.yahoo.com> <1791665551.452444.1761209220211@mail.yahoo.com> <18022523-0F8F-4C07-AFF5-57DC9086D78E@yandex-team.ru> <1895971769.8343.1761240853939@mail.yahoo.com> <574624399.175025.1761290201491@mail.yahoo.com> <953203149.383019.1761345585325@mail.yahoo.com> <6F76FA61-E2DC-44EF-9504-889D9BDB4EBD@yandex-team.ru> <1154454839.957923.1761604611424@mail.yahoo.com> <87ldkv8cog.fsf@wibble.ilmari.org> <87ikfz7zcu.fsf@wibble.ilmari.org> X-Mailer: Apple Mail (2.3826.700.81) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_034AAE3C-C436-4EBE-AC6E-F3C41A989FC1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 28 Oct 2025, at 22:44, Masahiko Sawada = wrote: >=20 > Andrey has shared his patch for base32hex support before[1]. While it > needs to be updated, it seems to implement sufficient function. I'd propose something like attached patch. It's on top of Ilmari's v2 = patch with small suggestions as a step 2. Thanks! Best regards, Andrey Borodin. --Apple-Mail=_034AAE3C-C436-4EBE-AC6E-F3C41A989FC1 Content-Disposition: attachment; filename=v3-0001-Allow-explicit-casting-between-bytea-and-UUID.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v3-0001-Allow-explicit-casting-between-bytea-and-UUID.patch" Content-Transfer-Encoding: quoted-printable =46rom=20cf475ec8632720a629afaab264106a952c625b80=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20=3D?UTF-8?q?Dagfinn=3D20Ilmari=3D20Manns=3DC3=3D= A5ker?=3D=20=0ADate:=20Tue,=2028=20Oct=202025=20= 16:33:17=20+0000=0ASubject:=20[PATCH=20v3=201/3]=20Allow=20explicit=20= casting=20between=20bytea=20and=20UUID=0A=0AThis=20enables=20using=20= encode()=20and=20decode()=20to=20convert=20UUIDs=20to=20and=20from=0A= alternative=20formats,=20such=20as=20base64.=0A---=0A=20= src/backend/utils/adt/bytea.c=20=20=20=20=20=20|=2026=20= ++++++++++++++++++++++++++=0A=20src/include/catalog/pg_cast.dat=20=20=20=20= |=20=206=20++++++=0A=20src/include/catalog/pg_proc.dat=20=20=20=20|=20=20= 7=20+++++++=0A=20src/test/regress/expected/uuid.out=20|=2015=20= +++++++++++++++=0A=20src/test/regress/sql/uuid.sql=20=20=20=20=20=20|=20=20= 4=20++++=0A=205=20files=20changed,=2058=20insertions(+)=0A=0Adiff=20= --git=20a/src/backend/utils/adt/bytea.c=20= b/src/backend/utils/adt/bytea.c=0Aindex=206e7b914c563..ff9e46f3015=20= 100644=0A---=20a/src/backend/utils/adt/bytea.c=0A+++=20= b/src/backend/utils/adt/bytea.c=0A@@=20-26,6=20+26,7=20@@=0A=20#include=20= "utils/fmgrprotos.h"=0A=20#include=20"utils/memutils.h"=0A=20#include=20= "utils/sortsupport.h"=0A+#include=20"utils/uuid.h"=0A=20#include=20= "utils/varlena.h"=0A=20#include=20"varatt.h"=0A=20=0A@@=20-1112,3=20= +1113,28=20@@=20int8_bytea(PG_FUNCTION_ARGS)=0A=20{=0A=20=09return=20= int8send(fcinfo);=0A=20}=0A+=0A+/*=20Cast=20bytea=20->=20uuid=20*/=0A= +Datum=0A+bytea_uuid(PG_FUNCTION_ARGS)=0A+{=0A+=09bytea=09=20=20=20*v=20= =3D=20PG_GETARG_BYTEA_PP(0);=0A+=09int=09=09=09len=20=3D=20= VARSIZE_ANY_EXHDR(v);=0A+=09pg_uuid_t=20=20*uuid;=0A+=0A+=09if=20(len=20= !=3D=20UUID_LEN)=0A+=09=09ereport(ERROR,=0A+=09=09=09=09= errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),=0A+=09=09=09=09= errmsg("invalid=20uuid=20length"));=0A+=0A+=09uuid=20=3D=20(pg_uuid_t=20= *)=20palloc(UUID_LEN);=0A+=09memcpy(uuid->data,=20VARDATA_ANY(v),=20= UUID_LEN);=0A+=09PG_RETURN_POINTER(uuid);=0A+}=0A+=0A+/*=20Cast=20uuid=20= ->=20bytea;=20can=20just=20use=20uuid_send()=20*/=0A+Datum=0A= +uuid_bytea(PG_FUNCTION_ARGS)=0A+{=0A+=09return=20uuid_send(fcinfo);=0A= +}=0Adiff=20--git=20a/src/include/catalog/pg_cast.dat=20= b/src/include/catalog/pg_cast.dat=0Aindex=20fbfd669587f..913c55ef869=20= 100644=0A---=20a/src/include/catalog/pg_cast.dat=0A+++=20= b/src/include/catalog/pg_cast.dat=0A@@=20-348,6=20+348,12=20@@=0A=20{=20= castsource=20=3D>=20'bytea',=20casttarget=20=3D>=20'int8',=20castfunc=20= =3D>=20'int8(bytea)',=0A=20=20=20castcontext=20=3D>=20'e',=20castmethod=20= =3D>=20'f'=20},=0A=20=0A+#=20Allow=20explicit=20coercions=20between=20= bytea=20and=20uuid=20type=0A+{=20castsource=20=3D>=20'bytea',=20= casttarget=20=3D>=20'uuid',=20castfunc=20=3D>=20'uuid(bytea)',=0A+=20=20= castcontext=20=3D>=20'e',=20castmethod=20=3D>=20'f'=20},=0A+{=20= castsource=20=3D>=20'uuid',=20casttarget=20=3D>=20'bytea',=20castfunc=20= =3D>=20'bytea(uuid)',=0A+=20=20castcontext=20=3D>=20'e',=20castmethod=20= =3D>=20'f'=20},=0A+=0A=20#=20Allow=20explicit=20coercions=20between=20= int4=20and=20"char"=0A=20{=20castsource=20=3D>=20'char',=20casttarget=20= =3D>=20'int4',=20castfunc=20=3D>=20'int4(char)',=0A=20=20=20castcontext=20= =3D>=20'e',=20castmethod=20=3D>=20'f'=20},=0Adiff=20--git=20= a/src/include/catalog/pg_proc.dat=20b/src/include/catalog/pg_proc.dat=0A= index=20b51d2b17379..afcc9a3476a=20100644=0A---=20= a/src/include/catalog/pg_proc.dat=0A+++=20= b/src/include/catalog/pg_proc.dat=0A@@=20-1199,6=20+1199,13=20@@=0A=20=20= =20proname=20=3D>=20'int8',=20prorettype=20=3D>=20'int8',=20proargtypes=20= =3D>=20'bytea',=0A=20=20=20prosrc=20=3D>=20'bytea_int8'=20},=0A=20=0A+{=20= oid=20=3D>=20'9880',=20descr=20=3D>=20'convert=20uuid=20to=20bytea',=0A+=20= =20proname=20=3D>=20'bytea',=20prorettype=20=3D>=20'bytea',=20= proargtypes=20=3D>=20'uuid',=0A+=20=20prosrc=20=3D>=20'uuid_bytea'=20},=0A= +{=20oid=20=3D>=20'9881',=20descr=20=3D>=20'convert=20bytea=20to=20= uuid',=0A+=20=20proname=20=3D>=20'uuid',=20prorettype=20=3D>=20'uuid',=20= proargtypes=20=3D>=20'bytea',=0A+=20=20prosrc=20=3D>=20'bytea_uuid'=20},=0A= +=0A=20{=20oid=20=3D>=20'449',=20descr=20=3D>=20'hash',=0A=20=20=20= proname=20=3D>=20'hashint2',=20prorettype=20=3D>=20'int4',=20proargtypes=20= =3D>=20'int2',=0A=20=20=20prosrc=20=3D>=20'hashint2'=20},=0Adiff=20--git=20= a/src/test/regress/expected/uuid.out=20= b/src/test/regress/expected/uuid.out=0Aindex=2095392003b86..4b635336606=20= 100644=0A---=20a/src/test/regress/expected/uuid.out=0A+++=20= b/src/test/regress/expected/uuid.out=0A@@=20-305,5=20+305,20=20@@=20= SELECT=20uuid_extract_timestamp('11111111-1111-1111-1111-111111111111');=20= =20--=20null=0A=20=20=0A=20(1=20row)=0A=20=0A+--=20casts=0A+SELECT=20= '5b35380a-7143-4912-9b55-f322699c6770'::uuid::bytea;=0A+=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20bytea=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=0A+------------------------------------=0A+=20= \x5b35380a714349129b55f322699c6770=0A+(1=20row)=0A+=0A+SELECT=20= '\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid;=0A+=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20uuid=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=0A+--------------------------------------=0A+=20= 019a2f85-9ced-7225-b99d-9c55044a2563=0A+(1=20row)=0A+=0A+SELECT=20= '\x1234567890abcdef'::bytea::uuid;=20--=20error=0A+ERROR:=20=20invalid=20= uuid=20length=0A=20--=20clean=20up=0A=20DROP=20TABLE=20guid1,=20guid2,=20= guid3=20CASCADE;=0Adiff=20--git=20a/src/test/regress/sql/uuid.sql=20= b/src/test/regress/sql/uuid.sql=0Aindex=20465153a0341..63520d0b640=20= 100644=0A---=20a/src/test/regress/sql/uuid.sql=0A+++=20= b/src/test/regress/sql/uuid.sql=0A@@=20-146,6=20+146,10=20@@=20SELECT=20= uuid_extract_timestamp('017F22E2-79B0-7CC3-98C4-DC0C0C07398F')=20=3D=20= 'Tuesday=0A=20SELECT=20uuid_extract_timestamp(gen_random_uuid());=20=20= --=20null=0A=20SELECT=20= uuid_extract_timestamp('11111111-1111-1111-1111-111111111111');=20=20--=20= null=0A=20=0A+--=20casts=0A+SELECT=20= '5b35380a-7143-4912-9b55-f322699c6770'::uuid::bytea;=0A+SELECT=20= '\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid;=0A+SELECT=20= '\x1234567890abcdef'::bytea::uuid;=20--=20error=0A=20=0A=20--=20clean=20= up=0A=20DROP=20TABLE=20guid1,=20guid2,=20guid3=20CASCADE;=0A--=20=0A= 2.39.5=20(Apple=20Git-154)=0A=0A= --Apple-Mail=_034AAE3C-C436-4EBE-AC6E-F3C41A989FC1 Content-Disposition: attachment; filename=v3-0003-Add-base32hex-encoding-support-to-encode-and-deco.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v3-0003-Add-base32hex-encoding-support-to-encode-and-deco.patch" Content-Transfer-Encoding: quoted-printable =46rom=2076a13f46fb07903d67f980b552346ebe6b3a8fe2=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Andrey=20Borodin=20=0ADate:=20= Wed,=2029=20Oct=202025=2015:53:12=20+0400=0ASubject:=20[PATCH=20v3=20= 3/3]=20Add=20base32hex=20encoding=20support=20to=20encode()=20and=0A=20= decode()=0A=0AImplement=20base32hex=20encoding/decoding=20per=20RFC=20= 4648=20Section=207=20for=0Aencode()=20and=20decode()=20functions.=20This=20= encoding=20uses=20the=20extended=20hex=0Aalphabet=20(0-9,=20A-V)=20which=20= preserves=20sort=20order.=0A=0AThe=20encode()=20function=20produces=20= unpadded=20output,=20while=20decode()=20accepts=0Aboth=20padded=20and=20= unpadded=20input.=20Decoding=20is=20case-insensitive.=0A=0AThis=20is=20= particularly=20useful=20for=20encoding=20UUIDs=20compactly:=0A=20=20=20=20= SELECT=20encode(uuid_value::bytea,=20'base32hex');=0Aproduces=20a=20= 26-character=20string=20compared=20to=20the=20standard=2036-character=0A= UUID=20representation.=0A=0ASuggested-by:=20Sergey=20= Prokhorenko=0A---=0A=20= doc/src/sgml/func/func-binarystring.sgml=20|=20=2025=20+++++=0A=20= src/backend/utils/adt/encode.c=20=20=20=20=20=20=20=20=20=20=20|=20124=20= +++++++++++++++++++++++=0A=20src/test/regress/expected/uuid.out=20=20=20=20= =20=20=20|=20=2088=20++++++++++++++++=0A=20src/test/regress/sql/uuid.sql=20= =20=20=20=20=20=20=20=20=20=20=20|=20=2027=20+++++=0A=204=20files=20= changed,=20264=20insertions(+)=0A=0Adiff=20--git=20= a/doc/src/sgml/func/func-binarystring.sgml=20= b/doc/src/sgml/func/func-binarystring.sgml=0Aindex=20= dd7037811af..4659ad49787=20100644=0A---=20= a/doc/src/sgml/func/func-binarystring.sgml=0A+++=20= b/doc/src/sgml/func/func-binarystring.sgml=0A@@=20-729,6=20+729,7=20@@=0A= =20=20=20=20=20=20=20=20format=20values=20are:=0A=20= =20=20=20=20=20=20=20base64,=0A=20=20= =20=20=20=20=20=20base64url,=0A= +=20=20=20=20=20=20=20base32hex,=0A= =20=20=20=20=20=20=20=20escape,=0A=20=20= =20=20=20=20=20=20hex.=0A=20=20=20=20= =20=20=20=0A@@=20-804,6=20+805,30=20@@=0A=20=20=20=20=20=20= =0A=20=20=20=20=20=0A=20=0A+=20=20=20=20= =0A+=20=20=20=20=20= base32hex=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= base32hex=20format=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20The=20base32hex=20= format=20is=20that=20of=0A+=20=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=20RFC=204648=20Section=207.=20=20It=20uses=20the=20= extended=20hex=20alphabet=0A+=20=20=20=20=20=20=20(0-9,=20A-V)=20which=20= preserves=20sort=20order=20when=20encoding=20binary=20data.=0A+=20=20=20=20= =20=20=20The=20encode=20function=20produces=20= unpadded=20output,=0A+=20=20=20=20=20=20=20while=20= decode=20accepts=20both=20padded=20and=20unpadded=0A= +=20=20=20=20=20=20=20input.=20Decoding=20is=20case-insensitive=20and=20= ignores=20whitespace=20characters.=0A+=20=20=20=20=20=20=0A+=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20This=20format=20is=20= particularly=20useful=20for=20encoding=20UUIDs=20in=20a=20compact,=0A+=20= =20=20=20=20=20=20sortable=20format:=20= encode(uuid_value::bytea,=20'base32hex')=0A+=20=20=20=20= =20=20=20produces=20a=2026-character=20string=20compared=20to=20the=20= standard=2036-character=0A+=20=20=20=20=20=20=20UUID=20representation.=0A= +=20=20=20=20=20=20=0A+=20=20=20=20=20=0A+=20=20=20=20= =0A+=0A=20=20=20=20=20=0A=20=20=20=20=20=20escape=0A=20=20=20= =20=20=20=0Adiff=20--git=20a/src/backend/utils/adt/encode.c=20= b/src/backend/utils/adt/encode.c=0Aindex=20aabe9913eee..c31ab60d4b7=20= 100644=0A---=20a/src/backend/utils/adt/encode.c=0A+++=20= b/src/backend/utils/adt/encode.c=0A@@=20-821,6=20+821,124=20@@=20= esc_dec_len(const=20char=20*src,=20size_t=20srclen)=0A=20=09return=20= len;=0A=20}=0A=20=0A+/*=0A+=20*=20BASE32HEX=0A+=20*/=0A+=0A+static=20= const=20char=20base32hex_table[]=20=3D=20= "0123456789ABCDEFGHIJKLMNOPQRSTUV";=0A+=0A+static=20uint64=0A= +base32hex_enc_len(const=20char=20*src,=20size_t=20srclen)=0A+{=0A+=09/*=20= 5=20bits=20per=20base32hex=20character,=20so=20round=20up=20(srclen=20*=20= 8=20+=204)=20/=205=20*/=0A+=09return=20((uint64)=20srclen=20*=208=20+=20= 4)=20/=205;=0A+}=0A+=0A+static=20uint64=0A+base32hex_dec_len(const=20= char=20*src,=20size_t=20srclen)=0A+{=0A+=09/*=20Decode=20length=20is=20= (srclen=20*=205)=20/=208,=20but=20we=20may=20have=20padding=20*/=0A+=09= return=20((uint64)=20srclen=20*=205)=20/=208;=0A+}=0A+=0A+static=20= uint64=0A+base32hex_encode(const=20char=20*src,=20size_t=20srclen,=20= char=20*dst)=0A+{=0A+=09const=20unsigned=20char=20*data=20=3D=20(const=20= unsigned=20char=20*)=20src;=0A+=09uint64=09=09bits_buffer=20=3D=200;=0A+=09= int=09=09=09bits_in_buffer=20=3D=200;=0A+=09uint64=09=09output_pos=20=3D=20= 0;=0A+=09size_t=09=09i;=0A+=0A+=09for=20(i=20=3D=200;=20i=20<=20srclen;=20= i++)=0A+=09{=0A+=09=09/*=20Add=208=20bits=20to=20the=20buffer=20*/=0A+=09= =09bits_buffer=20=3D=20(bits_buffer=20<<=208)=20|=20data[i];=0A+=09=09= bits_in_buffer=20+=3D=208;=0A+=0A+=09=09/*=20Extract=205-bit=20chunks=20= while=20we=20have=20enough=20bits=20*/=0A+=09=09while=20(bits_in_buffer=20= >=3D=205)=0A+=09=09{=0A+=09=09=09bits_in_buffer=20-=3D=205;=0A+=09=09=09= /*=20Extract=20top=205=20bits=20*/=0A+=09=09=09dst[output_pos++]=20=3D=20= base32hex_table[(bits_buffer=20>>=20bits_in_buffer)=20&=200x1F];=0A+=09=09= =09/*=20Clear=20the=20extracted=20bits=20by=20masking=20*/=0A+=09=09=09= bits_buffer=20&=3D=20((1ULL=20<<=20bits_in_buffer)=20-=201);=0A+=09=09}=0A= +=09}=0A+=0A+=09/*=20Handle=20remaining=20bits=20(if=20any)=20*/=0A+=09= if=20(bits_in_buffer=20>=200)=0A+=09{=0A+=09=09dst[output_pos++]=20=3D=20= base32hex_table[(bits_buffer=20<<=20(5=20-=20bits_in_buffer))=20&=20= 0x1F];=0A+=09}=0A+=0A+=09return=20output_pos;=0A+}=0A+=0A+static=20= uint64=0A+base32hex_decode(const=20char=20*src,=20size_t=20srclen,=20= char=20*dst)=0A+{=0A+=09const=20unsigned=20char=20*data=20=3D=20(const=20= unsigned=20char=20*)=20src;=0A+=09uint64=09=09bits_buffer=20=3D=200;=0A+=09= int=09=09=09bits_in_buffer=20=3D=200;=0A+=09uint64=09=09output_pos=20=3D=20= 0;=0A+=09size_t=09=09i;=0A+=09size_t=09=09decode_len=20=3D=20srclen;=0A+=0A= +=09/*=0A+=09=20*=20RFC=204648=20allows=20padding=20with=20'=3D'=20to=20= make=20the=20length=20a=20multiple=20of=208.=0A+=09=20*=20Count=20and=20= skip=20trailing=20padding=20characters.=0A+=09=20*/=0A+=09while=20= (decode_len=20>=200=20&&=20data[decode_len=20-=201]=20=3D=3D=20'=3D')=0A= +=09=09decode_len--;=0A+=0A+=09for=20(i=20=3D=200;=20i=20<=20decode_len;=20= i++)=0A+=09{=0A+=09=09unsigned=20char=20c=20=3D=20data[i];=0A+=09=09int=09= =09=09val;=0A+=0A+=09=09/*=20Skip=20whitespace=20*/=0A+=09=09if=20(c=20= =3D=3D=20'=20'=20||=20c=20=3D=3D=20'\t'=20||=20c=20=3D=3D=20'\n'=20||=20= c=20=3D=3D=20'\r')=0A+=09=09=09continue;=0A+=0A+=09=09/*=20Decode=20= base32hex=20character=20(0-9,=20A-V,=20case-insensitive)=20*/=0A+=09=09= if=20(c=20>=3D=20'0'=20&&=20c=20<=3D=20'9')=0A+=09=09=09val=20=3D=20c=20= -=20'0';=0A+=09=09else=20if=20(c=20>=3D=20'A'=20&&=20c=20<=3D=20'V')=0A+=09= =09=09val=20=3D=20c=20-=20'A'=20+=2010;=0A+=09=09else=20if=20(c=20>=3D=20= 'a'=20&&=20c=20<=3D=20'v')=0A+=09=09=09val=20=3D=20c=20-=20'a'=20+=2010;=0A= +=09=09else=0A+=09=09=09ereport(ERROR,=0A+=09=09=09=09=09= (errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A+=09=09=09=09=09=20= errmsg("invalid=20symbol=20\"%.*s\"=20found=20while=20decoding=20= base32hex=20sequence",=0A+=09=09=09=09=09=09=09pg_mblen((const=20char=20= *)=20&c),=20(const=20char=20*)=20&c)));=0A+=0A+=09=09/*=20Add=205=20bits=20= to=20buffer=20*/=0A+=09=09bits_buffer=20=3D=20(bits_buffer=20<<=205)=20|=20= val;=0A+=09=09bits_in_buffer=20+=3D=205;=0A+=0A+=09=09/*=20Extract=20= 8-bit=20bytes=20when=20we=20have=20enough=20bits=20*/=0A+=09=09while=20= (bits_in_buffer=20>=3D=208)=0A+=09=09{=0A+=09=09=09bits_in_buffer=20-=3D=20= 8;=0A+=09=09=09dst[output_pos++]=20=3D=20(unsigned=20char)=20= (bits_buffer=20>>=20bits_in_buffer);=0A+=09=09=09/*=20Clear=20the=20= extracted=20bits=20*/=0A+=09=09=09bits_buffer=20&=3D=20((1ULL=20<<=20= bits_in_buffer)=20-=201);=0A+=09=09}=0A+=09}=0A+=0A+=09/*=20Verify=20no=20= extra=20bits=20remain=20(padding=20bits=20should=20be=20zero)=20*/=0A+=09= if=20(bits_in_buffer=20>=200=20&&=20(bits_buffer=20&=20((1ULL=20<<=20= bits_in_buffer)=20-=201))=20!=3D=200)=0A+=09=09ereport(ERROR,=0A+=09=09=09= =09(errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A+=09=09=09=09=20= errmsg("invalid=20base32hex=20end=20sequence"),=0A+=09=09=09=09=20= errhint("Input=20data=20has=20non-zero=20padding=20bits.")));=0A+=0A+=09= return=20output_pos;=0A+}=0A+=0A=20/*=0A=20=20*=20Common=0A=20=20*/=0A@@=20= -850,6=20+968,12=20@@=20static=20const=20struct=0A=20=09=09=09= pg_base64url_enc_len,=20pg_base64url_dec_len,=20pg_base64url_encode,=20= pg_base64url_decode=0A=20=09=09}=0A=20=09},=0A+=09{=0A+=09=09= "base32hex",=0A+=09=09{=0A+=09=09=09base32hex_enc_len,=20= base32hex_dec_len,=20base32hex_encode,=20base32hex_decode=0A+=09=09}=0A+=09= },=0A=20=09{=0A=20=09=09"escape",=0A=20=09=09{=0Adiff=20--git=20= a/src/test/regress/expected/uuid.out=20= b/src/test/regress/expected/uuid.out=0Aindex=2024486084aaf..86d21a29093=20= 100644=0A---=20a/src/test/regress/expected/uuid.out=0A+++=20= b/src/test/regress/expected/uuid.out=0A@@=20-321,5=20+321,93=20@@=20= SELECT=20'\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid;=0A=20SELECT=20= '\x1234567890abcdef'::bytea::uuid;=20--=20error=0A=20ERROR:=20=20invalid=20= length=20for=20UUID=0A=20DETAIL:=20=20Expected=2016=20bytes,=20got=208.=0A= +--=20base32hex=20encoding=20via=20encode/decode=0A+SELECT=20= encode('00000000-0000-0000-0000-000000000000'::uuid::bytea,=20= 'base32hex');=0A+=20=20=20=20=20=20=20=20=20=20=20encode=20=20=20=20=20=20= =20=20=20=20=20=0A+----------------------------=0A+=20= 00000000000000000000000000=0A+(1=20row)=0A+=0A+SELECT=20= encode('11111111-1111-1111-1111-111111111111'::uuid::bytea,=20= 'base32hex');=0A+=20=20=20=20=20=20=20=20=20=20=20encode=20=20=20=20=20=20= =20=20=20=20=20=0A+----------------------------=0A+=20= 248H248H248H248H248H248H24=0A+(1=20row)=0A+=0A+SELECT=20= encode('ffffffff-ffff-ffff-ffff-ffffffffffff'::uuid::bytea,=20= 'base32hex');=0A+=20=20=20=20=20=20=20=20=20=20=20encode=20=20=20=20=20=20= =20=20=20=20=20=0A+----------------------------=0A+=20= VVVVVVVVVVVVVVVVVVVVVVVVVS=0A+(1=20row)=0A+=0A+SELECT=20= encode('123e4567-e89b-12d3-a456-426614174000'::uuid::bytea,=20= 'base32hex');=0A+=20=20=20=20=20=20=20=20=20=20=20encode=20=20=20=20=20=20= =20=20=20=20=20=0A+----------------------------=0A+=20= 28V4APV8JC9D792M89J185Q000=0A+(1=20row)=0A+=0A+--=20test=20decode=20with=20= base32hex=0A+SELECT=20decode('00000000000000000000000000',=20= 'base32hex')::uuid;=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= decode=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=0A= +--------------------------------------=0A+=20= 00000000-0000-0000-0000-000000000000=0A+(1=20row)=0A+=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q000',=20'base32hex')::uuid;=0A+=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20decode=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=0A+--------------------------------------=0A+=20= 123e4567-e89b-12d3-a456-426614174000=0A+(1=20row)=0A+=0A+--=20test=20= round-trip=20conversions=0A+SELECT=20= decode(encode('00000000-0000-0000-0000-000000000000'::uuid::bytea,=20= 'base32hex'),=20'base32hex')::uuid;=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20decode=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=0A= +--------------------------------------=0A+=20= 00000000-0000-0000-0000-000000000000=0A+(1=20row)=0A+=0A+SELECT=20= encode(decode('28V4APV8JC9D792M89J185Q000',=20'base32hex')::uuid::bytea,=20= 'base32hex');=0A+=20=20=20=20=20=20=20=20=20=20=20encode=20=20=20=20=20=20= =20=20=20=20=20=0A+----------------------------=0A+=20= 28V4APV8JC9D792M89J185Q000=0A+(1=20row)=0A+=0A+SELECT=20= decode(encode('123e4567-e89b-12d3-a456-426614174000'::uuid::bytea,=20= 'base32hex'),=20'base32hex')::uuid;=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20decode=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=0A= +--------------------------------------=0A+=20= 123e4567-e89b-12d3-a456-426614174000=0A+(1=20row)=0A+=0A+--=20test=20= case=20insensitivity=0A+SELECT=20decode('28v4apv8jc9d792m89j185q000',=20= 'base32hex')::uuid;=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= decode=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=0A= +--------------------------------------=0A+=20= 123e4567-e89b-12d3-a456-426614174000=0A+(1=20row)=0A+=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q000',=20'base32hex')::uuid;=0A+=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20decode=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=0A+--------------------------------------=0A+=20= 123e4567-e89b-12d3-a456-426614174000=0A+(1=20row)=0A+=0A+--=20test=20RFC=20= 4648=20padding=20(32=20chars=20with=206=20'=3D'=20signs)=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q000=3D=3D=3D=3D=3D=3D',=20= 'base32hex')::uuid;=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= decode=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=0A= +--------------------------------------=0A+=20= 123e4567-e89b-12d3-a456-426614174000=0A+(1=20row)=0A+=0A+SELECT=20= decode('00000000000000000000000000=3D=3D=3D=3D=3D=3D',=20= 'base32hex')::uuid;=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= decode=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=0A= +--------------------------------------=0A+=20= 00000000-0000-0000-0000-000000000000=0A+(1=20row)=0A+=0A+--=20test=20= error=20cases=20for=20base32hex=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q00W',=20'base32hex')::uuid;=20=20--=20= invalid=20character=20W=0A+ERROR:=20=20invalid=20symbol=20"W"=20found=20= while=20decoding=20base32hex=20sequence=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q00!',=20'base32hex')::uuid;=20=20--=20= invalid=20character=20!=0A+ERROR:=20=20invalid=20symbol=20"!"=20found=20= while=20decoding=20base32hex=20sequence=0A=20--=20clean=20up=0A=20DROP=20= TABLE=20guid1,=20guid2,=20guid3=20CASCADE;=0Adiff=20--git=20= a/src/test/regress/sql/uuid.sql=20b/src/test/regress/sql/uuid.sql=0A= index=2063520d0b640..44e8fa8b243=20100644=0A---=20= a/src/test/regress/sql/uuid.sql=0A+++=20b/src/test/regress/sql/uuid.sql=0A= @@=20-151,5=20+151,32=20@@=20SELECT=20= '5b35380a-7143-4912-9b55-f322699c6770'::uuid::bytea;=0A=20SELECT=20= '\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid;=0A=20SELECT=20= '\x1234567890abcdef'::bytea::uuid;=20--=20error=0A=20=0A+--=20base32hex=20= encoding=20via=20encode/decode=0A+SELECT=20= encode('00000000-0000-0000-0000-000000000000'::uuid::bytea,=20= 'base32hex');=0A+SELECT=20= encode('11111111-1111-1111-1111-111111111111'::uuid::bytea,=20= 'base32hex');=0A+SELECT=20= encode('ffffffff-ffff-ffff-ffff-ffffffffffff'::uuid::bytea,=20= 'base32hex');=0A+SELECT=20= encode('123e4567-e89b-12d3-a456-426614174000'::uuid::bytea,=20= 'base32hex');=0A+=0A+--=20test=20decode=20with=20base32hex=0A+SELECT=20= decode('00000000000000000000000000',=20'base32hex')::uuid;=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q000',=20'base32hex')::uuid;=0A+=0A+--=20= test=20round-trip=20conversions=0A+SELECT=20= decode(encode('00000000-0000-0000-0000-000000000000'::uuid::bytea,=20= 'base32hex'),=20'base32hex')::uuid;=0A+SELECT=20= encode(decode('28V4APV8JC9D792M89J185Q000',=20'base32hex')::uuid::bytea,=20= 'base32hex');=0A+SELECT=20= decode(encode('123e4567-e89b-12d3-a456-426614174000'::uuid::bytea,=20= 'base32hex'),=20'base32hex')::uuid;=0A+=0A+--=20test=20case=20= insensitivity=0A+SELECT=20decode('28v4apv8jc9d792m89j185q000',=20= 'base32hex')::uuid;=0A+SELECT=20decode('28V4APV8JC9D792M89J185Q000',=20= 'base32hex')::uuid;=0A+=0A+--=20test=20RFC=204648=20padding=20(32=20= chars=20with=206=20'=3D'=20signs)=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q000=3D=3D=3D=3D=3D=3D',=20= 'base32hex')::uuid;=0A+SELECT=20= decode('00000000000000000000000000=3D=3D=3D=3D=3D=3D',=20= 'base32hex')::uuid;=0A+=0A+--=20test=20error=20cases=20for=20base32hex=0A= +SELECT=20decode('28V4APV8JC9D792M89J185Q00W',=20'base32hex')::uuid;=20=20= --=20invalid=20character=20W=0A+SELECT=20= decode('28V4APV8JC9D792M89J185Q00!',=20'base32hex')::uuid;=20=20--=20= invalid=20character=20!=0A+=0A=20--=20clean=20up=0A=20DROP=20TABLE=20= guid1,=20guid2,=20guid3=20CASCADE;=0A--=20=0A2.39.5=20(Apple=20Git-154)=0A= =0A= --Apple-Mail=_034AAE3C-C436-4EBE-AC6E-F3C41A989FC1 Content-Disposition: attachment; filename=v3-0002-Minor-suggestions-to-Ilmari-s-patch.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v3-0002-Minor-suggestions-to-Ilmari-s-patch.patch" Content-Transfer-Encoding: quoted-printable =46rom=20d73e7c1cd31f5036a847b8a6bc3823a01cac5a77=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Andrey=20Borodin=20=0ADate:=20= Wed,=2029=20Oct=202025=2015:59:46=20+0400=0ASubject:=20[PATCH=20v3=20= 2/3]=20Minor=20suggestions=20to=20Ilmari's=20patch=0A=0A---=0A=20= src/backend/utils/adt/bytea.c=20=20=20=20=20=20|=209=20+++++----=0A=20= src/test/regress/expected/uuid.out=20|=203=20++-=0A=202=20files=20= changed,=207=20insertions(+),=205=20deletions(-)=0A=0Adiff=20--git=20= a/src/backend/utils/adt/bytea.c=20b/src/backend/utils/adt/bytea.c=0A= index=20ff9e46f3015..14e95031be1=20100644=0A---=20= a/src/backend/utils/adt/bytea.c=0A+++=20b/src/backend/utils/adt/bytea.c=0A= @@=20-1124,12=20+1124,13=20@@=20bytea_uuid(PG_FUNCTION_ARGS)=0A=20=0A=20=09= if=20(len=20!=3D=20UUID_LEN)=0A=20=09=09ereport(ERROR,=0A-=09=09=09=09= errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),=0A-=09=09=09=09= errmsg("invalid=20uuid=20length"));=0A+=09=09=09=09= (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),=0A+=09=09=09=09=20= errmsg("invalid=20length=20for=20UUID"),=0A+=09=09=09=09=20= errdetail("Expected=20%d=20bytes,=20got=20%d.",=20UUID_LEN,=20len)));=0A=20= =0A-=09uuid=20=3D=20(pg_uuid_t=20*)=20palloc(UUID_LEN);=0A+=09uuid=20=3D=20= (pg_uuid_t=20*)=20palloc(sizeof(pg_uuid_t));=0A=20=09memcpy(uuid->data,=20= VARDATA_ANY(v),=20UUID_LEN);=0A-=09PG_RETURN_POINTER(uuid);=0A+=09= PG_RETURN_UUID_P(uuid);=0A=20}=0A=20=0A=20/*=20Cast=20uuid=20->=20bytea;=20= can=20just=20use=20uuid_send()=20*/=0Adiff=20--git=20= a/src/test/regress/expected/uuid.out=20= b/src/test/regress/expected/uuid.out=0Aindex=204b635336606..24486084aaf=20= 100644=0A---=20a/src/test/regress/expected/uuid.out=0A+++=20= b/src/test/regress/expected/uuid.out=0A@@=20-319,6=20+319,7=20@@=20= SELECT=20'\x019a2f859ced7225b99d9c55044a2563'::bytea::uuid;=0A=20(1=20= row)=0A=20=0A=20SELECT=20'\x1234567890abcdef'::bytea::uuid;=20--=20error=0A= -ERROR:=20=20invalid=20uuid=20length=0A+ERROR:=20=20invalid=20length=20= for=20UUID=0A+DETAIL:=20=20Expected=2016=20bytes,=20got=208.=0A=20--=20= clean=20up=0A=20DROP=20TABLE=20guid1,=20guid2,=20guid3=20CASCADE;=0A--=20= =0A2.39.5=20(Apple=20Git-154)=0A=0A= --Apple-Mail=_034AAE3C-C436-4EBE-AC6E-F3C41A989FC1--