10

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

这与带有 PostgreSQL 8.4 的 hibernate 3.3.2.GA 一起使用,它使用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 '

...我们不能轻易地在查询中使用它作为选择或条件来检索相关行。

有没有人有办法在查询的选择或位置部分(例如通过 psql 或 pgadmin3)中读取或使用 bytea 列,而无需设置一些休眠查询?

4

3 回答 3

7

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


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

因为uuid是一个固定大小的类型,byteavarlena不能仅仅create cast ... as implicit对它们进行二进制强制,因为可变长度的字段标题会妨碍它们。

bytea 输入没有返回 uuid 的内置函数。拥有它会很方便,但我认为还没有人做过。

最简单的方法

更新:实际上有一种简单的方法可以做到这一点。bytea十六进制形式实际上是一个有效的 uuid 文字,一旦\x被剥离,因为接受没有or的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 扩展模块。

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

于 2014-07-22T10:40:37.230 回答
0

这对我有用:

ALTER TABLE myTable ALTER COLUMN id TYPE uuid USING CAST(ENCODE(id, 'hex') AS uuid);
于 2015-01-13T09:50:44.793 回答
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;

这通过提取用于 minimumSigBits 和 mostSigBits(以相反的顺序存储)的 java long 值中使用的字节,而不是编码为十六进制并转换为类型“uuid”来工作。

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

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

于 2014-07-23T12:05:51.293 回答