将PostgreSQL bytea存储的序列化java UUID转换为PostgreSQL UUID
我们的一个软件项目使用一个PostgreSQL表,其列“guid”类型为bytea 这与hibernate 3.3.2.GA和PostgreSQL 8.4一起使用,后者使用。结果是一个类似以下将PostgreSQL bytea存储的序列化java UUID转换为PostgreSQL UUID,java,postgresql,serialization,uuid,bytea,Java,Postgresql,Serialization,Uuid,Bytea,我们的一个软件项目使用一个PostgreSQL表,其列“guid”类型为bytea 这与hibernate 3.3.2.GA和PostgreSQL 8.4一起使用,后者使用。结果是一个类似以下escapeformat bytea literal的值: '\254\355\000\005sr\000\016java.util.UUID\274\231\003\367\230m\205/\002\000\002J\000\014leastSigBitsJ\000\013mostSigBitsxp
escape
format bytea literal的值:
'\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 '
'\x0FCC6350118D11E4A5597DE5338EB025'
。。。我们不能在查询中轻松地使用它作为选择或条件来检索相关行
是否有人可以在不设置hibernate查询的情况下读取或使用查询的select或where部分(例如通过psql或pgadmin3)中的bytea列?更新:请参见编辑到问题,此答案适用于常见的16字节uuid序列化;修改该问题是为了反映java序列化
有趣的问题。我最终编写了一个简单的C扩展来有效地完成它,但是使用下面的PL/Python版本可能更明智 因为
uuid
是一个固定大小的类型,bytea
是varlena
你不能只创建cast。。。作为隐式的
对它们进行二进制强制,因为可变长度字段头会妨碍它们
bytea输入没有用于返回uuid的内置函数。这是一件方便的东西,但我认为还没有人做过
最简单的方法
更新:实际上有一种简单的方法可以做到这一点<一旦去掉\x
,十六进制形式的code>bytea实际上是一个有效的uuid文本,因为中的uuid\u接受没有-
或{}
的普通未修饰十六进制。所以只要:
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文本:
'\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 '
'\x0FCC6350118D11E4A5597DE5338EB025'
您可以使用以下命令将其转换为uuid
类型:
PL/Perl
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扩展模块
但说真的,我是说它很丑。如果您希望在C中正确完成,最好实际修补PostgreSQL,而不是使用扩展。经过一些尝试和错误后,我创建了以下函数来提取PostgreSQL UUID值:
CREATE或REPLACE FUNCTION bytea2uuid(x bytea)将uuid返回为$$SELECT encode(子字符串(x,73,8)| |子字符串(x,65,8),'hex')::uuid$$language sql代码>
这是通过提取leastSigBits和mostSigBits的java长值中使用的字节(以相反的顺序存储)来实现的,而不是编码为十六进制并强制转换为“uuid”类型
用法如下:
从文档限制1中选择bytea2uuid(guid)作为guid代码>
“75bcc810-e204-4d20-bb92-29f02a72d2b2”
这对我来说很有用:
ALTER TABLE myTable ALTER COLUMN id TYPE uuid USING CAST(ENCODE(id, 'hex') AS uuid);
也许我应该更清楚地提到bytea列的内容是UUID实例的java序列化版本,例如:selectguidfromdocumentslimit1代码>“\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,是的。至少可以说,这是有用的。这就是为什么您应该始终包含示例数据。您最好也验证serialVersionUid字段,确保您没有解码错误。在一般情况下,您是正确的,但出于我的目的,我确信所有UUID序列化都是使用java 6执行的,因为java 6用于我们的所有项目。因此,在我的例子中,我不需要检查serialVersionUid,因为这保证对所有guid值都是相同的。这不是正确的编码:一个java.util.UUID序列化值,例如:“\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\342\004M“