Convert PostgreSQL bytea-stored serialized-java-UUID to postgresql-UUID
我们的一个软件项目使用PostgreSQL表,其中列为'guid',类型为bytea。
这与hibernate 3.3.2.GA和PostgreSQL 8.4一起使用,它使用java对象序列化来序列化java UUID类型。 结果是一个类似于以下
1 | '\254\355\000\005sr\000\016java.util.UUID\274\231\003\367\230m\205/\002\000\002??J\000\014leastSigBitsJ\000\013mostSigBitsxp\273\222)\360*r\322\262u\274\310\020\3??42\004M ' |
...我们不能轻易地在查询中使用select或条件来检索相关行。
有没有人有办法在查询的select-或where-parts中读取或使用bytea-column(例如通过psql或pgadmin3),而无需设置一些hibernate-query?
更新:请参阅编辑问题,此答案适用于uuid的常见16字节序列化;问题被修改以反映java序列化。
有趣的问题。我开始编写一个简单的C扩展来高效地完成它,但是使用下面的PL / Python版本可能更明智。
因为
bytea输入没有内置函数来返回uuid。这是一个方便的事情,但我认为没有人做过。
最简单的方法
更新:实际上有一种简单的方法可以做到这一点。一旦
1 2 3 4 5 6 7 | 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文字:
1 | '\x0FCC6350118D11E4A5597DE5338EB025' |
您可以将其转换为
PL / Perl的
1 2 3 4 5 6 7 8 9 10 11 | 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的
它在Python中可能更快更干净,因为PL / Python接口将
1 2 3 4 5 6 7 8 9 10 | 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中,只是为了踢。丑陋的黑客。
您可以在此处查看C扩展模块。
但实际上,我的意思是说它很难看。如果你想在C中正确完成它,最好实际修补PostgreSQL而不是使用扩展。
这对我有用:
1 | ALTER TABLE myTable ALTER COLUMN id TYPE uuid USING CAST(ENCODE(id, 'hex') AS uuid); |
经过一些试验和错误后,我创建了以下函数来提取postgresql-UUID值:
这通过提取在java长值中使用的字节为leastSigBits和mostSigBits(以相反的顺序存储),而不是编码为十六进制和转换为类型'uuid'。
使用如下: