更新:请参见问题的编辑,这个答案适用于普通的16字节uuid序列化;问题已经修改以反映java序列化。
有趣的问题。我最终编写了一个简单的C扩展来高效地解决它,但使用下面的PL/Python版本可能更明智。
由于uuid
是一个固定大小的类型,而bytea
是varlena
,所以你不能只是create cast ... as implicit
将它们二进制强制转换,因为变长字段头会妨碍这一过程。
没有内置函数可以将bytea输入返回为uuid。这将是一个方便的功能,但我不认为有人已经做到了。
最简单的方法
更新:实际上有一种简单的方法可以做到这一点。一旦去掉\x
,bytea
的十六进制形式实际上是一个有效的uuid文本,因为uuid_in
接受没有-
或{}
的纯十六进制形式。因此,只需:
regress=> SET bytea_output = 'hex';
SET
regress=> SELECT CAST( substring(CAST (BYTEA '\x0FCC6350118D11E4A5597DE5338EB025' AS text) from 3) AS uuid);
substring
0fcc6350-118d-11e4-a559-7de5338eb025
(1 row)
涉及一些字符串复制和十六进制编码/解码循环,但这比我之前建议的任何PL答案都要快得多,但比C慢。
其他选项
个人建议使用PL/Perl或pl/pythonu。我将用一个例子跟进。
假设您的uuid是十六进制格式的bytea文字:
'\x0FCC6350118D11E4A5597DE5338EB025'
您可以使用以下方法将其转换为
uuid
类型:
PL/Perl
create language plperlu;
create or replace function to_uuid(bytea) returns uuid language plperlu immutable as $$
use Data::UUID;
my $ug = new Data::UUID;
my $uuid = $ug->from_hexstring(substr($_[0],2));
return $ug->to_string($uuid);
$$
SET bytea_output = hex;
SELECT to_uuid(BYTEA '\x0FCC6350118D11E4A5597DE5338EB025');
PL/Python
在 PL/Python 中,由于 PL/Python 接口将 bytea
作为原始字节而不是十六进制字符串传递,因此使用 Python 可能更快且更清晰:
CREATE LANGUAGE plpythonu;
CREATE or replace function to_uuid(uuidbytes bytea)
RETURNS uuid LANGUAGE plpythonu IMMUTABLE
AS $$
import uuid
return uuid.UUID(bytes=uuidbytes)
$$;
SELECT to_uuid(BYTEA '\x0FCC6350118D11E4A5597DE5338EB025');
在C语言中,仅是为了好玩。丑陋的hack。
您可以查看此处的C扩展模块。
但实际上,我说它很丑陋是认真的。如果想要在C中正确地完成此操作,最好是实际修补PostgreSQL而不是使用扩展。
select guid from documents limit 1;
"\254\355\000\005sr\000\016java.util.UUID\274\231\003\367\230m\205/\002\000\002J\000\014leastSigBitsJ\000\013mostSigBitsxp\273\222)\360*r\322\262u\274\310\020\342\004M "
- FvHovell