Конвертировать PostgreSQL bytea-хранимый сериализованный-java-UUID в postgresql-UUID

один из наших программных проектов использует PostgreSQL-таблицу со столбцом "guid" типа bytea.

это используется с hibernate 3.3.2.GA с PostgreSQL 8.4, который сериализует тип java UUID с помощью сериализация объектов java. Результатом является значение, подобное следующему escape формат bytea литерал:

'4505sr06java.util.UUID41370m5/202‌​J04leastSigBitsJ03mostSigBitsxp32)0*r22u400‌​424M '

... который мы не можем легко использовать в запросе как select или condition для получения соответствующих строк.

есть ли у кого-нибудь способ прочитайте или используйте столбец bytea в select-или where-частях запроса (например, через psql или pgadmin3), не настраивая какой-либо hibernate-запрос?

3 ответов


обновление: см. edit to question, этот ответ относится к обычным 16-байтовым сериализациям uuid; вопрос был изменен, чтобы отразить сериализация java.


интересные задачи. Я закончил писать простое расширение C, чтобы сделать это эффективно, но, вероятно, более разумно использовать версию PL/Python ниже.

, потому что uuid фиксированного размера и типа bytea is varlena вы не можете просто create cast ... as implicit в binary-принудить их, потому что заголовок поля переменной длины будет мешать.

нет встроенной функции для ввода bytea для возврата uuid. Это было бы удобно иметь, но я не думаю, что кто-то еще это сделал.

самый простой способ

обновление: на самом деле есть простой способ сделать это. bytea в шестнадцатеричной форме фактически является допустимым литералом uuid после \x снимается, потому что 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, а не использовать расширение.


после некоторых проб и ошибок я создал следующую функцию для извлечения значения 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 long-values для leastSigBits и mostSigBits (которые хранятся в обратном порядке), чем кодирование в hex и литье для типа 'uuid'.

использовать следующим образом: select bytea2uuid(guid) as guid from documents limit 1;

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


это работает для меня:

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