Преобразование bytea в двойную точность в PostgreSQL
у меня есть база данных, где в одной из таблиц хранится blob (bytea
) всех видов общих данных, собранных из другой системы. The bytea
в поле может быть что угодно. Чтобы знать, как интерпретировать данные, таблица также имеет поле формата. Я написал Java-приложение для чтения bytea
поле из базы данных byte[]
и тогда я могу легко преобразовать его в double[]
или int[]
или все, что говорит поле формата, используя ByteBuffer
и различные виды (DoubleBuffer
, IntBuffer
, etc.).
теперь у меня есть ситуация, когда мне нужно сделать некоторые манипуляции с данными в самой базе данных в рамках триггерной функции, чтобы поддерживать целостность с другой таблицей. Я могу найти преобразования практически для любого типа данных, но я не могу найти ничего для перехода от bytea
(или даже bit
) к double precision
и обратно. А bytea
можно разбить, преобразовать в биты, а затем преобразовать в int
или bigint
, а не double precision
. Например, x'deadbeefdeadbeef'::bit(64)::bigint
преобразует в -2401053088876216593
без проблем, но x'deadbeefdeadbeef'::bit(64)::double precision
терпит неудачу с "ошибкой: не может привести бит типа к двойной точности" вместо того, чтобы дать ответ IEEE 754 -1.1885959257070704E148
.
я нашел этот ответ https://stackoverflow.com/a/11661849/5274457, который в основном реализует стандарт IEEE для преобразования битов в double, но действительно ли нет базовой функции преобразования в PostgreSQL для этого? Кроме того, мне нужно вернуться назад от double precision
to bytea
когда я закончу манипулировать данными и нужно обновить таблицы, которые этот ответ не предоставляет.
какие идеи?
1 ответов
Ок, я нашел ответ. В PostgreSQL вы можете писать функции с помощью Python. Чтобы включить использование Python, вы должны установить конкретную версию Python, необходимую для установки PostgreSQL, и иметь ее доступной в переменной среды PATH. Вы можете найти, какая версия Python требуется для установки PostgreSQL, просмотрев примечания по установке. В настоящее время я использую PostgreSQL 9.6.5 в Windows, и он вызывает Python 3.3. Сначала я попробовал последнюю версию Python 3.6, но это не сработает. Я остановился на последнем Python 3.3 для Windows, который является 3.3.5.
после установки Python вы включаете его в PostgreSQL, выполнив CREATE EXTENSION plpython3u;
в вашей базе данных, как описано здесь https://www.postgresql.org/docs/current/static/plpython.html. Оттуда вы можете написать любую функцию с телами Python.
для моего конкретного случая для преобразования из bytea
до double precision[]
и обратно, я написал следующее функции:
CREATE FUNCTION bytea_to_double_array(b bytea)
RETURNS double precision[]
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
return struct.unpack('<' + str(int(len(b) / 8)) + 'd', b)
$BODY$;
CREATE FUNCTION double_array_to_bytea(dblarray double precision[])
RETURNS bytea
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
# dblarray here is really a list.
# PostgreSQL passes SQL arrays as Python lists
return struct.pack('<' + str(int(len(dblarray))) + 'd', *dblarray)
$BODY$;
в моем случае все двойники хранятся в little endian, поэтому я использую <
. Я также кэширую импорт struct
модуль в глобальном словаре, как описано в https://stackoverflow.com/a/15025425/5274457. Я использовал GD вместо SD, потому что я хочу, чтобы импорт был доступен в других функциях, которые я могу написать. Сведения о GD и SD см. В разделе https://www.postgresql.org/docs/current/static/plpython-sharing.html.
чтобы увидеть его в действии, зная, что капли в моей базе данных хранятся как мало endian,
SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');
и я получаю ответ:
bytea_to_double_array | encode
double precision[] | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde
здесь 'efbeaddeefbeadde'
и 'deadbeefdeadbeef'
в прямом порядке байтов.