Ok, znalazłem odpowiedź. W PostgreSQL możesz pisać funkcje za pomocą Pythona. Aby umożliwić korzystanie z Pythona, musisz zainstalować konkretną wersję Pythona wymaganą przez Twoją instalację PostgreSQL i udostępnić ją w zmiennej środowiskowej PATH. Możesz dowiedzieć się, jakiej wersji Pythona wymaga Twoja instalacja PostgreSQL, przeglądając uwagi dotyczące instalacji. Obecnie używam PostgreSQL 9.6.5 w systemie Windows i wywołuje Python 3.3. Początkowo próbowałem najnowszego Pythona 3.6, ale to nie zadziałało. Zdecydowałem się na najnowszy Python 3.3 dla Windows, czyli 3.3.5.
Po zainstalowaniu Pythona włączasz go w PostgreSQL, wykonując polecenie CREATE EXTENSION plpython3u;
w Twojej bazie danych, jak udokumentowano tutaj https://www.postgresql.org/docs /current/static/plpython.html
. Stamtąd możesz napisać dowolną funkcję z ciałami Pythona.
W moim konkretnym przypadku do konwersji z bytea
do double precision[]
iz powrotem napisałem następujące funkcje:
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$;
W moim przypadku wszystkie dublety są przechowywane w little endian, więc używam <
. Buforuję również import struct
w słowniku globalnym, jak opisano w https://stackoverflow.com/a/15025425/5274457 . Użyłem GD zamiast SD, ponieważ chcę, aby import był dostępny w innych funkcjach, które mogę napisać. Aby uzyskać informacje o GD i SD, zobacz https://www.postgresql .org/docs/current/static/plpython-sharing.html
.
Aby zobaczyć to w akcji, wiedząc, że bloby w mojej bazie danych są przechowywane jako little endian,
SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');
Odpowiedź, którą otrzymuję, to
bytea_to_double_array | encode
double precision[] | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde
gdzie 'efbeaddeefbeadde'
to 'deadbeefdeadbeef'
w little endian.