将PostgreSQL bytea存储的serialized-java-UUID转换为postgresql-UUID

时间:2014-07-22 09:04:16

标签: java postgresql serialization uuid bytea

我们的一个软件项目使用PostgreSQL表,其中包含一列#guid'类型为bytea。

这与hibernate 3.3.2.GA一起使用PostgreSQL 8.4,它使用java object serialization序列化java UUID类型。结果是一个类似于以下escape格式bytea文字的值:

'\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?

3 个答案:

答案 0 :(得分:6)

更新:请参阅编辑问题,此答案适用于uuid的常见16字节序列化;该问题已修改为反映 java序列化


有趣的问题。我开始编写一个简单的C扩展来高效地完成它,但使用下面的PL / Python版本可能更明智。

由于uuid是固定大小的类型且byteavarlena,因此您不能create cast ... as implicit二进制强制它们,因为可变长度字段标题会挡路。

没有用于bytea输入的内置函数来返回uuid。它是一个方便的东西,但我不认为任何人已经完成它。

最简单的方式

更新:实际上这是一种简单的方法。一旦bytea被剥离,十六进制形式的\x实际上是一个有效的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的

它在Python中可能更快更干净,因为PL / Python接口将bytea作为原始字节而不是十六进制字符串传递:

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扩展模块here

但实际上,我的意思是说它很难看。如果您希望在C中正确 ,则最好实际修补PostgreSQL而不是使用扩展名。

答案 1 :(得分:0)

经过一些试验和错误后,我创建了以下函数来提取postgresql-UUID值:

CREATE OR REPLACE FUNCTION bytea2uuid (x bytea) RETURNS uuid as $$ SELECT encode(substring(x, 73, 8) || substring(x, 65, 8), 'hex')::uuid $$ language sql;

这可以通过提取java长值中使用的字节为leastSigBits和mostSigBits(以相反的顺序存储),而不是编码为十六进制并转换为类型' uuid'。

使用如下: select bytea2uuid(guid) as guid from documents limit 1;

"75bcc810-e204-4d20-bb92-29f02a72d2b2"

答案 2 :(得分:0)

这对我有用:

ALTER TABLE myTable ALTER COLUMN id TYPE uuid USING CAST(ENCODE(id, 'hex') AS uuid);