Конвертировать 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/202J04leastSigBitsJ03mostSigBitsxp32)0*r22u400424M '
... который мы не можем легко использовать в запросе как 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);